From 7084aa69f49fc913473d50c5bff6cb42e4bad576 Mon Sep 17 00:00:00 2001 From: HAL <328961630@qq.com> Date: Mon, 26 Aug 2024 22:56:29 +0800 Subject: [PATCH] init --- .github/workflows/publish.yml | 39 + .gitignore | 33 + README.md | 66 + app.go | 304 ++ build/README.md | 35 + build/appicon.png | Bin 0 -> 7869 bytes build/darwin/Info.dev.plist | 68 + build/darwin/Info.plist | 63 + build/windows/icon.ico | Bin 0 -> 421150 bytes build/windows/info.json | 15 + build/windows/installer/project.nsi | 114 + build/windows/installer/wails_tools.nsh | 249 ++ build/windows/wails.exe.manifest | 15 + frontend/dist/assets/001_微笑.1ec7a344.png | Bin 0 -> 5790 bytes frontend/dist/assets/002_撇嘴.0279218b.png | Bin 0 -> 5195 bytes frontend/dist/assets/003_色.e92bb91a.png | Bin 0 -> 5401 bytes frontend/dist/assets/004_发呆.8d849292.png | Bin 0 -> 5829 bytes frontend/dist/assets/005_得意.72060784.png | Bin 0 -> 5783 bytes frontend/dist/assets/006_流泪.f52e5f23.png | Bin 0 -> 4738 bytes frontend/dist/assets/007_害羞.414541cc.png | Bin 0 -> 5561 bytes frontend/dist/assets/008_闭嘴.4b6c78a6.png | Bin 0 -> 5683 bytes frontend/dist/assets/009_睡.75e64219.png | Bin 0 -> 5213 bytes frontend/dist/assets/010_大哭.2cd2fee3.png | Bin 0 -> 5532 bytes frontend/dist/assets/011_尴尬.70cfea1c.png | Bin 0 -> 4920 bytes frontend/dist/assets/012_发怒.b88ce021.png | Bin 0 -> 5123 bytes frontend/dist/assets/013_调皮.f3363541.png | Bin 0 -> 5042 bytes frontend/dist/assets/014_呲牙.3cd1fb7c.png | Bin 0 -> 6278 bytes frontend/dist/assets/015_惊讶.c9eb5e15.png | Bin 0 -> 5354 bytes frontend/dist/assets/016_难过.5d872489.png | Bin 0 -> 5022 bytes frontend/dist/assets/017_囧.59ee6551.png | Bin 0 -> 5244 bytes frontend/dist/assets/018_抓狂.d1646df8.png | Bin 0 -> 6316 bytes frontend/dist/assets/019_吐.51bb226f.png | Bin 0 -> 5813 bytes frontend/dist/assets/020_偷笑.59941b0b.png | Bin 0 -> 6236 bytes frontend/dist/assets/021_愉快.47582f99.png | Bin 0 -> 5163 bytes frontend/dist/assets/022_白眼.ca492234.png | Bin 0 -> 5820 bytes frontend/dist/assets/023_傲慢.651b4c79.png | Bin 0 -> 5858 bytes frontend/dist/assets/024_困.4556c7db.png | Bin 0 -> 4831 bytes frontend/dist/assets/025_惊恐.ed5cfeab.png | Bin 0 -> 5325 bytes frontend/dist/assets/026_憨笑.6d317a05.png | Bin 0 -> 6018 bytes frontend/dist/assets/027_悠闲.cef28253.png | Bin 0 -> 5057 bytes frontend/dist/assets/028_咒骂.a26d48fa.png | Bin 0 -> 6251 bytes frontend/dist/assets/029_疑问.aaa09269.png | Bin 0 -> 6362 bytes frontend/dist/assets/030_嘘.40e8213d.png | Bin 0 -> 5403 bytes frontend/dist/assets/031_晕.44e3541a.png | Bin 0 -> 6589 bytes frontend/dist/assets/032_衰.1a3910a6.png | Bin 0 -> 5136 bytes frontend/dist/assets/033_骷髅.3c9202dc.png | Bin 0 -> 6050 bytes frontend/dist/assets/034_敲打.b2798ca7.png | Bin 0 -> 31889 bytes frontend/dist/assets/035_再见.db23652c.png | Bin 0 -> 5285 bytes frontend/dist/assets/036_擦汗.b46fa893.png | Bin 0 -> 5603 bytes frontend/dist/assets/037_抠鼻.64bc8033.png | Bin 0 -> 5385 bytes frontend/dist/assets/038_鼓掌.2a84e4c7.png | Bin 0 -> 6203 bytes frontend/dist/assets/039_坏笑.4998b91f.png | Bin 0 -> 5427 bytes frontend/dist/assets/040_右哼哼.27d8126d.png | Bin 0 -> 4963 bytes frontend/dist/assets/041_鄙视.7e22890d.png | Bin 0 -> 6545 bytes frontend/dist/assets/042_委屈.a5caf83a.png | Bin 0 -> 6177 bytes frontend/dist/assets/043_快哭了.62b1b67c.png | Bin 0 -> 5960 bytes frontend/dist/assets/044_阴险.3697222b.png | Bin 0 -> 5985 bytes frontend/dist/assets/045_亲亲.dfa6bbdf.png | Bin 0 -> 5458 bytes frontend/dist/assets/046_可怜.634845ad.png | Bin 0 -> 6229 bytes frontend/dist/assets/047_笑脸.ab25a28c.png | Bin 0 -> 5911 bytes frontend/dist/assets/048_生病.cd7aadb3.png | Bin 0 -> 5904 bytes frontend/dist/assets/049_脸红.9ecb5c1c.png | Bin 0 -> 5935 bytes .../dist/assets/050_破涕为笑.a3d2342d.png | Bin 0 -> 6073 bytes frontend/dist/assets/051_恐惧.7af18313.png | Bin 0 -> 5653 bytes frontend/dist/assets/052_失望.87e0479b.png | Bin 0 -> 5723 bytes frontend/dist/assets/053_无语.6220ee7c.png | Bin 0 -> 5733 bytes frontend/dist/assets/054_嘿哈.2116e692.png | Bin 0 -> 6338 bytes frontend/dist/assets/055_捂脸.28f3a0d3.png | Bin 0 -> 6365 bytes frontend/dist/assets/056_奸笑.9cf99423.png | Bin 0 -> 6061 bytes frontend/dist/assets/057_机智.93c3d05a.png | Bin 0 -> 6162 bytes frontend/dist/assets/058_皱眉.efe09ed7.png | Bin 0 -> 5821 bytes frontend/dist/assets/059_耶.a6bc3d2b.png | Bin 0 -> 6523 bytes frontend/dist/assets/060_吃瓜.a2a158de.png | Bin 0 -> 5850 bytes frontend/dist/assets/061_加油.77c81f5b.png | Bin 0 -> 6459 bytes frontend/dist/assets/062_汗.be95535c.png | Bin 0 -> 5498 bytes frontend/dist/assets/063_天啊.a8355bf9.png | Bin 0 -> 5881 bytes frontend/dist/assets/064_Emm.787be530.png | Bin 0 -> 5395 bytes .../dist/assets/065_社会社会.a5f5902a.png | Bin 0 -> 6429 bytes frontend/dist/assets/066_旺柴.7825a175.png | Bin 0 -> 5690 bytes frontend/dist/assets/067_好的.a9fffc64.png | Bin 0 -> 6479 bytes frontend/dist/assets/068_打脸.560c8d1f.png | Bin 0 -> 5915 bytes frontend/dist/assets/069_哇.74cdcc27.png | Bin 0 -> 6230 bytes frontend/dist/assets/070_翻白眼.ecb744e2.png | Bin 0 -> 5106 bytes frontend/dist/assets/071_666.281fb9b6.png | Bin 0 -> 6623 bytes .../dist/assets/072_让我看看.cee96a9f.png | Bin 0 -> 6692 bytes frontend/dist/assets/073_叹气.712846f3.png | Bin 0 -> 5841 bytes frontend/dist/assets/074_苦涩.4edf4f58.png | Bin 0 -> 5438 bytes frontend/dist/assets/075_裂开.3fb97804.png | Bin 0 -> 6395 bytes frontend/dist/assets/076_嘴唇.59b9c0be.png | Bin 0 -> 4844 bytes frontend/dist/assets/077_爱心.a09c823b.png | Bin 0 -> 5709 bytes frontend/dist/assets/078_心碎.9a4fb37d.png | Bin 0 -> 5110 bytes frontend/dist/assets/079_拥抱.e529a46b.png | Bin 0 -> 5018 bytes frontend/dist/assets/080_强.64fe98a8.png | Bin 0 -> 4448 bytes frontend/dist/assets/081_弱.07ddf3a5.png | Bin 0 -> 4316 bytes frontend/dist/assets/082_握手.aeb86265.png | Bin 0 -> 6325 bytes frontend/dist/assets/083_胜利.e9ff0663.png | Bin 0 -> 6266 bytes frontend/dist/assets/084_抱拳.0ae5f316.png | Bin 0 -> 5964 bytes frontend/dist/assets/085_勾引.a4c3a7b4.png | Bin 0 -> 5399 bytes frontend/dist/assets/086_拳头.2829fdbe.png | Bin 0 -> 6776 bytes frontend/dist/assets/087_OK.fc42db3d.png | Bin 0 -> 6862 bytes frontend/dist/assets/088_合十.58cd6a1d.png | Bin 0 -> 4707 bytes frontend/dist/assets/089_啤酒.2d022508.png | Bin 0 -> 6281 bytes frontend/dist/assets/090_咖啡.8f40dc95.png | Bin 0 -> 5915 bytes frontend/dist/assets/091_蛋糕.f01a91ed.png | Bin 0 -> 5853 bytes frontend/dist/assets/093_凋谢.aa715ee6.png | Bin 0 -> 5137 bytes frontend/dist/assets/095_炸弹.3dffd8e8.png | Bin 0 -> 5171 bytes frontend/dist/assets/096_便便.b0d5c50c.png | Bin 0 -> 5693 bytes frontend/dist/assets/097_月亮.47389834.png | Bin 0 -> 5920 bytes frontend/dist/assets/098_太阳.89c3d0ab.png | Bin 0 -> 6637 bytes frontend/dist/assets/099_庆祝.2d9e8f8a.png | Bin 0 -> 5048 bytes frontend/dist/assets/100_礼物.37ae5ec0.png | Bin 0 -> 6041 bytes frontend/dist/assets/102_發.f43fee5c.png | Bin 0 -> 5351 bytes frontend/dist/assets/103_福.58c94555.png | Bin 0 -> 4750 bytes frontend/dist/assets/104_烟花.61568e1e.png | Bin 0 -> 6371 bytes frontend/dist/assets/105_爆竹.35531687.png | Bin 0 -> 4552 bytes frontend/dist/assets/106_猪头.7eb8ff1d.png | Bin 0 -> 5386 bytes frontend/dist/assets/107_跳跳.24101efa.png | Bin 0 -> 4273 bytes frontend/dist/assets/108_发抖.3eabd306.png | Bin 0 -> 4563 bytes frontend/dist/assets/109_转圈.67669ca4.png | Bin 0 -> 4137 bytes frontend/dist/assets/emoji.b5d5ea11.png | Bin 0 -> 4977 bytes frontend/dist/assets/index.beba636e.js | 348 +++ frontend/dist/assets/index.de7292ad.css | 1 + .../nunito-v16-latin-regular.06f3af3f.woff2 | Bin 0 -> 18972 bytes frontend/dist/index.html | 15 + go.mod | 70 + main.go | 79 + pkg/lame/.gitignore | 23 + pkg/lame/LICENSE | 19 + pkg/lame/README.md | 43 + pkg/lame/clame/VbrTag.c | 1082 +++++++ pkg/lame/clame/VbrTag.h | 79 + pkg/lame/clame/bitstream.c | 1111 +++++++ pkg/lame/clame/bitstream.h | 40 + pkg/lame/clame/config.h | 30 + pkg/lame/clame/encoder.c | 574 ++++ pkg/lame/clame/encoder.h | 156 + pkg/lame/clame/fft.c | 339 +++ pkg/lame/clame/fft.h | 35 + pkg/lame/clame/gain_analysis.c | 476 +++ pkg/lame/clame/gain_analysis.h | 109 + pkg/lame/clame/id3tag.c | 1926 ++++++++++++ pkg/lame/clame/id3tag.h | 64 + pkg/lame/clame/l3side.h | 95 + pkg/lame/clame/lame-analysis.h | 96 + pkg/lame/clame/lame.c | 2665 +++++++++++++++++ pkg/lame/clame/lame.h | 1342 +++++++++ pkg/lame/clame/lame_global_flags.h | 184 ++ pkg/lame/clame/lame_intrin.h | 33 + pkg/lame/clame/machine.h | 189 ++ pkg/lame/clame/mpglib_interface.c | 477 +++ pkg/lame/clame/newmdct.c | 1039 +++++++ pkg/lame/clame/newmdct.h | 27 + pkg/lame/clame/presets.c | 404 +++ pkg/lame/clame/psymodel.c | 2167 ++++++++++++++ pkg/lame/clame/psymodel.h | 64 + pkg/lame/clame/quantize.c | 2050 +++++++++++++ pkg/lame/clame/quantize.h | 38 + pkg/lame/clame/quantize_pvt.c | 1074 +++++++ pkg/lame/clame/quantize_pvt.h | 128 + pkg/lame/clame/reservoir.c | 293 ++ pkg/lame/clame/reservoir.h | 31 + pkg/lame/clame/set_get.c | 2346 +++++++++++++++ pkg/lame/clame/set_get.h | 76 + pkg/lame/clame/tables.c | 564 ++++ pkg/lame/clame/tables.h | 95 + pkg/lame/clame/takehiro.c | 1375 +++++++++ pkg/lame/clame/util.c | 1018 +++++++ pkg/lame/clame/util.h | 616 ++++ pkg/lame/clame/vbrquantize.c | 1580 ++++++++++ pkg/lame/clame/vbrquantize.h | 28 + pkg/lame/clame/version.c | 254 ++ pkg/lame/clame/version.h | 68 + pkg/lame/clame/xmm_quantize_sub.c | 240 ++ pkg/lame/lame.go | 239 ++ pkg/lame/writer.go | 41 + pkg/lame/z_link_lame_c.c | 21 + pkg/silk/csilk/Decoder_Api.c | 80 + pkg/silk/csilk/SKP_Silk_A2NLSF.c | 287 ++ pkg/silk/csilk/SKP_Silk_AsmHelper.h | 180 ++ pkg/silk/csilk/SKP_Silk_AsmPreproc.h | 220 ++ pkg/silk/csilk/SKP_Silk_CNG.c | 149 + .../csilk/SKP_Silk_HP_variable_cutoff_FIX.c | 120 + pkg/silk/csilk/SKP_Silk_Inlines.h | 278 ++ pkg/silk/csilk/SKP_Silk_LBRR_reset.c | 40 + pkg/silk/csilk/SKP_Silk_LPC_inv_pred_gain.c | 154 + .../csilk/SKP_Silk_LPC_synthesis_filter.c | 117 + .../csilk/SKP_Silk_LPC_synthesis_order16.c | 216 ++ pkg/silk/csilk/SKP_Silk_LP_variable_cutoff.c | 194 ++ pkg/silk/csilk/SKP_Silk_LSF_cos_table.c | 65 + .../csilk/SKP_Silk_LTP_analysis_filter_FIX.c | 80 + pkg/silk/csilk/SKP_Silk_LTP_scale_ctrl_FIX.c | 81 + pkg/silk/csilk/SKP_Silk_MA.c | 120 + pkg/silk/csilk/SKP_Silk_NLSF2A.c | 151 + pkg/silk/csilk/SKP_Silk_NLSF2A_stable.c | 58 + pkg/silk/csilk/SKP_Silk_NLSF_MSVQ_decode.c | 91 + .../csilk/SKP_Silk_NLSF_MSVQ_encode_FIX.c | 239 ++ .../SKP_Silk_NLSF_VQ_rate_distortion_FIX.c | 61 + .../csilk/SKP_Silk_NLSF_VQ_sum_error_FIX.c | 83 + .../csilk/SKP_Silk_NLSF_VQ_weights_laroia.c | 79 + pkg/silk/csilk/SKP_Silk_NLSF_stabilize.c | 139 + pkg/silk/csilk/SKP_Silk_NSQ.c | 454 +++ pkg/silk/csilk/SKP_Silk_NSQ_del_dec.c | 733 +++++ pkg/silk/csilk/SKP_Silk_PLC.c | 418 +++ pkg/silk/csilk/SKP_Silk_PLC.h | 79 + pkg/silk/csilk/SKP_Silk_SDK_API.h | 152 + pkg/silk/csilk/SKP_Silk_SigProc_FIX.h | 663 ++++ pkg/silk/csilk/SKP_Silk_VAD.c | 320 ++ .../csilk/SKP_Silk_VQ_nearest_neighbor_FIX.c | 159 + pkg/silk/csilk/SKP_Silk_ana_filt_bank_1.c | 82 + pkg/silk/csilk/SKP_Silk_apply_sine_window.c | 120 + pkg/silk/csilk/SKP_Silk_array_maxabs.c | 70 + pkg/silk/csilk/SKP_Silk_autocorr.c | 81 + pkg/silk/csilk/SKP_Silk_biquad.c | 72 + pkg/silk/csilk/SKP_Silk_biquad_alt.c | 73 + pkg/silk/csilk/SKP_Silk_burg_modified.c | 229 ++ pkg/silk/csilk/SKP_Silk_bwexpander.c | 49 + pkg/silk/csilk/SKP_Silk_bwexpander_32.c | 46 + pkg/silk/csilk/SKP_Silk_code_signs.c | 91 + .../csilk/SKP_Silk_common_pitch_est_defines.h | 76 + pkg/silk/csilk/SKP_Silk_control.h | 91 + .../csilk/SKP_Silk_control_audio_bandwidth.c | 137 + pkg/silk/csilk/SKP_Silk_control_codec_FIX.c | 402 +++ pkg/silk/csilk/SKP_Silk_corrMatrix_FIX.c | 153 + pkg/silk/csilk/SKP_Silk_create_init_destroy.c | 53 + pkg/silk/csilk/SKP_Silk_dec_API.c | 279 ++ pkg/silk/csilk/SKP_Silk_decode_core.c | 314 ++ pkg/silk/csilk/SKP_Silk_decode_frame.c | 155 + pkg/silk/csilk/SKP_Silk_decode_parameters.c | 244 ++ pkg/silk/csilk/SKP_Silk_decode_pitch.c | 57 + pkg/silk/csilk/SKP_Silk_decode_pulses.c | 105 + pkg/silk/csilk/SKP_Silk_decoder_set_fs.c | 80 + pkg/silk/csilk/SKP_Silk_define.h | 306 ++ pkg/silk/csilk/SKP_Silk_detect_SWB_input.c | 76 + pkg/silk/csilk/SKP_Silk_div_oabi.c | 35 + pkg/silk/csilk/SKP_Silk_enc_API.c | 247 ++ pkg/silk/csilk/SKP_Silk_encode_frame_FIX.c | 413 +++ pkg/silk/csilk/SKP_Silk_encode_parameters.c | 162 + pkg/silk/csilk/SKP_Silk_encode_pulses.c | 195 ++ pkg/silk/csilk/SKP_Silk_errors.h | 89 + pkg/silk/csilk/SKP_Silk_find_LPC_FIX.c | 148 + pkg/silk/csilk/SKP_Silk_find_LTP_FIX.c | 243 ++ pkg/silk/csilk/SKP_Silk_find_pitch_lags_FIX.c | 125 + pkg/silk/csilk/SKP_Silk_find_pred_coefs_FIX.c | 132 + pkg/silk/csilk/SKP_Silk_gain_quant.c | 94 + pkg/silk/csilk/SKP_Silk_init_encoder_FIX.c | 56 + pkg/silk/csilk/SKP_Silk_inner_prod_aligned.c | 73 + pkg/silk/csilk/SKP_Silk_interpolate.c | 47 + pkg/silk/csilk/SKP_Silk_k2a.c | 58 + pkg/silk/csilk/SKP_Silk_k2a_Q16.c | 58 + pkg/silk/csilk/SKP_Silk_lin2log.c | 51 + pkg/silk/csilk/SKP_Silk_log2lin.c | 61 + pkg/silk/csilk/SKP_Silk_macros.h | 125 + pkg/silk/csilk/SKP_Silk_macros_arm.h | 248 ++ pkg/silk/csilk/SKP_Silk_main.h | 388 +++ pkg/silk/csilk/SKP_Silk_main_FIX.h | 338 +++ .../csilk/SKP_Silk_noise_shape_analysis_FIX.c | 477 +++ pkg/silk/csilk/SKP_Silk_pitch_analysis_core.c | 706 +++++ pkg/silk/csilk/SKP_Silk_pitch_est_defines.h | 40 + pkg/silk/csilk/SKP_Silk_pitch_est_tables.c | 89 + pkg/silk/csilk/SKP_Silk_prefilter_FIX.c | 224 ++ pkg/silk/csilk/SKP_Silk_process_NLSFs_FIX.c | 127 + pkg/silk/csilk/SKP_Silk_process_gains_FIX.c | 108 + pkg/silk/csilk/SKP_Silk_quant_LTP_gains_FIX.c | 104 + pkg/silk/csilk/SKP_Silk_range_coder.c | 372 +++ .../SKP_Silk_regularize_correlations_FIX.c | 43 + pkg/silk/csilk/SKP_Silk_resampler.c | 323 ++ pkg/silk/csilk/SKP_Silk_resampler_down2.c | 79 + pkg/silk/csilk/SKP_Silk_resampler_down2_3.c | 103 + pkg/silk/csilk/SKP_Silk_resampler_down3.c | 94 + pkg/silk/csilk/SKP_Silk_resampler_private.h | 131 + .../csilk/SKP_Silk_resampler_private_AR2.c | 60 + .../csilk/SKP_Silk_resampler_private_ARMA4.c | 79 + .../SKP_Silk_resampler_private_IIR_FIR.c | 110 + .../csilk/SKP_Silk_resampler_private_copy.c | 49 + .../csilk/SKP_Silk_resampler_private_down4.c | 77 + .../SKP_Silk_resampler_private_down_FIR.c | 167 ++ .../csilk/SKP_Silk_resampler_private_up2_HQ.c | 120 + .../csilk/SKP_Silk_resampler_private_up4.c | 81 + pkg/silk/csilk/SKP_Silk_resampler_rom.c | 269 ++ pkg/silk/csilk/SKP_Silk_resampler_rom.h | 91 + pkg/silk/csilk/SKP_Silk_resampler_structs.h | 80 + pkg/silk/csilk/SKP_Silk_resampler_up2.c | 77 + .../csilk/SKP_Silk_residual_energy16_FIX.c | 99 + pkg/silk/csilk/SKP_Silk_residual_energy_FIX.c | 88 + pkg/silk/csilk/SKP_Silk_scale_copy_vector16.c | 45 + pkg/silk/csilk/SKP_Silk_scale_vector.c | 43 + pkg/silk/csilk/SKP_Silk_schur.c | 94 + pkg/silk/csilk/SKP_Silk_schur64.c | 82 + pkg/silk/csilk/SKP_Silk_setup_complexity.h | 99 + pkg/silk/csilk/SKP_Silk_shell_coder.c | 155 + pkg/silk/csilk/SKP_Silk_sigm_Q15.c | 80 + pkg/silk/csilk/SKP_Silk_solve_LS_FIX.c | 241 ++ pkg/silk/csilk/SKP_Silk_sort.c | 147 + pkg/silk/csilk/SKP_Silk_structs.h | 353 +++ pkg/silk/csilk/SKP_Silk_structs_FIX.h | 151 + pkg/silk/csilk/SKP_Silk_sum_sqr_shift.c | 102 + pkg/silk/csilk/SKP_Silk_tables.h | 168 ++ pkg/silk/csilk/SKP_Silk_tables_LTP.c | 324 ++ pkg/silk/csilk/SKP_Silk_tables_NLSF_CB0_10.c | 890 ++++++ pkg/silk/csilk/SKP_Silk_tables_NLSF_CB0_10.h | 51 + pkg/silk/csilk/SKP_Silk_tables_NLSF_CB0_16.c | 1320 ++++++++ pkg/silk/csilk/SKP_Silk_tables_NLSF_CB0_16.h | 51 + pkg/silk/csilk/SKP_Silk_tables_NLSF_CB1_10.c | 578 ++++ pkg/silk/csilk/SKP_Silk_tables_NLSF_CB1_10.h | 51 + pkg/silk/csilk/SKP_Silk_tables_NLSF_CB1_16.c | 704 +++++ pkg/silk/csilk/SKP_Silk_tables_NLSF_CB1_16.h | 51 + pkg/silk/csilk/SKP_Silk_tables_gain.c | 77 + pkg/silk/csilk/SKP_Silk_tables_other.c | 148 + pkg/silk/csilk/SKP_Silk_tables_pitch_lag.c | 199 ++ .../csilk/SKP_Silk_tables_pulses_per_block.c | 235 ++ pkg/silk/csilk/SKP_Silk_tables_sign.c | 42 + pkg/silk/csilk/SKP_Silk_tables_type_offset.c | 52 + pkg/silk/csilk/SKP_Silk_tuning_parameters.h | 183 ++ pkg/silk/csilk/SKP_Silk_typedef.h | 107 + .../SKP_Silk_warped_autocorrelation_FIX.c | 88 + pkg/silk/csilk/skp_silk_sdk.h | 11 + pkg/silk/silk.go | 122 + pkg/silk/writer.go | 41 + pkg/silk/z_link_silk_c.c | 111 + pkg/utils/utils.go | 77 + pkg/wechat/msg.pb.go | 301 ++ pkg/wechat/wechat.go | 653 ++++ pkg/wechat/wechatDBDec.go | 170 ++ pkg/wechat/wechatDataProvider.go | 878 ++++++ pkg/wechat/wechatIMGDec.go | 209 ++ res/result.png | Bin 0 -> 253402 bytes res/tips.png | Bin 0 -> 120539 bytes wails.json | 13 + 328 files changed, 55628 insertions(+) create mode 100644 .github/workflows/publish.yml create mode 100644 .gitignore create mode 100644 app.go create mode 100644 build/README.md create mode 100644 build/appicon.png create mode 100644 build/darwin/Info.dev.plist create mode 100644 build/darwin/Info.plist create mode 100644 build/windows/icon.ico create mode 100644 build/windows/info.json create mode 100644 build/windows/installer/project.nsi create mode 100644 build/windows/installer/wails_tools.nsh create mode 100644 build/windows/wails.exe.manifest create mode 100644 frontend/dist/assets/001_微笑.1ec7a344.png create mode 100644 frontend/dist/assets/002_撇嘴.0279218b.png create mode 100644 frontend/dist/assets/003_色.e92bb91a.png create mode 100644 frontend/dist/assets/004_发呆.8d849292.png create mode 100644 frontend/dist/assets/005_得意.72060784.png create mode 100644 frontend/dist/assets/006_流泪.f52e5f23.png create mode 100644 frontend/dist/assets/007_害羞.414541cc.png create mode 100644 frontend/dist/assets/008_闭嘴.4b6c78a6.png create mode 100644 frontend/dist/assets/009_睡.75e64219.png create mode 100644 frontend/dist/assets/010_大哭.2cd2fee3.png create mode 100644 frontend/dist/assets/011_尴尬.70cfea1c.png create mode 100644 frontend/dist/assets/012_发怒.b88ce021.png create mode 100644 frontend/dist/assets/013_调皮.f3363541.png create mode 100644 frontend/dist/assets/014_呲牙.3cd1fb7c.png create mode 100644 frontend/dist/assets/015_惊讶.c9eb5e15.png create mode 100644 frontend/dist/assets/016_难过.5d872489.png create mode 100644 frontend/dist/assets/017_囧.59ee6551.png create mode 100644 frontend/dist/assets/018_抓狂.d1646df8.png create mode 100644 frontend/dist/assets/019_吐.51bb226f.png create mode 100644 frontend/dist/assets/020_偷笑.59941b0b.png create mode 100644 frontend/dist/assets/021_愉快.47582f99.png create mode 100644 frontend/dist/assets/022_白眼.ca492234.png create mode 100644 frontend/dist/assets/023_傲慢.651b4c79.png create mode 100644 frontend/dist/assets/024_困.4556c7db.png create mode 100644 frontend/dist/assets/025_惊恐.ed5cfeab.png create mode 100644 frontend/dist/assets/026_憨笑.6d317a05.png create mode 100644 frontend/dist/assets/027_悠闲.cef28253.png create mode 100644 frontend/dist/assets/028_咒骂.a26d48fa.png create mode 100644 frontend/dist/assets/029_疑问.aaa09269.png create mode 100644 frontend/dist/assets/030_嘘.40e8213d.png create mode 100644 frontend/dist/assets/031_晕.44e3541a.png create mode 100644 frontend/dist/assets/032_衰.1a3910a6.png create mode 100644 frontend/dist/assets/033_骷髅.3c9202dc.png create mode 100644 frontend/dist/assets/034_敲打.b2798ca7.png create mode 100644 frontend/dist/assets/035_再见.db23652c.png create mode 100644 frontend/dist/assets/036_擦汗.b46fa893.png create mode 100644 frontend/dist/assets/037_抠鼻.64bc8033.png create mode 100644 frontend/dist/assets/038_鼓掌.2a84e4c7.png create mode 100644 frontend/dist/assets/039_坏笑.4998b91f.png create mode 100644 frontend/dist/assets/040_右哼哼.27d8126d.png create mode 100644 frontend/dist/assets/041_鄙视.7e22890d.png create mode 100644 frontend/dist/assets/042_委屈.a5caf83a.png create mode 100644 frontend/dist/assets/043_快哭了.62b1b67c.png create mode 100644 frontend/dist/assets/044_阴险.3697222b.png create mode 100644 frontend/dist/assets/045_亲亲.dfa6bbdf.png create mode 100644 frontend/dist/assets/046_可怜.634845ad.png create mode 100644 frontend/dist/assets/047_笑脸.ab25a28c.png create mode 100644 frontend/dist/assets/048_生病.cd7aadb3.png create mode 100644 frontend/dist/assets/049_脸红.9ecb5c1c.png create mode 100644 frontend/dist/assets/050_破涕为笑.a3d2342d.png create mode 100644 frontend/dist/assets/051_恐惧.7af18313.png create mode 100644 frontend/dist/assets/052_失望.87e0479b.png create mode 100644 frontend/dist/assets/053_无语.6220ee7c.png create mode 100644 frontend/dist/assets/054_嘿哈.2116e692.png create mode 100644 frontend/dist/assets/055_捂脸.28f3a0d3.png create mode 100644 frontend/dist/assets/056_奸笑.9cf99423.png create mode 100644 frontend/dist/assets/057_机智.93c3d05a.png create mode 100644 frontend/dist/assets/058_皱眉.efe09ed7.png create mode 100644 frontend/dist/assets/059_耶.a6bc3d2b.png create mode 100644 frontend/dist/assets/060_吃瓜.a2a158de.png create mode 100644 frontend/dist/assets/061_加油.77c81f5b.png create mode 100644 frontend/dist/assets/062_汗.be95535c.png create mode 100644 frontend/dist/assets/063_天啊.a8355bf9.png create mode 100644 frontend/dist/assets/064_Emm.787be530.png create mode 100644 frontend/dist/assets/065_社会社会.a5f5902a.png create mode 100644 frontend/dist/assets/066_旺柴.7825a175.png create mode 100644 frontend/dist/assets/067_好的.a9fffc64.png create mode 100644 frontend/dist/assets/068_打脸.560c8d1f.png create mode 100644 frontend/dist/assets/069_哇.74cdcc27.png create mode 100644 frontend/dist/assets/070_翻白眼.ecb744e2.png create mode 100644 frontend/dist/assets/071_666.281fb9b6.png create mode 100644 frontend/dist/assets/072_让我看看.cee96a9f.png create mode 100644 frontend/dist/assets/073_叹气.712846f3.png create mode 100644 frontend/dist/assets/074_苦涩.4edf4f58.png create mode 100644 frontend/dist/assets/075_裂开.3fb97804.png create mode 100644 frontend/dist/assets/076_嘴唇.59b9c0be.png create mode 100644 frontend/dist/assets/077_爱心.a09c823b.png create mode 100644 frontend/dist/assets/078_心碎.9a4fb37d.png create mode 100644 frontend/dist/assets/079_拥抱.e529a46b.png create mode 100644 frontend/dist/assets/080_强.64fe98a8.png create mode 100644 frontend/dist/assets/081_弱.07ddf3a5.png create mode 100644 frontend/dist/assets/082_握手.aeb86265.png create mode 100644 frontend/dist/assets/083_胜利.e9ff0663.png create mode 100644 frontend/dist/assets/084_抱拳.0ae5f316.png create mode 100644 frontend/dist/assets/085_勾引.a4c3a7b4.png create mode 100644 frontend/dist/assets/086_拳头.2829fdbe.png create mode 100644 frontend/dist/assets/087_OK.fc42db3d.png create mode 100644 frontend/dist/assets/088_合十.58cd6a1d.png create mode 100644 frontend/dist/assets/089_啤酒.2d022508.png create mode 100644 frontend/dist/assets/090_咖啡.8f40dc95.png create mode 100644 frontend/dist/assets/091_蛋糕.f01a91ed.png create mode 100644 frontend/dist/assets/093_凋谢.aa715ee6.png create mode 100644 frontend/dist/assets/095_炸弹.3dffd8e8.png create mode 100644 frontend/dist/assets/096_便便.b0d5c50c.png create mode 100644 frontend/dist/assets/097_月亮.47389834.png create mode 100644 frontend/dist/assets/098_太阳.89c3d0ab.png create mode 100644 frontend/dist/assets/099_庆祝.2d9e8f8a.png create mode 100644 frontend/dist/assets/100_礼物.37ae5ec0.png create mode 100644 frontend/dist/assets/102_發.f43fee5c.png create mode 100644 frontend/dist/assets/103_福.58c94555.png create mode 100644 frontend/dist/assets/104_烟花.61568e1e.png create mode 100644 frontend/dist/assets/105_爆竹.35531687.png create mode 100644 frontend/dist/assets/106_猪头.7eb8ff1d.png create mode 100644 frontend/dist/assets/107_跳跳.24101efa.png create mode 100644 frontend/dist/assets/108_发抖.3eabd306.png create mode 100644 frontend/dist/assets/109_转圈.67669ca4.png create mode 100644 frontend/dist/assets/emoji.b5d5ea11.png create mode 100644 frontend/dist/assets/index.beba636e.js create mode 100644 frontend/dist/assets/index.de7292ad.css create mode 100644 frontend/dist/assets/nunito-v16-latin-regular.06f3af3f.woff2 create mode 100644 frontend/dist/index.html create mode 100644 go.mod create mode 100644 main.go create mode 100644 pkg/lame/.gitignore create mode 100644 pkg/lame/LICENSE create mode 100644 pkg/lame/README.md create mode 100644 pkg/lame/clame/VbrTag.c create mode 100644 pkg/lame/clame/VbrTag.h create mode 100644 pkg/lame/clame/bitstream.c create mode 100644 pkg/lame/clame/bitstream.h create mode 100644 pkg/lame/clame/config.h create mode 100644 pkg/lame/clame/encoder.c create mode 100644 pkg/lame/clame/encoder.h create mode 100644 pkg/lame/clame/fft.c create mode 100644 pkg/lame/clame/fft.h create mode 100644 pkg/lame/clame/gain_analysis.c create mode 100644 pkg/lame/clame/gain_analysis.h create mode 100644 pkg/lame/clame/id3tag.c create mode 100644 pkg/lame/clame/id3tag.h create mode 100644 pkg/lame/clame/l3side.h create mode 100644 pkg/lame/clame/lame-analysis.h create mode 100644 pkg/lame/clame/lame.c create mode 100644 pkg/lame/clame/lame.h create mode 100644 pkg/lame/clame/lame_global_flags.h create mode 100644 pkg/lame/clame/lame_intrin.h create mode 100644 pkg/lame/clame/machine.h create mode 100644 pkg/lame/clame/mpglib_interface.c create mode 100644 pkg/lame/clame/newmdct.c create mode 100644 pkg/lame/clame/newmdct.h create mode 100644 pkg/lame/clame/presets.c create mode 100644 pkg/lame/clame/psymodel.c create mode 100644 pkg/lame/clame/psymodel.h create mode 100644 pkg/lame/clame/quantize.c create mode 100644 pkg/lame/clame/quantize.h create mode 100644 pkg/lame/clame/quantize_pvt.c create mode 100644 pkg/lame/clame/quantize_pvt.h create mode 100644 pkg/lame/clame/reservoir.c create mode 100644 pkg/lame/clame/reservoir.h create mode 100644 pkg/lame/clame/set_get.c create mode 100644 pkg/lame/clame/set_get.h create mode 100644 pkg/lame/clame/tables.c create mode 100644 pkg/lame/clame/tables.h create mode 100644 pkg/lame/clame/takehiro.c create mode 100644 pkg/lame/clame/util.c create mode 100644 pkg/lame/clame/util.h create mode 100644 pkg/lame/clame/vbrquantize.c create mode 100644 pkg/lame/clame/vbrquantize.h create mode 100644 pkg/lame/clame/version.c create mode 100644 pkg/lame/clame/version.h create mode 100644 pkg/lame/clame/xmm_quantize_sub.c create mode 100644 pkg/lame/lame.go create mode 100644 pkg/lame/writer.go create mode 100644 pkg/lame/z_link_lame_c.c create mode 100644 pkg/silk/csilk/Decoder_Api.c create mode 100644 pkg/silk/csilk/SKP_Silk_A2NLSF.c create mode 100644 pkg/silk/csilk/SKP_Silk_AsmHelper.h create mode 100644 pkg/silk/csilk/SKP_Silk_AsmPreproc.h create mode 100644 pkg/silk/csilk/SKP_Silk_CNG.c create mode 100644 pkg/silk/csilk/SKP_Silk_HP_variable_cutoff_FIX.c create mode 100644 pkg/silk/csilk/SKP_Silk_Inlines.h create mode 100644 pkg/silk/csilk/SKP_Silk_LBRR_reset.c create mode 100644 pkg/silk/csilk/SKP_Silk_LPC_inv_pred_gain.c create mode 100644 pkg/silk/csilk/SKP_Silk_LPC_synthesis_filter.c create mode 100644 pkg/silk/csilk/SKP_Silk_LPC_synthesis_order16.c create mode 100644 pkg/silk/csilk/SKP_Silk_LP_variable_cutoff.c create mode 100644 pkg/silk/csilk/SKP_Silk_LSF_cos_table.c create mode 100644 pkg/silk/csilk/SKP_Silk_LTP_analysis_filter_FIX.c create mode 100644 pkg/silk/csilk/SKP_Silk_LTP_scale_ctrl_FIX.c create mode 100644 pkg/silk/csilk/SKP_Silk_MA.c create mode 100644 pkg/silk/csilk/SKP_Silk_NLSF2A.c create mode 100644 pkg/silk/csilk/SKP_Silk_NLSF2A_stable.c create mode 100644 pkg/silk/csilk/SKP_Silk_NLSF_MSVQ_decode.c create mode 100644 pkg/silk/csilk/SKP_Silk_NLSF_MSVQ_encode_FIX.c create mode 100644 pkg/silk/csilk/SKP_Silk_NLSF_VQ_rate_distortion_FIX.c create mode 100644 pkg/silk/csilk/SKP_Silk_NLSF_VQ_sum_error_FIX.c create mode 100644 pkg/silk/csilk/SKP_Silk_NLSF_VQ_weights_laroia.c create mode 100644 pkg/silk/csilk/SKP_Silk_NLSF_stabilize.c create mode 100644 pkg/silk/csilk/SKP_Silk_NSQ.c create mode 100644 pkg/silk/csilk/SKP_Silk_NSQ_del_dec.c create mode 100644 pkg/silk/csilk/SKP_Silk_PLC.c create mode 100644 pkg/silk/csilk/SKP_Silk_PLC.h create mode 100644 pkg/silk/csilk/SKP_Silk_SDK_API.h create mode 100644 pkg/silk/csilk/SKP_Silk_SigProc_FIX.h create mode 100644 pkg/silk/csilk/SKP_Silk_VAD.c create mode 100644 pkg/silk/csilk/SKP_Silk_VQ_nearest_neighbor_FIX.c create mode 100644 pkg/silk/csilk/SKP_Silk_ana_filt_bank_1.c create mode 100644 pkg/silk/csilk/SKP_Silk_apply_sine_window.c create mode 100644 pkg/silk/csilk/SKP_Silk_array_maxabs.c create mode 100644 pkg/silk/csilk/SKP_Silk_autocorr.c create mode 100644 pkg/silk/csilk/SKP_Silk_biquad.c create mode 100644 pkg/silk/csilk/SKP_Silk_biquad_alt.c create mode 100644 pkg/silk/csilk/SKP_Silk_burg_modified.c create mode 100644 pkg/silk/csilk/SKP_Silk_bwexpander.c create mode 100644 pkg/silk/csilk/SKP_Silk_bwexpander_32.c create mode 100644 pkg/silk/csilk/SKP_Silk_code_signs.c create mode 100644 pkg/silk/csilk/SKP_Silk_common_pitch_est_defines.h create mode 100644 pkg/silk/csilk/SKP_Silk_control.h create mode 100644 pkg/silk/csilk/SKP_Silk_control_audio_bandwidth.c create mode 100644 pkg/silk/csilk/SKP_Silk_control_codec_FIX.c create mode 100644 pkg/silk/csilk/SKP_Silk_corrMatrix_FIX.c create mode 100644 pkg/silk/csilk/SKP_Silk_create_init_destroy.c create mode 100644 pkg/silk/csilk/SKP_Silk_dec_API.c create mode 100644 pkg/silk/csilk/SKP_Silk_decode_core.c create mode 100644 pkg/silk/csilk/SKP_Silk_decode_frame.c create mode 100644 pkg/silk/csilk/SKP_Silk_decode_parameters.c create mode 100644 pkg/silk/csilk/SKP_Silk_decode_pitch.c create mode 100644 pkg/silk/csilk/SKP_Silk_decode_pulses.c create mode 100644 pkg/silk/csilk/SKP_Silk_decoder_set_fs.c create mode 100644 pkg/silk/csilk/SKP_Silk_define.h create mode 100644 pkg/silk/csilk/SKP_Silk_detect_SWB_input.c create mode 100644 pkg/silk/csilk/SKP_Silk_div_oabi.c create mode 100644 pkg/silk/csilk/SKP_Silk_enc_API.c create mode 100644 pkg/silk/csilk/SKP_Silk_encode_frame_FIX.c create mode 100644 pkg/silk/csilk/SKP_Silk_encode_parameters.c create mode 100644 pkg/silk/csilk/SKP_Silk_encode_pulses.c create mode 100644 pkg/silk/csilk/SKP_Silk_errors.h create mode 100644 pkg/silk/csilk/SKP_Silk_find_LPC_FIX.c create mode 100644 pkg/silk/csilk/SKP_Silk_find_LTP_FIX.c create mode 100644 pkg/silk/csilk/SKP_Silk_find_pitch_lags_FIX.c create mode 100644 pkg/silk/csilk/SKP_Silk_find_pred_coefs_FIX.c create mode 100644 pkg/silk/csilk/SKP_Silk_gain_quant.c create mode 100644 pkg/silk/csilk/SKP_Silk_init_encoder_FIX.c create mode 100644 pkg/silk/csilk/SKP_Silk_inner_prod_aligned.c create mode 100644 pkg/silk/csilk/SKP_Silk_interpolate.c create mode 100644 pkg/silk/csilk/SKP_Silk_k2a.c create mode 100644 pkg/silk/csilk/SKP_Silk_k2a_Q16.c create mode 100644 pkg/silk/csilk/SKP_Silk_lin2log.c create mode 100644 pkg/silk/csilk/SKP_Silk_log2lin.c create mode 100644 pkg/silk/csilk/SKP_Silk_macros.h create mode 100644 pkg/silk/csilk/SKP_Silk_macros_arm.h create mode 100644 pkg/silk/csilk/SKP_Silk_main.h create mode 100644 pkg/silk/csilk/SKP_Silk_main_FIX.h create mode 100644 pkg/silk/csilk/SKP_Silk_noise_shape_analysis_FIX.c create mode 100644 pkg/silk/csilk/SKP_Silk_pitch_analysis_core.c create mode 100644 pkg/silk/csilk/SKP_Silk_pitch_est_defines.h create mode 100644 pkg/silk/csilk/SKP_Silk_pitch_est_tables.c create mode 100644 pkg/silk/csilk/SKP_Silk_prefilter_FIX.c create mode 100644 pkg/silk/csilk/SKP_Silk_process_NLSFs_FIX.c create mode 100644 pkg/silk/csilk/SKP_Silk_process_gains_FIX.c create mode 100644 pkg/silk/csilk/SKP_Silk_quant_LTP_gains_FIX.c create mode 100644 pkg/silk/csilk/SKP_Silk_range_coder.c create mode 100644 pkg/silk/csilk/SKP_Silk_regularize_correlations_FIX.c create mode 100644 pkg/silk/csilk/SKP_Silk_resampler.c create mode 100644 pkg/silk/csilk/SKP_Silk_resampler_down2.c create mode 100644 pkg/silk/csilk/SKP_Silk_resampler_down2_3.c create mode 100644 pkg/silk/csilk/SKP_Silk_resampler_down3.c create mode 100644 pkg/silk/csilk/SKP_Silk_resampler_private.h create mode 100644 pkg/silk/csilk/SKP_Silk_resampler_private_AR2.c create mode 100644 pkg/silk/csilk/SKP_Silk_resampler_private_ARMA4.c create mode 100644 pkg/silk/csilk/SKP_Silk_resampler_private_IIR_FIR.c create mode 100644 pkg/silk/csilk/SKP_Silk_resampler_private_copy.c create mode 100644 pkg/silk/csilk/SKP_Silk_resampler_private_down4.c create mode 100644 pkg/silk/csilk/SKP_Silk_resampler_private_down_FIR.c create mode 100644 pkg/silk/csilk/SKP_Silk_resampler_private_up2_HQ.c create mode 100644 pkg/silk/csilk/SKP_Silk_resampler_private_up4.c create mode 100644 pkg/silk/csilk/SKP_Silk_resampler_rom.c create mode 100644 pkg/silk/csilk/SKP_Silk_resampler_rom.h create mode 100644 pkg/silk/csilk/SKP_Silk_resampler_structs.h create mode 100644 pkg/silk/csilk/SKP_Silk_resampler_up2.c create mode 100644 pkg/silk/csilk/SKP_Silk_residual_energy16_FIX.c create mode 100644 pkg/silk/csilk/SKP_Silk_residual_energy_FIX.c create mode 100644 pkg/silk/csilk/SKP_Silk_scale_copy_vector16.c create mode 100644 pkg/silk/csilk/SKP_Silk_scale_vector.c create mode 100644 pkg/silk/csilk/SKP_Silk_schur.c create mode 100644 pkg/silk/csilk/SKP_Silk_schur64.c create mode 100644 pkg/silk/csilk/SKP_Silk_setup_complexity.h create mode 100644 pkg/silk/csilk/SKP_Silk_shell_coder.c create mode 100644 pkg/silk/csilk/SKP_Silk_sigm_Q15.c create mode 100644 pkg/silk/csilk/SKP_Silk_solve_LS_FIX.c create mode 100644 pkg/silk/csilk/SKP_Silk_sort.c create mode 100644 pkg/silk/csilk/SKP_Silk_structs.h create mode 100644 pkg/silk/csilk/SKP_Silk_structs_FIX.h create mode 100644 pkg/silk/csilk/SKP_Silk_sum_sqr_shift.c create mode 100644 pkg/silk/csilk/SKP_Silk_tables.h create mode 100644 pkg/silk/csilk/SKP_Silk_tables_LTP.c create mode 100644 pkg/silk/csilk/SKP_Silk_tables_NLSF_CB0_10.c create mode 100644 pkg/silk/csilk/SKP_Silk_tables_NLSF_CB0_10.h create mode 100644 pkg/silk/csilk/SKP_Silk_tables_NLSF_CB0_16.c create mode 100644 pkg/silk/csilk/SKP_Silk_tables_NLSF_CB0_16.h create mode 100644 pkg/silk/csilk/SKP_Silk_tables_NLSF_CB1_10.c create mode 100644 pkg/silk/csilk/SKP_Silk_tables_NLSF_CB1_10.h create mode 100644 pkg/silk/csilk/SKP_Silk_tables_NLSF_CB1_16.c create mode 100644 pkg/silk/csilk/SKP_Silk_tables_NLSF_CB1_16.h create mode 100644 pkg/silk/csilk/SKP_Silk_tables_gain.c create mode 100644 pkg/silk/csilk/SKP_Silk_tables_other.c create mode 100644 pkg/silk/csilk/SKP_Silk_tables_pitch_lag.c create mode 100644 pkg/silk/csilk/SKP_Silk_tables_pulses_per_block.c create mode 100644 pkg/silk/csilk/SKP_Silk_tables_sign.c create mode 100644 pkg/silk/csilk/SKP_Silk_tables_type_offset.c create mode 100644 pkg/silk/csilk/SKP_Silk_tuning_parameters.h create mode 100644 pkg/silk/csilk/SKP_Silk_typedef.h create mode 100644 pkg/silk/csilk/SKP_Silk_warped_autocorrelation_FIX.c create mode 100644 pkg/silk/csilk/skp_silk_sdk.h create mode 100644 pkg/silk/silk.go create mode 100644 pkg/silk/writer.go create mode 100644 pkg/silk/z_link_silk_c.c create mode 100644 pkg/utils/utils.go create mode 100644 pkg/wechat/msg.pb.go create mode 100644 pkg/wechat/wechat.go create mode 100644 pkg/wechat/wechatDBDec.go create mode 100644 pkg/wechat/wechatDataProvider.go create mode 100644 pkg/wechat/wechatIMGDec.go create mode 100644 res/result.png create mode 100644 res/tips.png create mode 100644 wails.json diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..d8460ff --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,39 @@ +name: Wails build + +on: + push: + tags: + # Match any new tag + - '*' + +env: + # Necessary for most environments as build failure can occur due to OOM issues + NODE_OPTIONS: "--max-old-space-size=4096" + +jobs: + build: + strategy: + # Failure in one platform build won't impact the others + fail-fast: false + matrix: + build: + - name: 'wechatDataBackup.exe' + platform: 'windows/amd64' + os: 'windows-latest' + + runs-on: ${{ matrix.build.os }} + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + submodules: recursive + + - name: Build wails + uses: dAppServer/wails-build-action@v2.2 + id: build + with: + build-name: ${{ matrix.build.name }} + sign: false + build-platform: ${{ matrix.build.platform }} + package: true + go-version: '1.21' \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..07196c8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# After editing .gitignore to match the ignored files, you can do < git ls-files -ci --exclude-standard > +# to see the files that are included in the exclude lists; you can then do +# +# @ Linux/MacOS: < git ls-files -ci --exclude-standard -z | xargs -0 git rm --cached > +# @ Windows (PowerShell): < git ls-files -ci --exclude-standard | % { git rm --cached "$_" } > +# @ Windows (cmd.exe): < for /F "tokens=*" %a in ('git ls-files -ci --exclude-standard') do @git rm --cached "%a" > +# ...to re-init the ignore list + +# Wails directories +build/bin +frontend/wailsjs +frontend/node_modules + +# Wails junk files +.syso + +# Go files +go.sum + +# IDEs +.idea +.vscode + +# System enviroment variables +env +*/.DS_Store + + +# runtime +User +config.json +wechatDataBackup.exe +app.log \ No newline at end of file diff --git a/README.md b/README.md index 2fd0eaa..7399fdd 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,68 @@ # wechatDataBackup PC微信聊天记录数据导出工具 + +* 基于wails开发 + React前端,实现PC端微信聊天记录一键导出功能。 +* 导出后数据可以做永久化保存,即使微信停止支持,聊天记录也可以随时查看。 +* 前端界面尽量与微信界面保持一致,减少使用成本。 +* 理论上支持所有Windows 32/64位微信版本。 + +效果图如下: + +![](./res/result.png) + +## 使用方法 +1. 下载release可执行文件直接打开 +2. 下载源码自行编译可执行文件 [安装wails环境](https://wails.io/zh-Hans/docs/gettingstarted/installation) +```shell +git clone https://github.com/git-jiadong/wechatDataBackup.git +cd wechatDataBackup +wails build +``` +编译成功后在可执行二进制文件路径`build\bin\wechatDataBackup.exe` + +3. 导出聊天记录 +电脑登陆微信,然后打开`wechatDataBackup.exe`后按照如图提示导出 +![](./res/tips.png) + +## 功能 +本项目目前的规划与实现进度: +- [x] 支持图片消息 +- [x] 支持视频消息 +- [x] 支持链接消息 +- [x] 支持文件消息 +- [x] 支持原始表情显示 +- [x] 支持按类型检索 +- [x] 支持日期检索 +- [x] 支持按群成员检索 +- [x] 支持增量式导出 +- [ ] 支持更多消息类型显示 +- [ ] 图片查看器重绘 +- [ ] 实现头像或表情预先下载(实现完全离线查看) +- [ ] 聊天报告 +- [ ] AI本地模型应用 +- [ ] 导出数据本地加密 +- ... +如果遇到什么问题,或者有更好的建议与优化点欢迎给作者提 [ISSUE](https://github.com/git-jiadong/wechatDataBackup/issues) + + +### 常见问题 +Q: 支持手机端的聊天记录备份吗?
+A: 手机端可以使用聊天数据迁移功能,将手机的数据迁移到电脑后再将数据导出 [迁移聊天记录](https://mp.weixin.qq.com/s?src=11×tamp=1724572247&ver=5465&signature=j1TNxZAx48TdBzc6KJIHInIvXlBhwSAlQ4XGowKeyijZ2gsmXyOb2Zpg9qfVyMdGrte0SwU9kT8xCDgFBI7CR7fqCHpHuZzpv3O77gSkV3mbxmFdPKfW7Fq89CzHPQr0&new=1)
+Q: 导出的数据比PC微信里面看到的少,数据不完整
+A: 这是由于可能数据存在于内存中还没有回写到磁盘导致的,退出微信时会将内存的数据全部回写到磁盘,导出数据时最好退出重新登陆一次微信,保证数据都在磁盘中再导出即可。
+ +## 免责声明 +**⚠️ 本项目仅供学习、研究使用,严禁商业使用**
+**⚠️ 用于网络安全用途的,请确保在国家法律法规下使用**
+**⚠️ 本项目完全免费,问你要钱的都是骗子**
+**⚠️ 使用本项目初衷是作者研究微信数据库的运行使用,您使用本软件导致的后果,包含但不限于数据损坏,记录丢失等问题,作者不承担相关责任。**
+**⚠️ 因软件特殊性质,请在使用时获得微信账号所有人授权,你当确保不侵犯他人个人隐私权,后果自行承担**
+ +## 前端代码 +由于前端代码不成熟,前端界面代码暂时不公开。 + +## 参考/引用 +- 微信数据库解密和数据库的使用 [PyWxDump](https://github.com/xaoyaoo/PyWxDump/tree/master) +- silk语音消息解码 [silk-v3-decoder](https://github.com/kn007/silk-v3-decoder) +- PCM转MP3 [lame](https://github.com/viert/lame.git) +- Dat图片解码 [wechatDatDecode](https://github.com/liuggchen/wechatDatDecode) \ No newline at end of file diff --git a/app.go b/app.go new file mode 100644 index 0000000..648b4a7 --- /dev/null +++ b/app.go @@ -0,0 +1,304 @@ +package main + +import ( + "context" + "encoding/json" + "fmt" + "log" + "os" + "path/filepath" + "wechatDataBackup/pkg/utils" + "wechatDataBackup/pkg/wechat" + + "github.com/spf13/viper" + "github.com/wailsapp/wails/v2/pkg/runtime" +) + +const ( + defaultConfig = "config" + configDefaultUserKey = "userConfig.defaultUser" + configUsersKey = "userConfig.users" + appVersion = "v1.0.0" +) + +// App struct +type App struct { + ctx context.Context + info wechat.WeChatInfo + provider *wechat.WechatDataProvider + defaultUser string + users []string +} + +type WeChatInfo struct { + ProcessID uint32 `json:"PID"` + FilePath string `json:"FilePath"` + AcountName string `json:"AcountName"` + Version string `json:"Version"` + Is64Bits bool `json:"Is64Bits"` + DBKey string `json:"DBkey"` +} + +// NewApp creates a new App application struct +func NewApp() *App { + a := &App{} + + viper.SetConfigName(defaultConfig) + viper.SetConfigType("json") + viper.AddConfigPath(".") + if err := viper.ReadInConfig(); err == nil { + a.defaultUser = viper.GetString(configDefaultUserKey) + a.users = viper.GetStringSlice(configUsersKey) + // log.Println(a.defaultUser) + // log.Println(a.users) + } else { + log.Println("not config exist") + } + + return a +} + +// startup is called when the app starts. The context is saved +// so we can call the runtime methods +func (a *App) startup(ctx context.Context) { + a.ctx = ctx +} + +func (a *App) beforeClose(ctx context.Context) (prevent bool) { + dialog, err := runtime.MessageDialog(ctx, runtime.MessageDialogOptions{ + Type: runtime.QuestionDialog, + Title: "Quit?", + Message: "Are you sure you want to quit?", + }) + + if err != nil || dialog == "Yes" { + a.provider.WechatWechatDataProviderClose() + a.provider = nil + return false + } + + return true +} + +func (a *App) GetWeChatAllInfo() string { + a.info, _ = wechat.GetWeChatAllInfo() + + var info WeChatInfo + info.ProcessID = a.info.ProcessID + info.FilePath = a.info.FilePath + info.AcountName = a.info.AcountName + info.Version = a.info.Version + info.Is64Bits = a.info.Is64Bits + info.DBKey = a.info.DBKey + + infoStr, _ := json.Marshal(info) + log.Println(string(infoStr)) + + return string(infoStr) +} + +func (a *App) ExportWeChatAllData(full bool) { + + if a.provider != nil { + a.provider.WechatWechatDataProviderClose() + a.provider = nil + } + + progress := make(chan string) + go func() { + + _, err := os.Stat(".\\User") + if err != nil { + os.Mkdir(".\\User", os.ModeDir) + } + + expPath := ".\\User\\" + a.info.AcountName + _, err = os.Stat(expPath) + if err == nil { + if !full { + os.RemoveAll(expPath + "\\Msg") + } else { + os.RemoveAll(expPath) + } + } + + _, err = os.Stat(expPath) + if err != nil { + os.Mkdir(expPath, os.ModeDir) + } + + go wechat.ExportWeChatAllData(a.info, expPath, progress) + + for p := range progress { + log.Println(p) + runtime.EventsEmit(a.ctx, "exportData", p) + } + + if len(a.defaultUser) == 0 { + a.defaultUser = a.info.AcountName + } + + hasUser := false + for _, user := range a.users { + if user == a.info.AcountName { + hasUser = true + break + } + } + if !hasUser { + a.users = append(a.users, a.info.AcountName) + } + a.setCurrentConfig() + }() +} + +func (a *App) createWechatDataProvider(resPath string) error { + if a.provider != nil && a.provider.SelfInfo != nil && filepath.Base(resPath) == a.provider.SelfInfo.UserName { + log.Println("WechatDataProvider not need create:", a.provider.SelfInfo.UserName) + return nil + } + + provider, err := wechat.CreateWechatDataProvider(resPath) + if err != nil { + log.Println("CreateWechatDataProvider failed:", resPath) + return err + } + + a.provider = provider + // infoJson, _ := json.Marshal(a.provider.SelfInfo) + // runtime.EventsEmit(a.ctx, "selfInfo", string(infoJson)) + return nil +} + +func (a *App) WeChatInit() { + expPath := ".\\User\\" + a.defaultUser + if a.createWechatDataProvider(expPath) == nil { + infoJson, _ := json.Marshal(a.provider.SelfInfo) + runtime.EventsEmit(a.ctx, "selfInfo", string(infoJson)) + } +} + +func (a *App) GetWechatSessionList(pageIndex int, pageSize int) string { + expPath := ".\\User\\" + a.defaultUser + if a.createWechatDataProvider(expPath) != nil { + return "" + } + log.Printf("pageIndex: %d\n", pageIndex) + list, err := a.provider.WeChatGetSessionList(pageIndex, pageSize) + if err != nil { + return "" + } + + listStr, _ := json.Marshal(list) + log.Println("GetWechatSessionList:", list.Total) + return string(listStr) +} + +func (a *App) GetWechatMessageListByTime(userName string, time int64, pageSize int, direction string) string { + log.Println("GetWechatMessageList:", userName, pageSize, time, direction) + if len(userName) == 0 { + return "{\"Total\":0, \"Rows\":[]}" + } + dire := wechat.Message_Search_Forward + if direction == "backward" { + dire = wechat.Message_Search_Backward + } else if direction == "both" { + dire = wechat.Message_Search_Both + } + list, err := a.provider.WeChatGetMessageListByTime(userName, time, pageSize, dire) + if err != nil { + log.Println("WeChatGetMessageList failed:", err) + return "" + } + listStr, _ := json.Marshal(list) + log.Println("GetWechatMessageList:", list.Total) + + return string(listStr) +} + +func (a *App) GetWechatMessageListByKeyWord(userName string, time int64, keyword string, msgType string, pageSize int) string { + log.Println("GetWechatMessageListByKeyWord:", userName, pageSize, time, msgType) + if len(userName) == 0 { + return "{\"Total\":0, \"Rows\":[]}" + } + list, err := a.provider.WeChatGetMessageListByKeyWord(userName, time, keyword, msgType, pageSize) + if err != nil { + log.Println("WeChatGetMessageListByKeyWord failed:", err) + return "" + } + listStr, _ := json.Marshal(list) + log.Println("WeChatGetMessageListByKeyWord:", list.Total, list.KeyWord) + + return string(listStr) +} + +func (a *App) GetWechatMessageDate(userName string) string { + log.Println("GetWechatMessageDate:", userName) + if len(userName) == 0 { + return "{\"Total\":0, \"Date\":[]}" + } + + messageData, err := a.provider.WeChatGetMessageDate(userName) + if err != nil { + log.Println("GetWechatMessageDate:", err) + return "" + } + + messageDataStr, _ := json.Marshal(messageData) + log.Println("GetWechatMessageDate:", messageData.Total) + + return string(messageDataStr) +} + +func (a *App) setCurrentConfig() { + viper.Set(configDefaultUserKey, a.defaultUser) + viper.Set(configUsersKey, a.users) + err := viper.SafeWriteConfig() + if err != nil { + log.Println(err) + } +} + +type userList struct { + Users []string `json:"Users"` +} + +func (a *App) GetWeChatUserList() string { + + l := userList{} + l.Users = a.users + + usersStr, _ := json.Marshal(l) + str := string(usersStr) + log.Println("users:", str) + return str +} + +func (a *App) OpenFileOrExplorer(filePath string, explorer bool) string { + // if root, err := os.Getwd(); err == nil { + // filePath = root + filePath[1:] + // } + // log.Println("OpenFileOrExplorer:", filePath) + err := utils.OpenFileOrExplorer(filePath, explorer) + if err != nil { + return "{\"result\": \"OpenFileOrExplorer failed\", \"status\":\"failed\"}" + } + + return fmt.Sprintf("{\"result\": \"%s\", \"status\":\"OK\"}", "") +} + +func (a *App) GetWeChatRoomUserList(roomId string) string { + userlist, err := a.provider.WeChatGetChatRoomUserList(roomId) + if err != nil { + log.Println("WeChatGetChatRoomUserList:", err) + return "" + } + + userListStr, _ := json.Marshal(userlist) + + return string(userListStr) +} + +func (a *App) GetAppVersion() string { + return appVersion +} diff --git a/build/README.md b/build/README.md new file mode 100644 index 0000000..1ae2f67 --- /dev/null +++ b/build/README.md @@ -0,0 +1,35 @@ +# Build Directory + +The build directory is used to house all the build files and assets for your application. + +The structure is: + +* bin - Output directory +* darwin - macOS specific files +* windows - Windows specific files + +## Mac + +The `darwin` directory holds files specific to Mac builds. +These may be customised and used as part of the build. To return these files to the default state, simply delete them +and +build with `wails build`. + +The directory contains the following files: + +- `Info.plist` - the main plist file used for Mac builds. It is used when building using `wails build`. +- `Info.dev.plist` - same as the main plist file but used when building using `wails dev`. + +## Windows + +The `windows` directory contains the manifest and rc files used when building with `wails build`. +These may be customised for your application. To return these files to the default state, simply delete them and +build with `wails build`. + +- `icon.ico` - The icon used for the application. This is used when building using `wails build`. If you wish to + use a different icon, simply replace this file with your own. If it is missing, a new `icon.ico` file + will be created using the `appicon.png` file in the build directory. +- `installer/*` - The files used to create the Windows installer. These are used when building using `wails build`. +- `info.json` - Application details used for Windows builds. The data here will be used by the Windows installer, + as well as the application itself (right click the exe -> properties -> details) +- `wails.exe.manifest` - The main application manifest file. \ No newline at end of file diff --git a/build/appicon.png b/build/appicon.png new file mode 100644 index 0000000000000000000000000000000000000000..d0e5563fb4e95b486b9d6d214df0a0cce157ab4e GIT binary patch literal 7869 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 + + + CFBundlePackageType + APPL + CFBundleName + {{.Info.ProductName}} + CFBundleExecutable + {{.Name}} + CFBundleIdentifier + com.wails.{{.Name}} + CFBundleVersion + {{.Info.ProductVersion}} + CFBundleGetInfoString + {{.Info.Comments}} + CFBundleShortVersionString + {{.Info.ProductVersion}} + CFBundleIconFile + iconfile + LSMinimumSystemVersion + 10.13.0 + NSHighResolutionCapable + true + NSHumanReadableCopyright + {{.Info.Copyright}} + {{if .Info.FileAssociations}} + CFBundleDocumentTypes + + {{range .Info.FileAssociations}} + + CFBundleTypeExtensions + + {{.Ext}} + + CFBundleTypeName + {{.Name}} + CFBundleTypeRole + {{.Role}} + CFBundleTypeIconFile + {{.IconName}} + + {{end}} + + {{end}} + {{if .Info.Protocols}} + CFBundleURLTypes + + {{range .Info.Protocols}} + + CFBundleURLName + com.wails.{{.Scheme}} + CFBundleURLSchemes + + {{.Scheme}} + + CFBundleTypeRole + {{.Role}} + + {{end}} + + {{end}} + NSAppTransportSecurity + + NSAllowsLocalNetworking + + + + diff --git a/build/darwin/Info.plist b/build/darwin/Info.plist new file mode 100644 index 0000000..19cc937 --- /dev/null +++ b/build/darwin/Info.plist @@ -0,0 +1,63 @@ + + + + CFBundlePackageType + APPL + CFBundleName + {{.Info.ProductName}} + CFBundleExecutable + {{.Name}} + CFBundleIdentifier + com.wails.{{.Name}} + CFBundleVersion + {{.Info.ProductVersion}} + CFBundleGetInfoString + {{.Info.Comments}} + CFBundleShortVersionString + {{.Info.ProductVersion}} + CFBundleIconFile + iconfile + LSMinimumSystemVersion + 10.13.0 + NSHighResolutionCapable + true + NSHumanReadableCopyright + {{.Info.Copyright}} + {{if .Info.FileAssociations}} + CFBundleDocumentTypes + + {{range .Info.FileAssociations}} + + CFBundleTypeExtensions + + {{.Ext}} + + CFBundleTypeName + {{.Name}} + CFBundleTypeRole + {{.Role}} + CFBundleTypeIconFile + {{.IconName}} + + {{end}} + + {{end}} + {{if .Info.Protocols}} + CFBundleURLTypes + + {{range .Info.Protocols}} + + CFBundleURLName + com.wails.{{.Scheme}} + CFBundleURLSchemes + + {{.Scheme}} + + CFBundleTypeRole + {{.Role}} + + {{end}} + + {{end}} + + diff --git a/build/windows/icon.ico b/build/windows/icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..b0afe8ea1a944575e6c86b7f45ac93b66430dfc8 GIT binary patch literal 421150 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 literal 0 HcmV?d00001 diff --git a/build/windows/info.json b/build/windows/info.json new file mode 100644 index 0000000..9727946 --- /dev/null +++ b/build/windows/info.json @@ -0,0 +1,15 @@ +{ + "fixed": { + "file_version": "{{.Info.ProductVersion}}" + }, + "info": { + "0000": { + "ProductVersion": "{{.Info.ProductVersion}}", + "CompanyName": "{{.Info.CompanyName}}", + "FileDescription": "{{.Info.ProductName}}", + "LegalCopyright": "{{.Info.Copyright}}", + "ProductName": "{{.Info.ProductName}}", + "Comments": "{{.Info.Comments}}" + } + } +} \ No newline at end of file diff --git a/build/windows/installer/project.nsi b/build/windows/installer/project.nsi new file mode 100644 index 0000000..654ae2e --- /dev/null +++ b/build/windows/installer/project.nsi @@ -0,0 +1,114 @@ +Unicode true + +#### +## Please note: Template replacements don't work in this file. They are provided with default defines like +## mentioned underneath. +## If the keyword is not defined, "wails_tools.nsh" will populate them with the values from ProjectInfo. +## If they are defined here, "wails_tools.nsh" will not touch them. This allows to use this project.nsi manually +## from outside of Wails for debugging and development of the installer. +## +## For development first make a wails nsis build to populate the "wails_tools.nsh": +## > wails build --target windows/amd64 --nsis +## Then you can call makensis on this file with specifying the path to your binary: +## For a AMD64 only installer: +## > makensis -DARG_WAILS_AMD64_BINARY=..\..\bin\app.exe +## For a ARM64 only installer: +## > makensis -DARG_WAILS_ARM64_BINARY=..\..\bin\app.exe +## For a installer with both architectures: +## > makensis -DARG_WAILS_AMD64_BINARY=..\..\bin\app-amd64.exe -DARG_WAILS_ARM64_BINARY=..\..\bin\app-arm64.exe +#### +## The following information is taken from the ProjectInfo file, but they can be overwritten here. +#### +## !define INFO_PROJECTNAME "MyProject" # Default "{{.Name}}" +## !define INFO_COMPANYNAME "MyCompany" # Default "{{.Info.CompanyName}}" +## !define INFO_PRODUCTNAME "MyProduct" # Default "{{.Info.ProductName}}" +## !define INFO_PRODUCTVERSION "1.0.0" # Default "{{.Info.ProductVersion}}" +## !define INFO_COPYRIGHT "Copyright" # Default "{{.Info.Copyright}}" +### +## !define PRODUCT_EXECUTABLE "Application.exe" # Default "${INFO_PROJECTNAME}.exe" +## !define UNINST_KEY_NAME "UninstKeyInRegistry" # Default "${INFO_COMPANYNAME}${INFO_PRODUCTNAME}" +#### +## !define REQUEST_EXECUTION_LEVEL "admin" # Default "admin" see also https://nsis.sourceforge.io/Docs/Chapter4.html +#### +## Include the wails tools +#### +!include "wails_tools.nsh" + +# The version information for this two must consist of 4 parts +VIProductVersion "${INFO_PRODUCTVERSION}.0" +VIFileVersion "${INFO_PRODUCTVERSION}.0" + +VIAddVersionKey "CompanyName" "${INFO_COMPANYNAME}" +VIAddVersionKey "FileDescription" "${INFO_PRODUCTNAME} Installer" +VIAddVersionKey "ProductVersion" "${INFO_PRODUCTVERSION}" +VIAddVersionKey "FileVersion" "${INFO_PRODUCTVERSION}" +VIAddVersionKey "LegalCopyright" "${INFO_COPYRIGHT}" +VIAddVersionKey "ProductName" "${INFO_PRODUCTNAME}" + +# Enable HiDPI support. https://nsis.sourceforge.io/Reference/ManifestDPIAware +ManifestDPIAware true + +!include "MUI.nsh" + +!define MUI_ICON "..\icon.ico" +!define MUI_UNICON "..\icon.ico" +# !define MUI_WELCOMEFINISHPAGE_BITMAP "resources\leftimage.bmp" #Include this to add a bitmap on the left side of the Welcome Page. Must be a size of 164x314 +!define MUI_FINISHPAGE_NOAUTOCLOSE # Wait on the INSTFILES page so the user can take a look into the details of the installation steps +!define MUI_ABORTWARNING # This will warn the user if they exit from the installer. + +!insertmacro MUI_PAGE_WELCOME # Welcome to the installer page. +# !insertmacro MUI_PAGE_LICENSE "resources\eula.txt" # Adds a EULA page to the installer +!insertmacro MUI_PAGE_DIRECTORY # In which folder install page. +!insertmacro MUI_PAGE_INSTFILES # Installing page. +!insertmacro MUI_PAGE_FINISH # Finished installation page. + +!insertmacro MUI_UNPAGE_INSTFILES # Uinstalling page + +!insertmacro MUI_LANGUAGE "English" # Set the Language of the installer + +## The following two statements can be used to sign the installer and the uninstaller. The path to the binaries are provided in %1 +#!uninstfinalize 'signtool --file "%1"' +#!finalize 'signtool --file "%1"' + +Name "${INFO_PRODUCTNAME}" +OutFile "..\..\bin\${INFO_PROJECTNAME}-${ARCH}-installer.exe" # Name of the installer's file. +InstallDir "$PROGRAMFILES64\${INFO_COMPANYNAME}\${INFO_PRODUCTNAME}" # Default installing folder ($PROGRAMFILES is Program Files folder). +ShowInstDetails show # This will always show the installation details. + +Function .onInit + !insertmacro wails.checkArchitecture +FunctionEnd + +Section + !insertmacro wails.setShellContext + + !insertmacro wails.webview2runtime + + SetOutPath $INSTDIR + + !insertmacro wails.files + + CreateShortcut "$SMPROGRAMS\${INFO_PRODUCTNAME}.lnk" "$INSTDIR\${PRODUCT_EXECUTABLE}" + CreateShortCut "$DESKTOP\${INFO_PRODUCTNAME}.lnk" "$INSTDIR\${PRODUCT_EXECUTABLE}" + + !insertmacro wails.associateFiles + !insertmacro wails.associateCustomProtocols + + !insertmacro wails.writeUninstaller +SectionEnd + +Section "uninstall" + !insertmacro wails.setShellContext + + RMDir /r "$AppData\${PRODUCT_EXECUTABLE}" # Remove the WebView2 DataPath + + RMDir /r $INSTDIR + + Delete "$SMPROGRAMS\${INFO_PRODUCTNAME}.lnk" + Delete "$DESKTOP\${INFO_PRODUCTNAME}.lnk" + + !insertmacro wails.unassociateFiles + !insertmacro wails.unassociateCustomProtocols + + !insertmacro wails.deleteUninstaller +SectionEnd diff --git a/build/windows/installer/wails_tools.nsh b/build/windows/installer/wails_tools.nsh new file mode 100644 index 0000000..f9c0f88 --- /dev/null +++ b/build/windows/installer/wails_tools.nsh @@ -0,0 +1,249 @@ +# DO NOT EDIT - Generated automatically by `wails build` + +!include "x64.nsh" +!include "WinVer.nsh" +!include "FileFunc.nsh" + +!ifndef INFO_PROJECTNAME + !define INFO_PROJECTNAME "{{.Name}}" +!endif +!ifndef INFO_COMPANYNAME + !define INFO_COMPANYNAME "{{.Info.CompanyName}}" +!endif +!ifndef INFO_PRODUCTNAME + !define INFO_PRODUCTNAME "{{.Info.ProductName}}" +!endif +!ifndef INFO_PRODUCTVERSION + !define INFO_PRODUCTVERSION "{{.Info.ProductVersion}}" +!endif +!ifndef INFO_COPYRIGHT + !define INFO_COPYRIGHT "{{.Info.Copyright}}" +!endif +!ifndef PRODUCT_EXECUTABLE + !define PRODUCT_EXECUTABLE "${INFO_PROJECTNAME}.exe" +!endif +!ifndef UNINST_KEY_NAME + !define UNINST_KEY_NAME "${INFO_COMPANYNAME}${INFO_PRODUCTNAME}" +!endif +!define UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${UNINST_KEY_NAME}" + +!ifndef REQUEST_EXECUTION_LEVEL + !define REQUEST_EXECUTION_LEVEL "admin" +!endif + +RequestExecutionLevel "${REQUEST_EXECUTION_LEVEL}" + +!ifdef ARG_WAILS_AMD64_BINARY + !define SUPPORTS_AMD64 +!endif + +!ifdef ARG_WAILS_ARM64_BINARY + !define SUPPORTS_ARM64 +!endif + +!ifdef SUPPORTS_AMD64 + !ifdef SUPPORTS_ARM64 + !define ARCH "amd64_arm64" + !else + !define ARCH "amd64" + !endif +!else + !ifdef SUPPORTS_ARM64 + !define ARCH "arm64" + !else + !error "Wails: Undefined ARCH, please provide at least one of ARG_WAILS_AMD64_BINARY or ARG_WAILS_ARM64_BINARY" + !endif +!endif + +!macro wails.checkArchitecture + !ifndef WAILS_WIN10_REQUIRED + !define WAILS_WIN10_REQUIRED "This product is only supported on Windows 10 (Server 2016) and later." + !endif + + !ifndef WAILS_ARCHITECTURE_NOT_SUPPORTED + !define WAILS_ARCHITECTURE_NOT_SUPPORTED "This product can't be installed on the current Windows architecture. Supports: ${ARCH}" + !endif + + ${If} ${AtLeastWin10} + !ifdef SUPPORTS_AMD64 + ${if} ${IsNativeAMD64} + Goto ok + ${EndIf} + !endif + + !ifdef SUPPORTS_ARM64 + ${if} ${IsNativeARM64} + Goto ok + ${EndIf} + !endif + + IfSilent silentArch notSilentArch + silentArch: + SetErrorLevel 65 + Abort + notSilentArch: + MessageBox MB_OK "${WAILS_ARCHITECTURE_NOT_SUPPORTED}" + Quit + ${else} + IfSilent silentWin notSilentWin + silentWin: + SetErrorLevel 64 + Abort + notSilentWin: + MessageBox MB_OK "${WAILS_WIN10_REQUIRED}" + Quit + ${EndIf} + + ok: +!macroend + +!macro wails.files + !ifdef SUPPORTS_AMD64 + ${if} ${IsNativeAMD64} + File "/oname=${PRODUCT_EXECUTABLE}" "${ARG_WAILS_AMD64_BINARY}" + ${EndIf} + !endif + + !ifdef SUPPORTS_ARM64 + ${if} ${IsNativeARM64} + File "/oname=${PRODUCT_EXECUTABLE}" "${ARG_WAILS_ARM64_BINARY}" + ${EndIf} + !endif +!macroend + +!macro wails.writeUninstaller + WriteUninstaller "$INSTDIR\uninstall.exe" + + SetRegView 64 + WriteRegStr HKLM "${UNINST_KEY}" "Publisher" "${INFO_COMPANYNAME}" + WriteRegStr HKLM "${UNINST_KEY}" "DisplayName" "${INFO_PRODUCTNAME}" + WriteRegStr HKLM "${UNINST_KEY}" "DisplayVersion" "${INFO_PRODUCTVERSION}" + WriteRegStr HKLM "${UNINST_KEY}" "DisplayIcon" "$INSTDIR\${PRODUCT_EXECUTABLE}" + WriteRegStr HKLM "${UNINST_KEY}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\"" + WriteRegStr HKLM "${UNINST_KEY}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S" + + ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2 + IntFmt $0 "0x%08X" $0 + WriteRegDWORD HKLM "${UNINST_KEY}" "EstimatedSize" "$0" +!macroend + +!macro wails.deleteUninstaller + Delete "$INSTDIR\uninstall.exe" + + SetRegView 64 + DeleteRegKey HKLM "${UNINST_KEY}" +!macroend + +!macro wails.setShellContext + ${If} ${REQUEST_EXECUTION_LEVEL} == "admin" + SetShellVarContext all + ${else} + SetShellVarContext current + ${EndIf} +!macroend + +# Install webview2 by launching the bootstrapper +# See https://docs.microsoft.com/en-us/microsoft-edge/webview2/concepts/distribution#online-only-deployment +!macro wails.webview2runtime + !ifndef WAILS_INSTALL_WEBVIEW_DETAILPRINT + !define WAILS_INSTALL_WEBVIEW_DETAILPRINT "Installing: WebView2 Runtime" + !endif + + SetRegView 64 + # If the admin key exists and is not empty then webview2 is already installed + ReadRegStr $0 HKLM "SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv" + ${If} $0 != "" + Goto ok + ${EndIf} + + ${If} ${REQUEST_EXECUTION_LEVEL} == "user" + # If the installer is run in user level, check the user specific key exists and is not empty then webview2 is already installed + ReadRegStr $0 HKCU "Software\Microsoft\EdgeUpdate\Clients{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv" + ${If} $0 != "" + Goto ok + ${EndIf} + ${EndIf} + + SetDetailsPrint both + DetailPrint "${WAILS_INSTALL_WEBVIEW_DETAILPRINT}" + SetDetailsPrint listonly + + InitPluginsDir + CreateDirectory "$pluginsdir\webview2bootstrapper" + SetOutPath "$pluginsdir\webview2bootstrapper" + File "tmp\MicrosoftEdgeWebview2Setup.exe" + ExecWait '"$pluginsdir\webview2bootstrapper\MicrosoftEdgeWebview2Setup.exe" /silent /install' + + SetDetailsPrint both + ok: +!macroend + +# Copy of APP_ASSOCIATE and APP_UNASSOCIATE macros from here https://gist.github.com/nikku/281d0ef126dbc215dd58bfd5b3a5cd5b +!macro APP_ASSOCIATE EXT FILECLASS DESCRIPTION ICON COMMANDTEXT COMMAND + ; Backup the previously associated file class + ReadRegStr $R0 SHELL_CONTEXT "Software\Classes\.${EXT}" "" + WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "${FILECLASS}_backup" "$R0" + + WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "" "${FILECLASS}" + + WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}" "" `${DESCRIPTION}` + WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\DefaultIcon" "" `${ICON}` + WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell" "" "open" + WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell\open" "" `${COMMANDTEXT}` + WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell\open\command" "" `${COMMAND}` +!macroend + +!macro APP_UNASSOCIATE EXT FILECLASS + ; Backup the previously associated file class + ReadRegStr $R0 SHELL_CONTEXT "Software\Classes\.${EXT}" `${FILECLASS}_backup` + WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "" "$R0" + + DeleteRegKey SHELL_CONTEXT `Software\Classes\${FILECLASS}` +!macroend + +!macro wails.associateFiles + ; Create file associations + {{range .Info.FileAssociations}} + !insertmacro APP_ASSOCIATE "{{.Ext}}" "{{.Name}}" "{{.Description}}" "$INSTDIR\{{.IconName}}.ico" "Open with ${INFO_PRODUCTNAME}" "$INSTDIR\${PRODUCT_EXECUTABLE} $\"%1$\"" + + File "..\{{.IconName}}.ico" + {{end}} +!macroend + +!macro wails.unassociateFiles + ; Delete app associations + {{range .Info.FileAssociations}} + !insertmacro APP_UNASSOCIATE "{{.Ext}}" "{{.Name}}" + + Delete "$INSTDIR\{{.IconName}}.ico" + {{end}} +!macroend + +!macro CUSTOM_PROTOCOL_ASSOCIATE PROTOCOL DESCRIPTION ICON COMMAND + DeleteRegKey SHELL_CONTEXT "Software\Classes\${PROTOCOL}" + WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}" "" "${DESCRIPTION}" + WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}" "URL Protocol" "" + WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\DefaultIcon" "" "${ICON}" + WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\shell" "" "" + WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\shell\open" "" "" + WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\shell\open\command" "" "${COMMAND}" +!macroend + +!macro CUSTOM_PROTOCOL_UNASSOCIATE PROTOCOL + DeleteRegKey SHELL_CONTEXT "Software\Classes\${PROTOCOL}" +!macroend + +!macro wails.associateCustomProtocols + ; Create custom protocols associations + {{range .Info.Protocols}} + !insertmacro CUSTOM_PROTOCOL_ASSOCIATE "{{.Scheme}}" "{{.Description}}" "$INSTDIR\${PRODUCT_EXECUTABLE},0" "$INSTDIR\${PRODUCT_EXECUTABLE} $\"%1$\"" + + {{end}} +!macroend + +!macro wails.unassociateCustomProtocols + ; Delete app custom protocol associations + {{range .Info.Protocols}} + !insertmacro CUSTOM_PROTOCOL_UNASSOCIATE "{{.Scheme}}" + {{end}} +!macroend diff --git a/build/windows/wails.exe.manifest b/build/windows/wails.exe.manifest new file mode 100644 index 0000000..17e1a23 --- /dev/null +++ b/build/windows/wails.exe.manifest @@ -0,0 +1,15 @@ + + + + + + + + + + + true/pm + permonitorv2,permonitor + + + \ No newline at end of file diff --git a/frontend/dist/assets/001_微笑.1ec7a344.png b/frontend/dist/assets/001_微笑.1ec7a344.png new file mode 100644 index 0000000000000000000000000000000000000000..ab818778c81723ea8836901cf4a545d967d1769a GIT binary patch literal 5790 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 P00000NkvXXu0mjfs2e7( literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/005_得意.72060784.png b/frontend/dist/assets/005_得意.72060784.png new file mode 100644 index 0000000000000000000000000000000000000000..5de282bd8ea62bfffd77e18010285014034fdd61 GIT binary patch literal 5783 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 XAwEX0q_uH500000NkvXXu0mjfa-8Y7 literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/010_大哭.2cd2fee3.png b/frontend/dist/assets/010_大哭.2cd2fee3.png new file mode 100644 index 0000000000000000000000000000000000000000..c0a63c1f8f274a87a90acc4f7bbb113452206276 GIT binary patch literal 5532 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 q$}X#mqPP@A-DKAC0006yP)t-s0002u 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 IM6N<$f?rx&KL7v# literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/014_呲牙.3cd1fb7c.png b/frontend/dist/assets/014_呲牙.3cd1fb7c.png new file mode 100644 index 0000000000000000000000000000000000000000..d615596555c31f12b7522d0d8e565cfaf644f65a GIT binary patch literal 6278 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 literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/015_惊讶.c9eb5e15.png b/frontend/dist/assets/015_惊讶.c9eb5e15.png new file mode 100644 index 0000000000000000000000000000000000000000..adc6d1d7541f5ec95343c112be3ced267c9b78f4 GIT binary patch literal 5354 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 IM6N<$f+MXli2wiq literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/016_难过.5d872489.png b/frontend/dist/assets/016_难过.5d872489.png new file mode 100644 index 0000000000000000000000000000000000000000..927c1344b977a51d23b615a820f3fe03ce4056c5 GIT binary patch literal 5022 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 literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/017_囧.59ee6551.png b/frontend/dist/assets/017_囧.59ee6551.png new file mode 100644 index 0000000000000000000000000000000000000000..bb814024964d6137357deffa4d5446e0e08aa54b GIT binary patch literal 5244 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 Zn(x&W(4vx30|Ed5002ovPDHLkV1h4D!odIl literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/022_白眼.ca492234.png b/frontend/dist/assets/022_白眼.ca492234.png new file mode 100644 index 0000000000000000000000000000000000000000..f2cc5d881a9a01ba971568cb512f1d9bb6814d77 GIT binary patch literal 5820 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 literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/024_困.4556c7db.png b/frontend/dist/assets/024_困.4556c7db.png new file mode 100644 index 0000000000000000000000000000000000000000..6525e880adfa5ecfe1de7928bc5f3ebd3f709d4c GIT binary patch literal 4831 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 FV1hE-I}QK< literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/025_惊恐.ed5cfeab.png b/frontend/dist/assets/025_惊恐.ed5cfeab.png new file mode 100644 index 0000000000000000000000000000000000000000..59ffdc040f5efe6397ec9ebc7c9f4a8ee0d944bf GIT binary patch literal 5325 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 w|7*2k+`MQ8&3b%|N2+!3mC0006*P)t-s0000W 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 X*X%ExR0yc&00000NkvXXu0mjf3W5~X literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/028_咒骂.a26d48fa.png b/frontend/dist/assets/028_咒骂.a26d48fa.png new file mode 100644 index 0000000000000000000000000000000000000000..549de88761f93262dbb36fe27db2f1193a41c26b GIT binary patch literal 6251 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 VWm0u?j^6+P002ovPDHLkV1h9g6ng*w literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/029_疑问.aaa09269.png b/frontend/dist/assets/029_疑问.aaa09269.png new file mode 100644 index 0000000000000000000000000000000000000000..aea4507ca77253ea9bf2a356a62b80a828220bb3 GIT binary patch literal 6362 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 literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/030_嘘.40e8213d.png b/frontend/dist/assets/030_嘘.40e8213d.png new file mode 100644 index 0000000000000000000000000000000000000000..18793fe886966f79a611838921c3eabe2f689d2d GIT binary patch literal 5403 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 literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/034_敲打.b2798ca7.png b/frontend/dist/assets/034_敲打.b2798ca7.png new file mode 100644 index 0000000000000000000000000000000000000000..9d2fdaa0c8fa8d31b34acfa9beeea9d36ee70af6 GIT binary patch literal 31889 zcmaI7V{|4_w;=pP9ox1$wr$(#=!tFHb~-jYwr$(C*|ENU@7z1z{FpVhR#hErpS@4* zs>rQC2h8ZZk9Irc-~xHy|27?o@AYTOnb~A`Xi%IBper50=Sez zc)3>z;}j$Z$GZGM(It1miI9#b`pqDQ0DxOC4|iYZT7eIc8an_ezwh3RT2cyJCQP#CNs~1)|xVl<92_$yHC8| zZ(S#Bh)IoP3VleDm6l10DtQ7XI}HZ_;JnWDeQ^rJpBx|V9h;t5-~1ga__DgSBjG2$ z+xhB@1_cKo$*l=4|LHuun7PpGgfAgX8<6n=QU1{76dSrR&)RWbe>}A zmL+4#4nqL|qIm%{wL*|^eQ1@v2w8pjoxPZ#hCf6F;mCS>)MwF>%75?4sxfT-am&Fu=;`$Lb7)1{WHILNz4j4o5bMT_u@@!c30^ zCoz;{P4q7!ItxcrA{iQWECMYTwoK5IB)z9|MB|Fl6?}`|7$stk{D|z7U`h_CR{~oE zbrEbUBgBau&U2b`W<}KVPc5*T!)YYo^KULFos&6raR&HA#v1$2F(H^nuNmq_hlv?P zXyQF~1vZ=?h8RKhmxT53s<`~{Uk%30}qh3Pk2P5@c2gb)sXv%7el#ySOHlnmc zX+Q@BGxbxFB$X*Nl6#`O4!Rq0*Trj!S5jOP6Ar*12{z{T0Ll{dul!qZEk7t&G zm9moDkfbY8DdL|;vdEI9xQMqI+dhP<_pc;MOK6Elj8{l}9~(GqLE|0@-zb%TQsg%28$G@`<`!uG;0#cIK3NS7^vSV&7B zRb^aZ#!WZ-jriM6O_Sz{#v46h93_Q2MLoqg<)lJY%}GsQ$)f^R^^Y3jAANP75^=Q# z#e;I_MT|d7<@jnHT3cG)O2EG}?*N29P=Y>iZsv5TpW5*C<3^N1o zG=-NP)xj=)TK$$Y(y4#Fly!x8$8}}!l2s9LsxYlIO)$+qc9;S|7_QsBw)E?5l z;WBg1zhHdfaR&W3{)lk4H7D_C^SAI3^ZaJ{W{!}9krj$P9^0CU)A)8W-uTq&w?*sR zZSYo#!Hir3J{f_bB8uxRM8n|dnQ zD#NsWu5rP6a&q+NX60(-*kvr&QkGSYVfR|+#z#y@u~^oSbQF8kNa}j3_XI?$T zZ*_ik5A{d&l}f2)-HV?WHp?2;intn?aGBhh6U}8+nN@?XnKnCU`)G00^VE+jw(Crn zAD1wf8J9nDwP)YgiU zfLVbNf~SKQL$X1{Ky>_Ifa6COhJ%LJB6Li$>&3jseKls;H2aw`hdvIKjjoOR#yCkK zOR$U_8#)8EgXC*h@+x~a*$frFD`6epN@#(dj``|?Moq(9L4U5)sN(G4{QPsd@=)vD ztSj~|t~|PpXT!4D(bcTd(puTt_%gHAzqO(@z&-3m>@E$(8I=tBD&lZ(b&xOOzzOuk zI)f$aFhe!f*|_>>v!D(0_-uM2$BkEuO)K7;Gvqf)TD`zg5RtGV1D3*3sjVD7>V0r# zh=N#mK}>;CT}!JpZ{l&bddd^$7LSj}n|Y{$xXUmLw1P6NM*?8sPj2D){K>|9}^a z8_TpM9d$n%%#>f1_LXJTFSX*W$NL)czm~ioJ#5z3x20RguP!7niY{y`pS5~wq`NGI zmS#h5;j3`(VvcZs*+_3Y=X+W{#!fX(jZcBG8M0mJOg2|;+~>0wK6z&Q=}oAAR{d$| zUZYrF?%8tldO!%mN9WnTNxtlCqIK7>>JsyLw4J{W+=|07!fo$4_T6fga8nq{iSsJ< zf_xIYxv+G$v)-)f>8XddQD%=JkmR;M%JjEe&%DZTYqHm-LFgAc>Z9B#@%B1UJk6gT z*c_PJN%w1cgu0OQpq=OLajB#$w8`Vk@47jSF3iT)$Cv1C`S!hGIxuz_VT;qq$;+nV zyL&whOgbnvDb2~27vNh=-}HEv{YbacQ_|})6Pd{oz;wQrZTa;)_ON{tr+3?F|Ci+1 zXoI{(ri!ncPr}#!b5F8H$L<37JaMJLTkZT;?t*9TX2I{xvUka8QZ=X3vEW=8X4 z^%nLuYNn^!qx`|~=1+MI_Xz0-Vdu05-(AT^)%1qXP3ukj&PW$wI@O2Zm*T_RoAF5L ztim(@iTBqB!*lS%yFV8>^1s{?+gVK0S;fxO+0D=q2oN%{GXfGx*%+Dum4SvP9u8wb zUH||r)IwF$SyN7y+t|*A-ta##^zJtH|F8i7UIBM|Lt`tTGm#O{%)*wBFEem@sw9J_OvqQG9eM*C*pPI{zt$D=xj*jZewlh#O=;U@?Uhh z|CRsK%s@i)Um(s_d?f!%C`~ys^Iz}dLMow;KCZhj7Nd9qiG%@8?78U<*UjJ%*B<9Y}_S_5%Zf!CNXFyS_0XEkAA zWMQT=0dla@F|o69(Q%p>a?!D{8#0+1vl|0B4H^H3&i@Ucm6?%4gj0-_RfLg)iAhXY zNSvKXlwC|nTvU{mLtKRIe{iL2otzDAje-Be+u|SZ|Hftcf8uhBI06lw?HpC@?5zLC z3lz=mob8;+7;4Q*B|9 z!pNv@?zl`z=+>lc_dQ@=sF6zFTa}i^{WdR;sOoV!C~O&%%KZ*Ry~^NftO8TaNGBn9 zIdCbth_#P>i}#6bx`br;j}!LsPP$#U-4m*4@HaH(7t3K!)YFqIXSBACj+7FbJ1;@2 zE`72z`JfS#;RZY0fIm=+Q4Up}?mKFAd0Bi~@z;&Ws2Ys5ZPwg9r_V7;h;V*OM#&H! zAR-{L(>fM>`)&Nz2cY=WdQbk^v;gJ!o*z+{92s}p0V5i5v5(*jxxxI%$(UXf5TAlWe zj`Heigw0b$aUY+qLc$}*S9SU{o@+qxfFW7ZnAVS|=c_--#Ad5c_ayvP(Q4Z{CMtSeqBcUbZ&zAkvgIJtAS&SHD`h= zsll%T;Mt4^JL#%z%m?vvJ`cbkO?_t83EVpcEs!R2At8c4-V3J}N+9Y!IB|X;a5EUW z#w%6Z({GlMzd8DwA2Qk?23_YyApzx)3dm{mx}R;$BGnW3m!xUBjWy05CtVF+eJl#qlCpt;}j_{8v2)e z%Q5ra!E-vD{sR#wdcceGgzLm(`{co6?fWRGx|;q@UEbN%l^>NJNgnC*+OcidnR~4S zl6}O0v6an#&DvKkiSARuYj(G~lwC1iYi4(L?|{g?b>k|Pns#wpn1W zPuUR=@{Rm^abx!a8VA;(BK>$g0``rbR{-X5l6m8&H?`n#es&sR8-kW+kbQu1G7P%` zO66gAr8PlRscrO9Y!%_prh6W3^UV!W<(EL{^8lR@Zb>3!ZC)k32V~v95b-jx3mG%3 z9>patYvW&av-b5yk)dHYq>;>Uv386^Pcr=Vo+C zQ->_s^3>Qb5$Ce^?H0jVCKtda$DrLq+`=){jwZZIHUE(%zCRp!FX@})$0pCE8!eDp zhCKv7@7$A!dT9_97DFiXVPecEL@ag=z=B0*jOy}(Fz7lrTBjMfeaL>AC8R2(WrU)J zA_Z%vAOC=co*Xp6*07Dwi|vIPmO@QCg^#A@JU~Pk^kBlw9!ww?p@5DBC*uxdh7)IC z<)l|sGSK19M}wiO^qVEvxhbUE618g_8{@h<^Z4F5@tF1-4*Et%xK4wK&KPJ(CEOE~ zYt-05KtQ-Y{yDN1bBfm1)`t1-$UXXl@*ZK$>&I?H`sC&0^dJCyJ5*ocz4^L$r>k)nhw}u(0{NqL{u#Y#is+b> zm^i@rE;pH4=O|Pv>2{Z(&UFd@I~X0G^bcjN&E@o4ww3Vv z<|qPEtfNFA7*t6rRA?63nqk2r_!44dpNVdXFiZRWTkvCVFmNHH?niEmovggC z+2Be3d&S+|-Kl}fF-)mM1%d{XwG0ur{89PE)sU{7*j<23d7<*Md~G0tGK($ML=qI; zC(Mvlso@=IWj4Ek7P}zxvCz6L$U=$mYaQMND*ft{?{xh$ChW$@=+g)je+yimn$h}O zj%rQ&EmeG@ort8P=N@Lo?S42xeeFZ7pj!VTs^41=GiFw{VdzozQ`_RXf-N)+M+gTY%W z?9KC1Q2GQ>W@_DXb~R%T>njS^?5qUstT1*lW!+^(EdGL{DM6k6Z%qrTbXl_|@H8`g zJMA7(yw4|B1+7+;J(AN!PCY*V9W(VgkL6hhK}E;D}zcDse_@sLo) z)noTw;->%9*M~lXkt7)zQt4SL5WLb`ST$Y?9hgB9Km82_j)R_R`)j#NC?mR|)F5!0NeP)f?;6a-=#fngVgnAuq zB?&kyhZ0XrG7*_)Y3$?=sc4slbKM^9jQV@V1v|Z{Fgu|LMLC0(_dSoViYHZQO??ME zA4S1;o+1m>)AL7rgR$1Yyf#lFoMP_bK#BgbTg_4{$PPPnBO6?~G`Da+yla6))=&Ah z-)q7je5v2nAVpw!RcH+r{x4N$Z~)k~{6fBggaN(n&~SJJJ1Ixe^0XQ$`}HaV*so;c ztZ0A}IJq=+OR`P`It2)#&FpFO8Xus{z5Q;KCQxgM~;`5;BWz zsQMhSv$bK=%;oB47ai+{=a^Gge?S!tZPs+OU0z+@dGs`dfm8jZh(ry$~SIfARsuOvV!Ve#kQteDN@=;^7c703Rp=i(`mO`o5hxjE=z zkjW%?sYg`1WcyK1>mlI#@p6Sd2e1U%t~W|Ck(_-qTOM^47J`k$;y*aGFO7eGygvNe zyZrrZ@z-kid(HW(IZJW4n77vV)6>OU^k!**dCqhuBY>$8b`Jfr|4-Pq;?B{a2oQLr zi$Lgfxmvd_7>Dj8?_U?=M*() zA!qtF$$*%IPeP+on6qOxcDYdqjzY1Z0{-e?Q{qRBc0^Ak*r*Ga8B{ zGZg7RYPQvysoM=6$&Pe?2EyHV;5@fa#BV&JX)_RNkWoZ%C8TqOhvFtAB^l>l(?ya; zk1b(G9hu5yIQ#zc@p-TTnRQCjP9CGE!&T!%;fCkj;)ff!N#ORRyXhL0bUUa{cAG=4 zZDv7Gj(GY8Q+y>sNFM6DZWc=JbuNhuv+r$*Zb8?|tS# zw7yr%#((bjhfMt42I1O`uO%OMQ?s)A<2X!FxAKVF!8N+$H!=0;5M*eLixH*g+1A>s zD6aq!ymO=Bvl~H3KYWYq5gB`N80v^dp7Zqdx8Q96N43*K`ctQ$d{HMlhEPDi2z>9QfM>z85kILr#8rMquH6jPkUy zBCrEM_0%-~M+n*0}83CfSQLCz$_Bn)~UA-lBM z06r4yLu?R|{ScmlY3DtA?ym3k9>TOS^(bdPXI_Szx^;(xH!MjZf_K*^B)Zp$kmKt# z+C}-%{`sOq6iCslaE^MB!h6U)S%;OJ4?X@<N@$aLv>8>p{RE-^2$#mh8@-79{c-VM?B5QOO-3`TSx}yA!uYuaiH${XE%8 z@-a^LU?(?;a`cun_0Q#CLs20y_kBpdoGhMGE*yJ(=|})vov(7gpx#n{E^w_OUVVL5 zroo|1{UJ+VVgz$xB-M*N(;k;}H$s8FR6NxZn_Z9?_}G#Ejj6DIz$S+)@v)*wX~nR& ze#Eib0o`llJ2v%vrL!Qnf;kp1@XZtTF0-|cLqwpitc$Na@o=Ah9eR9ACjW{8&bAot zzJ#Nzr_oX%&S(FyPFjB zv}YIRyWq5nXLHzmv>e6!D8BhHsz7d}o0Vtn&5&EI$DM1hSetRNjL@ z+)eLTg(rB|+30k%_JwFh-ibH#*g~g>f|=JG(_+-!@^-4bmAs@Rqq?f^kAD8y-;pjx>R-6{qq$x ziBR0G*VrcCh1KX6f22-+Hv|f^58NDTkOdYa#*3}0TCvt!rwvQZ4u@dQSMBw;*{MN= zV$1idIf=>xvope)rM)bOB_vR+BkdKeaw%hm`zQbVb$og%U)O6@HosoBV;^b=Fpw1Z&Iz7p90&7EK=x1G- zA`2ELMjQ5kg*<8DuX5iSRNNNbz&YeSdHWA;V|A31S}%6lrT)W40v_--)BqI{ z)`{>qh-acxv{DkU3>1p^4;ukktS#XSob#fQ9qxpY&$;n`DaIKnC^sms=_UKR;l+{< z&O0+?r8P=vOGKwPME5G5PyB%X&`6^(1o`7p)X0%GpGkYA?}X zw1!S24H7%`5_P%dr^v%MgM2h(aL|7%kz#C(A^+f8GxX>~GAEEBw?OIn9eW1*sZL1- znbpn7au*aBAc6UUde?%JK;N6R#Fdp&d7nvKuAP;BE-SUdyy95z@>~XW`op3M3Y=V1+z?( zN21_Cjlzl^j}%XK*tWKHd3`C{^FAZX9MK2XeA0Nrdh#*J%)|4r^S-US`CHJR7)}`G>vrPehz7NjD^i%eXbu(N){ygMqT*?;g3WuS2uUIe86P<7?qBAI6 z{&_~v!~W~0+4kgny3OHWSgFVNQ(gh&XQxVwLj|TS#A@5efF#kiPLpNIWEDnME>{fG z2kyzL?|#;hy|Txg7$(yoJ;-7Amb28Ze8c7p|C;^GSQX%8v(|7x{uc;-74LV*z#bhe zCOw|Awl+<$3$rCfC6}2!i%Bda0{Y+(q7XE($$5BQhuh8Zjhz^d8|?{xWxOI4D`?MW z8EL>KXa|JzOv7iJN`*r9IN^QL=wv#J2!caDG%D->7u5=7C>(#>b@v6r_{0QxoC2y& zME_x=e*{J(OD+DXg{T?$QGI=l`F5vSd2@9@WMm}xhTrY3P~^w~q2n8)`|a+PeR1Cv zW&vsbmT-=&(vA*DYu~F*v-RuY=kpHc7zgYO?F=o3MfB`?(*)Jvl4u-EKwAdY26UUr zRh+BZMtYHHnTf$48v1LA83s>XRui@X@_%_G^bvZvX#7}Lm)EmC0OI%1(2!rK*rqQt z2wPTe6kHm#_rf+#Q0;j6=mY4JU3VI&wH%`MKdVz_a@g69$$H#IVqzT6HNX-Ki4!7~ z%y_gz_9{PAND?KXaeooLHknch1*DLb6N82Tw-oX(NvNRw71OYMq4-{jCY)fuMIUl? zMURelpa|kqdLc%A-k-KYy}vP9BTGNWVN62i3N;v%z5eE9+~512eSCa&ck<#iyV}gD z=hpQ5Tv^Zp0oAI6=QfP=6uda~Gjw zU>He*V@${4!-A*ST^Dd8zIg#`tHI)4b{)*jg-MQ{O`7cRdAoMvv?v(DJXr*X{$!*f|37CCar*U~z2cG;$*&8BMTQY2l8 zFb`KxOA23$GmM3YDZi^}H8EC&x1-$4(`QhhSF1RI&zIq>#)f#cqu@x!+&NOFglp{e z6i%Th`evI%sleZDGz7zh%`T8bhDk=~x6jr7oU>78cawt#Wr#VupM1@g+e|bUBuhV!l%IjhruZ9ZDDU@YfTNL-p`u+? z)x1vgXL1nLO5;K4%W6VTi&Q9y*YkY!1bs(oMTzP4p5iEKAQxhA4U>0-x@slw(>U#l zPrC!@POXBPn%dg=(jN$qV?`-mq1Z*e_QN@Nj_BfPfN-~euIgMJrB*mYP99ag@Afxa zoD@Iu&pMSdnEkK_FM|}zi?iDmiBkp{b>)?6F}go98^kxDA8^}_Z3^j`K5ZT0AtSF> z?!(#ctIJPh*@aLN+eZ^=3r#Ef8xHK|f|)!&;E3dpNm~;ltpeNm#n_`gGQ;57Zq0qa zG(LEsb~Kfh6Z-^5u`8jzs;jFp%IoA0D0PKGAUu*I1SuJV0@2k{QY|qcr;@2IheLLk zmMBlF*ei2*04O8+_;U7UDt)byPLJA~gY5^Vs-0T@pRChc z{=4t>D%~gefi=b&4%dAv++fn~PHXi*f%jBU{#+(w`=bpzyDJWFPN~f?9W5#9>+k`x zxLi(RBSEO=xz&`imJ4}JDl%)D zCT!Ok{5JGA4Z9gQ>%(g*A6}1{hP@*kCd3ESwI87l(o9h9P>&(3QE%uwdmkvXCWuX7 z9(J7B^$Gt9$97)e<>i%K4{6Co-(Y=%k9GOcd`ZMF#OA-9PWy9k9DPU zJ~Nl-c=noeE59JQ&f9FsJXwm5mUNwY5>i$eX=@UGyBEF(l$b}*Vkx8GL$$&}o-Mz1 zn&xM6_vq$IW8QJlV9bizVRa=V9YS`)qU+|$Pbwe=ZP*sbLsp#G)|s;6u-lUylU`Gu zpC6I>pDj+1DGT>r5;7{sn{6WoIYAJOu20kH;4{l|?w^ZN<4;Lwy%=c%sgu^xP_^y{ zAk4;_yGxSw380+J!SAfY07oN>z-`fTJ{BUS?eq+E)cF$0Xe?QWP|3(NG6f7N>@8xl z&U#NSZ(b)&j%%S&dQxcLgf^Igx@ZUZG}|8 zJDw61?WT?$6RhHWR0d_qZI{R)CYmz z%T9y0><`D9@BMD0?&C1KB=_b$s@_Xk(K9LCNW8Ft&%a}jcvhCAP6}){4?_<3nee35 znKxXvrK+e4obsirc6f5Lt?<}GH=rj7Koz4B9azQR39EZ{-sd6Xve+C4{nSAos_(C- z@p73I&n`*ZZiNfv3)fN15W8_b#teh12d};gcg>lhlADz24tvx zKr!y5$UdLznfhAPYvgBp{`eQC=@-P{HWq8W8%nBA2V1!2N+upVAiH6xHQ5e%g1C$8 z`bCHhH$rVEpm5LouQfx+L(#SIXJ)x8b~Y!l|NJE(_SrtqB|t#Lje@T)@4h&vW&#j8 z4>NAGls|~uwqkYbbgzJM$Jr3Rs!(%g>cJ1Jg9yX!K_qW9>RrdXtnyeTKyOoXf7jeW zD%Gjhku@}F&t_pWvGbiz;+D&FqC0w?ZbIMJe|;Kf)S(frqPXrXAz7#o+bOtbh$Z%5 zE^nuocX2>P$}k^lPX|0obp$MvkhevQRj!Ggof{`thtEZF#SBoM9uK$5K=!45i|1Gk z`|)5Rr6=-@1ihGz&wwpS|LVzGDw^acBmYyG){M6YjAG&=rJ5V}ldXM|!A<(xtA~3! z8X(U7^+%(eh=VF)(~N=OCK9=%gJTk79r(tdqVIKSOtawnBTZU! z39p+|n~cM?EDeo|Aw^S10@?;Otu)8W^+j+{IP#4&*8S|=BwrQUgh#BihMzoyEsqzd z%ko2dbn#H43+yvp8mW1A0zo;5uK^@p0qFo?8sUOTH?7s2e}LXfb1 zdfc+F+%F$(5vS6sqR@8JjF$6A_WKq?kGl1^nU8oJD^zxSsrlB-C~AVbvywON^>#<2z703D*rH;DEL8xrr$H1p9?dE*m^VN=70h@By7q(2uI?j22wU{ zl@%?5&xKGgG65vCq(%U7H0W5o4XhgYLd$J&P@|Py*Kgj3S|zf*&XxyTih6bVq;yaP zt?KhI`Wk|JjH+$EAD9=tYLu(jAlgS=#^@=!CtX$G+@pN-TJNb#|J^ukE;p~voPpF)*yW9-F*_? zqIbo}?rxv(tP4t1si@>oltlICfQ053E~RA?8SIUy!-x;tT+tFtvo3e`g*=+H&(?)C zSE@EW#%NYIEO3eFv3%r0o~D>vaVv#dcNZk;#=eI=9Wr8D7UogoUfgz*5#2FQcEq4Q zwBs9U7~`~bMV*s?mJOUkXx(lz zElyi2y|JV>hc*?MCJ_1@_QcPGJ%JdG6EzN zA&P^zDG*Mx6-7j%q>YggTcy5*V~yEvjNXCgy?(GV#t;%4FOI;rq^XAB$gMND#&!B$ z$)OaW$IF(vOjnVI8h$Ew$Lccur1%mIfTu%P@QR965+Mr(kH)QgaYK>IT!Mv~H}}!& zw|9+HpFsJ^xKU!#;cpS%mT7Sz@o!Z*U$TTUh27~yBJ4@m{x=O&_zclvAs;kNaN&m%wGepkS$(T<9|>cQ<_!LENZwA(u?2y{)`Le z+46lX$*IrgGx!*2>MEZuiH_}ip0cyHh*f3>zicxPI|`I`Hz09|t+s6a46-(JDe`afztrGwQh>oUty;iEEixf_4)crJk{_Dl)4glD zYhC?;|BEu8%yHcf&I{;#QMQLemsA;x&VeBL@Lv1m!Erf+a&#*bGIh4hDY)+fYc&VV ziCTIzsE~(*(DE@Z`K$)?)c3_uZ+2(SmVdPN90n3zCVsVDwrVk!EP;QK1H3c{eyRB! z&FF1+19w)1h1JI^)IlgUF9H?oAm|{{wC$@F)Hmd-3Rq}Xl_YpR86$0)7!`FU`~$_L zm7+vR71`H_K}e(|M|09TecEoOxq7_(7&sUrRGq(Y9$t0z-EWTE{QmvOz}4e4ed9gz zSk`w>5xcES$VgJsZL%%Ar zKr{vt^P_h_)Aqpv0%uqn^}u7to}AfRSGu15SNBH)i$9GZ)ls%~NuqY3aN5Gz#}E1Q zoRX4~wNm-)M5-`_atGgNG3tkp4{!Cu+?13@H*Y^6BbKgAt_uH+aEFTJ*rZ|;=s?P( zV*TF&Ec<-IEJ-Gmr{n2t9!eDcsQXu5www$I3e#DSz64T<)5~ketkolQbabl{`D|?o zDXQd*xEJiagw=d9+cN0{1=@Tjqp5DBAG5u!`|s@5tM*cIa_~tg${?{t#3V1T1ZIFV zB6@gMCQ!C4exLS5%cf;jH8o`ab7t@F+aZ*!an`S{nIV7Gxxw$5UJxq+?^_{p&g^k} zqc;5AH>p!Qy5?D|ejQq+G=T8;?BMBl5$HyX9ml~*SUhrvVqyv6kUy+i1iXfbNh8y} zSY*3;1hLd}Ayf_7!Dw6`r{M=#XgEdI=U@anW3xS6G=UmGJ}n4ccqx}F%C#6nKHI{8 zpFbM}1#C`}1jIAs(953o&-hjS0NecSTddeU8Sz;A2X!!?kL&9tf-Bfnwu( zU)X24e|r#i9fWK8D~wilNSS#UO_*7$GUcywj3Az9GR*{0TY%>+uhNnW3bI6X{lp&xsAYk^7)3WnFk&qz%rL77Z;9kl_Cv6HD?P7# z$tfumZb(MLT3Tz^1cUHR{mFsvEhQ9;PHcGvvdQBjqo++;T0z#mW^{=K7jJA<%S8?{ zGw}H6^sRjKt?$>YKqRM46RX%B3P`#t!|;RQ|)tjN~!oxDsLfiK=p$ zuGF$ws(mm-k|^P8&huXTgV4$ip1$#xovmci)1&?*e;LM2C;iJ2`9z0QF6drg2?}!^ z=imerbR|-Zyk$tUSEkPnY8{6fDgl9^#TwYqExYxR%Xt1zG4XSbn9+affkG zf*nrTO}H3`JVpedm+lD%46#>P8R98z>EFj$>qr_AgWlMh}td5XOKDL&T^J^ZUlt^$WLrQJ5ClfENo z@*9a9;u;PTad0+WPkLDUTjBlElVKx2^C7XwVBzfq^^0P|OgToKDnGpPw8s)|IgvMz z5khzWlnETa`Vu)(rJKWG+%2Q~xAqRt**_}1!97XWG(vC|g@zOrU&~dy^_T(X(?5!B zNC!bB%TUaCAg|t~vj#Om{eIyNKJZpLZ{NW7_63dD!~P{ppQ^j{hMd+aEvNQGAM1VNsgr!8A^%-Cy@?5G#EV0 zs~U&Y?e;N9y{v3iJ03Btyr#Px3hS49a98X0ODuO#ECTDJOD@-sMel{5ZnQQh@B77J z)$bt2p}6M83>A~%3y72*%L#&b8^=6%PcmXfLrZ%@t_k}LJ4%vdu70x$vGdyr{_R#B zYC+3?2v+|Lr`D^bP}3?PW~k`uF;E|#AYyoKl=@Uc^fv>sNih>^#4-r!IJ{n>`?P;@ zJjb8{8s6K5<-Ot=IQ-37F%6S$o;-nD`2H>2i~0Q_*g+aY8tB#*1D zJBF3{E{B)TcrtZQDYxLfnDJdbBD6XG3Mji}WRV88=6!WQsSjQI?|tv2-MEDe0w9S z?=CLbMKm-xs&%pY-Pgz(K}d50-&}bbo7_ZXbda>ygY3IW0XFzT=2tL6W-Wx;+zHfN zu=a4Y#(*Y#DDcmWu(BFnWFeu1x%jiXQS1yz2*brx&OA2+7Snuip;mkK)~l}P9J~I$ zogp8mn^1TnLVh^X5(Ppxql4jie-4t9K-*aU?@p}-Q*xIGN+u|xxz$y;cL9Dly)C}h zcEiOxtRgS)+vF|C(qh7axoK$oC*Iz+W`1)^SP>tIA9#q~xJ67mVM?UD+Sx)sLHQZf zBA*#2K{y&an^59FEkdXXEUc|Rur#{jn^M_LvR-zIOZNGj#83aCD(Ei1jMIKEAw}rQ z4;P|A6UK3YuH3A3H(MUC$!T%MiG5Et zQYH}b$Yk^=k@W`Qn-I961MGjH%DqUskYxsmPZ1f#ZMQ$@Y2)(mBJ8De?r9vff$JcW z5bmis09vhu%2Y>l-Uvvwjn@rANihhdf%w`erot29o zRNA*6dE@@zc~t!D(;pohGete3D-O5Uzm>%XI>s^anm(8KMg=N~kO{O;g9l!AcxmdNCBB`p05>Xm|1yQr(x&f!f!q~F1yj;E2<;AfercIpz zrKhKt%^AU{8cPVNp(ZB*s(U)isR>CHiBgUp<9hn1b{cHuIOBRi# z)ms$duT0i2%FB>OiM}gdTU115flC!6iXvQm-`PnJ@kwV0b^C5O9SqC7`&mE|ip`i2 z+YbS|3yrr~ee&*%uhZamv(3ZE3k-fRk0A@N6{Z!QXS5LJdO*$sFKzh!yUU<-x6ZvD zT2{pv_Hx?^N^NYYK=92AQ~^aP%icHNZujE+oTm52TI{Sf(O-2C{5q+YdrvW(Dd-Pe zY!Hv(zJBL+kr%?4zwz^qfHL%t25Slxy3itPKejm#ezs`g>Tc0d#cZ$8t`~HZUcG-C z7z|wfopU&*Da2=|sI^ccEX8CIOp><@f#G$G*Kz!RUnF7X=Qlg&c!M_QvEBx;=dzGR zf1*$woWS5W@A6f)A`#}J$rqa^DBs~#%S0RSnWqO^NTM=tyQA-)zz1R7>YJ8myRYcQ z3;M(m_a#irLm6^nTUcFSkR&uPC7oTqMn?~@B~kEUa~wY2ok&o*_7s3qpZ!T^<7pt< z_^KU1M$-@unh$o@F_6-Lpl8EN5Z}p{$^F?84uyj|v?B)PoD;G?)p8s5w%8r;oFOi| zi%q-T7BNipE-2eu=NDqk%Nh>iSGQ(#lteN11dU3xy#xWnOcc#=Eokbll#JI1p;cA7 ztmormA^SWI=N}<__%VjRw3JGK=JPK}Y%Bt$Xcd@wHseR=;ZzJ%$f8N8bk*=-#b9V2 zx4h?!9;Oiay?=|g`;EBI*U)COALmTeAvhmwoVxdX{)5RNX)4vflQ$oea&FACe8{j8 zL$PxUIfno75}ZS3s-uAu&%jd--bC#PZySv^yY^uK|KHd2)ImlH#prah0|GnV z=6!q5)S%kpK80%NK1520>BW{vx1EpFhtDVezs%%QP|7Uj`FQwvQDjCu%mrD0Fr<)U zqTnz>!R0Ab)y#*MXlpe|Lh3(c|BU_Jh$m~(JWWocKwI+sM3fZTGZX80>J7p+Bb@ol zf1ozh#p|}R2#ZOJ4qbVQ4J@Rz%r92VRGos^wWZ>-ba38YBy^{Jx}gs-|d6WlhXOdQCUlcq%3L$({Z zl~91ThyjUk1QMfiPlgiwGHSo@3YR+F${e)JSNA8a+Vi^QU=25~Fb+2>#yNV>dyDF1 zbLVn3mi0Pn(77?PIpKSpR3n zG7uAeFR1>^55nq~2IWU-F>KM!ZIDti@UEErQ5h4b(FN8lNPG7!0abEW`vY-z2=YL5 zj9sy&=Wo6%=~i+xyCz^xgY;xw!0uqL@!xC!S4(ZX@FJ!nG!E+dpnxSL+h#-><|5~I z^0_Xmc$q9ovAOmLG*f?rU@hrhvu^TF=Wr8_SU0>ymWlW_5Jj(kq?$XgmCrtPXGow) z^mG>g4K>FOT+~XiLH9E9lfKII9J*zyDjeP$MIxMu{ z@aSva`ht>;cmWjT+5lQO6AmgId0k*E=6==MsUfU7Vz=ig@|<>4T_@K%u@@86{}=l@ z1jXZDMZf%C@%_^vR|#p~arxU{_oNjr?DaMeI5X7j+80+ML!FOqNdH@%`36^sn27{t zh{a*Aq zZV|slwtWOJ1>|`T1R7R*((=F8>+SeIsSzR*^RrpzYV&MoiAWH+bkz5vM+j`#Um2>Q zE(RiEj7SlNm=#kh#SH)otrxh?oLE1YjKgMgB5QzUIDz?>zlY%9tgNhs6xk zc_&^Y(cmfmejES{fgI!bz9jKRgxnB)!r@aeL<5jxoOrzx4ZUVx4??&F8PNjP*-Ay; zvd5MOmaTp43t_nl?V1(yT1-jeOw3A=1hmo!aPG&xY#f4kRk=c!RAuIl5C~+pNRos^8O5q^rstVTjt&Ed{l6oK(w3D z(HW0i>C;YnICu&t@%+zTgOXwwV}gwF{*ote1$(-4Ft9;|!R;`O%ut6wiL!7}hMnto zLiHOTfdf^rt0x5SZrKmdy!HcNDQCT1hCns>&TN!~RTCjgdO1Z{syoldYnxsTVUc{9vVQ0m=Mr^#|xdCm)6_@Uzt_}CtDJ5v@rxN9YHvAtO=HV`z7?#F(whvt)@pX zkS|HEDt|Rz0sVbiE&RVF3cp*r4*u}WW(b7haJ<0>AD@jvXH15Fet0HK{%Vf)Cfv0@H#X?oHzSX_Zy~sJ4o3h zPztgKwwYyKtM=qO;3zG-1>W6Q2P>ZaJ7l{B7@0{GA~IY#w;X2PGC}X`I0SY$1vnY- zMd11S-vW!x1TF1;IM=1ZxCvSC`0|^bKMh7=|9{tjC`1P--LeSn0hGN8HRtqZ#y_$)Z#x5qs!8ua&ivD@pn2ljp7k}OTvHYj5fm>>-5nPPd^l>g> zTWjnJ$dCns#j@=#9>zhn;wM$mYXfjHFaGib_<9l;%S((vI`E_`8dDhT)sK^lp_|+j z46}!-y|?)jn0#dp6qUONKe-2)_LD{Lg4rrSXM31w%lSQ>aO6M-IPj0Hcn^z-Qfwk? zxkEhc=nTM9znFr8Cuo>LR)z~&Us{p`D%i4#P&P8L*q2rG1L5mkLZAuM5yNeRLEP%I zC+4eJ{`%{{io}vw6ZVdYt;%))0wEF;WS0yzdwap@(BQG*n1*Sle2J_#dmu)~6%9H| zn&Gkm?5b{tqB7fHYm|_n8*N}Ds502BhzzDj?DSI57(~W)pmaqdKy3+W9J8z)uDtr{ zDY)mhvHiY)4xMFBsT8$^8Z*v(bvTNum_HhV2OEd?1Im##p|P1TqT!S4NuMcjp%%vs zuEt{&y`wqh^dG#Z7+zf01mnwHF#FmZC@ph9!%F!r9XSC@ghpMlAIw ztiYz-SLs~i`rQwi<32?9Cn4Cm+Y9S9oriIwY;e!QA{2KHo6}tsk!O3fMRXTP6{k-6 zU~=9Fh?h4GzY8=?w+elwQ&pFAur1>XM~*2Sxn{Po{vB#eLS|?Zz#d3M1QN2-ssShI z`9KUiY!dph!;%3zY>XF%vw}u9*y!pKXfm#KS!T}@qLzd)4L6(!gZ5d1qejUgB2P4i z-g*?`z7WJ3g7D$i^t9_P&Gj9q-m6YK+HZsgNPs2X3ZZUU%p6OPIudp4u#QB<8>))H zn85IxlJ>r$(?sFBCV{HniJeP}I?(;KiCRzU0Rhl33`nShU$v4VP$C*5SgIf@=-&e4-vSJIg9`A+ce|`c5MTI)l%|{m>gx)hg*te|>mfmw1 zI@+Re?1&GZU0Mge-q@gf3Pz>?3>_`f!s%zw1a%IEV^+|$b@*ryji)TqQ}Kuos;DM2 zF{&o-qPA+R)?4gv>(d{@8zdTu3%1hnmI7;@I}K?L2_~0#pm?$e&YcWEpEn3E|NJ=E zQ6;XZ^uWjx7xZ?-z}p>!O)r1K_?Sr`YTUX@v+m4>_J$bbj5TX^gqVs(>x#MQ5b!GC z$dI(=CA!X5T;_l=rBpHo-ZU*VTP1Hy5Kn@ zB&`7gPlxFS&EXWZM~A1R$Lvo2=#0cbBbbyv9EO-_hW_RWTwMkI@hcP*kxru;DC927 zvNsU#6Uuxr{4P+BM%a3$2U^+^?mmE@d6@&P1`32GwFo>kn}qqI$%kf+2u z>Qw)^f&Bho0owZ#FuAH~-L+5Esj;i7=X8?pq%)5|1|Snd5_2Jh!~j7MUNl@qFi%n6 z`<$NMcOO^1%IEW4H0tMlB2EMm1O%BR31JWdfy6|}OomR*V=2Zwf0*7|DPT|;DhGz4;~*Vzz2^H6ySr$2MX}P<3HoW z{kQsJ0-oQwb7ziSN7W|j7|O!yA4>e9154=5psMU&)mX}EJE~ckn#p9wWV6}Xca94zFAditxD1L&M3W6NFBwfOT`1E2nh%%2^Fml1-=TeWfdt# zV`C#7gLqv}qJ^QB^_Pedw^%sCDfpQLH=IR0m+vXXHB_u*&Y2ij|6UKguxb?ezfd;^ z3f%Sl^Uw1>099sB1FHxVio3wnQQXh0Tb$z7IsH7nk4P7W4$5%&@L?i$3Zg~06|eKw zi4!MMCrc+P;Sce>f5*>uz8Arq$;1yw7j~L)99E$u-op7;fMUooeHNl1R)<2NAMM}2 zzn)--2sB2SDqY~Zpw&SS)jF8#oKK}C@wMpArOsQ?E8!}@XR>(1x=1C8jz6zlvgo-i zcimYHbcX(~l;YU2V+3PTgV**ARD^F#m@t79;Q!#YYyeSB{WlZvnPz(Nx$1Q>&fIyo z0D40U3iwkf;GYuI+S5-z&Hty`t8}5O9#93yM*`*zxydBA4CBU)g_$#_!psY%!Nl?7 zID7-|TrBeoC>DZoaVrKBhl7CId?1AKBoaxUdhP1&h2tk%;4i!0fjxT;Ku2d6?|ZE% zui))jq!`K?sGe2&9r~Myzi_FlL2Gr-)TvYNDK9U75v{_Vc)jnQi_l6b%h{Ye+!9gz z*}tm-sF{z)B{-l@Z`-!5_JIc;$PpCk=35Dz{zsovtz!gmJaOV!SiANn4ld;Ldbp5X z5_m{#ze|WZxpn1eTkwWtH>74o+F2n2M53>v*Tm~HX3S_Xru^aQAio-HGv!9^AcPl4x#U`6BXe${M9{w4FNmF&aq^+ zDHeJT;kxMi|Lzt5XUKQ(BEEXhJ@;@ZENW%b1+PQzWd)a+XrRhu;nrJkfOYF`=Do)b zcl_K!*o0D}_aQS;%_25Mb&3wToyK=i#cQq?j%=Y6I}@T#j} z)wRnYj@IJUKW&GN4?YTm@g%4IqGd{UpXG2(=-Qi_n&_B2Zrr$c!r|~!_`h}dbG`3n z2Gio;#n)eIZU!G&(9?{u565dKTG5}QlKP7LfKri$`+UrNx-K-AzrywXCW=F;Wlv$R z70-D3Td`)5xnHt)5q#;(p8>Dw;b2s5)1~LUb#%H`lBqanALL*e@B79Rm2uUWnX>PFVW&+mT-T3g$> z@1fefl_IEnqrWkNFvpG^`!iIA6?mT?16~4s`ZZg(0KAPHl`TL*$7cim5*Hq3Z7p={ z-8-}O%{L#fU9n=4gI2=av*&-7j~w}}L7G_Fa&umn0401h``<>Pe&mJq%;IjD8I)tB9QLg4gTKyA>!%+(^n2| zp9froC`4r&)T>G5tE2>(V~|N7faIxu=tnWc0;|Csu>u0#B)F8vYzXoK!%|%y7B4ci zIXH>QuW8D}@vs_~hX;TAdmP*Vk6;w!Wn6-uDfk+Ced5Fk;t{_A|33m1d?o%)bU5J` z#P5nf7{AvgFSm8(0&)x_^H3L3QTt$9*!J%CVL)Ou5psMO*0u6Bq`(zSWp&!4*K5R2yNbv zLSWR@Q0C7FBs}gps;X3jGivZMJF2~M2}g3|=vs6ND^Pjk9M6E1m}VLZx`0Db-8W?} z@v#UM%r{kfW)p{ zkVPkyfa8LW^R=({_LhA&9RB@IN(7w#I1h1Sp zd1{i0+=H0)1WuvwUi5?%JxB>~Y%asFcLQ1is>!!bw-k^9*c1^l=037@>xLA-`tlhw zppu$!TU(*^&>`r-B{PcW5hZL2U!wv*Vvw8r%%Q9BzV4IL?w$=+)aIg3D}Q9H}QWXT&}+9 zhOs&6_5P~QF#ec!xw0wz?L&C%B2H9^5okjpo5Xoh0Mz;n{$N}OJuH=@SA4^^G8aK^S_aS4B%^!5Z4IJ{4v3I3(F5+jcfjQv2P`yA1%e!# zz=ka# z7@I)QpB{>)GMS_0F4viH_2XoDuUcBk1+S=L~3jMCs#*CikrPn>tK4?0A62^?J7yV6S zEwZY5MHHZC?KrNp3+o18qM%J2=JC55#zBqM5Fz%bJrg5`Uo&D zFl6IN_qvPkS0%k9{4#-HO;ie?GI_^cuJUaj&vR(P4;^&5e)E#Y(|r$_di)=OELM{b zB?V}R0tZ19b2`bDw5y{VBIS{i+s~@5 zL6M0l!Rwo0@;!$CH}v(NMro7Vy`2ta!YKh1LW>d5GJ%v4%`#Rn5k2^wy?FhE@Z{E@ zsfG(RPpbg$-hKBaP50jW$HvcmrjoGfkNxgQBL`mLEf9`~-M{HQ*)mB@eZb5{^IcXU^XtLqSn$@9>0>02mbc z{&d=gWZL2^vB_i#2GO!~n;(LjU>Q#{bJBB*ke)Lf5S3sq+gdyMlAt@cI!GxOBr3eh zap=V)`mQKGXYgn{-3A(^q|^A>TL`O|#z{Ju*-RcJL7JR=+P$do*^qjN?>(&bF;&w zNyi)BgC^(R$&)94fA;LzZYu0hXz)t-YG5dNLd6)|EaKl=w!92wK|jo2a54Uku{t?Z z=xABonWBAw43tNF(Bt|lyxY11%G-YfVQ&K5-Vk@nC?q3xTJrWaDp7e|js$8JOF;^s z(^-6-?t|_`1$6swhq{{45Dp3faIAA8xFlsEU}rqinG}ym7%Qwp&^KPl@~IufQdL4S zFGBErhjgo;{!bHvid2;1lEnBL0-gx7#evhZ#8w$Zd zQxhCMb_{&@<+N2>R#O9^sZ*hU+O(z7*4Cpfk3AL*R8`&4xMa!i+||_>f`vGPg)I^A zh$;-1f*DJfE?rOYFXhH5W2FX3MFON4luA|DhP1Lh@#JRc=#0YR#q%MJp9w|E&}lOH zE*|6QV03zXDF}|43bFXzaI_blyy!0QXWoW@s~x=PJc{Oimjs_O#4^I^iqQ$QQas;3 zm<~X1b}|h5E{DnyRWPB_g9;bM$U+P#cm6UI`X!;ij}Uxg&=-yITmmVZUR*+l0=XpL zht^yj4pAL+zmzq^nfxl=vtt$EyX)m@#bsu?k`z}s>GhXqwMAcQUD$WmT{m_<_uMCY zPn@`{Hxw%CAKcIr5v0YuCmf#sPSJ z^JWgLO~sga!~crr|BD+pZsg2iqy+lzpE_uXptZcWH_GFFf;}IBLRoRm5*R&t6b@Pd zEklr-SAzzh37iT;bb@lHjv!fMal9s6*GXt;T(db|ot5T30QU=6IS)5|elG<49tZ~9 z5b$|9?+ve;W5QRUh=HzwOl}k%)M)Pj96oXcHf??t!r=%Wp@L#pI*)P!B-}xXWUc@} z)s7)42q`-W{nV*bIYuTF+)2s{;QJ5ZGr@X9of2u>Vpg?MH3y}XfPVk6#~yckUoNj-jZ7)2<`$ECQU35u>_y_u>lhP zF?i)qJ2*)iDY2UU3fi6uN|hog4_pDCrzCVPEq7#13H6np>2FnSME9#OgQe2o{Ia&< zb=`;mr#i&g*(gD&tlxW5fPye^-aNiXpOMV*S;uijYJ#Us}5K#^Ynh9x-LY2QT&_6y6_D^T!Y$nW|P*v9nSHMV3OZ2L}3iuAO`VQiO^~ z2o^1v3lk~+oJ2spp&|kkV1t2)_J*WU=5h(c}6#z17zgnG$ zvt-)b56Uvog9csAI5Eqp z=+grg?UQfe&le_uxh__nS9!zO}IU2E~z>-?dR(Xe2F;T<>5WRXY!ZOSNz z=g!e=5|a$h9P$q`xHQo6Fo3aq2!HGvs*NM!Mf^W;d}ds(tsAetdRf}#a@f$FuN2j+Odt5)KKLmIMlWwMP#g-^261 zCpl9BR5O6r^UrvFGZbm9@{#lnHWeil_em7>LuAi76Nn!uOEczbK~EJhoTIcNt@ByA z_ES(RbFZ5=_tGy~sm#UgEhjw3jvR)*{yrXgs7OJjTXiKUE-5dSi`R4XdfQql zg396g1eFqSxqHE|*soB)H{Dsc?g8bufG z^+E8&NtpfWYsS1_YS#4Wa9R09W(}L|b29LQbNzCa1BoJ;PC~ZF2vx?aRcRZ#mJ- zH&|O{pWWv?bTVN)^1uoI;mw^sI1xkTWp+WVu2Z|6;c*0i|86>@LJ&vBC-K@pjrTQL z4}pt#cBwz%E+~Q5Jgg6J{D(g*-}i+t{2c#ZADTS*NX->jyn1lcrcK?Jbg;MQ-o@52=X{&)hp9sLAQ#Q1Ar{Pp*ABJrhGIFk*B#+^R zFzo_C7qdYYE(s!15R|wc9!e5BEPwC5tn=b zsxIFKhG8X3p~b^%vks?wVt+~h?!bQg-yiSs?tZL(B;LE5^Z(I|rRI{;F}@Ag<5%=N z3IF#|e5PZ%9QRl7_04#+y}vvFdfTtfm;qS~!$5kac?iJ#pps&oM3eT^tXW`Bn7}uP zigJ~ZA?K*M1s1*hvTtdfb=|l{o-doTytAR6urSfd@lm<63wSvW?GXA#0r)S#*W+-8 zQBpn%4jzDmPG#P1Lkv8Hbg`rj-7)mCyDd1;Y2j-dI-(Zz$89_;4E02IZ!nqVv>mh; zKoFdiGIpVcHPo0es>%gnzX5fXZkX2Kg_;N|gDHSw?W~~v$l1vPz5~iTByq6XQ24DJ z)0kNtGZe2k3oL=oSa$~OBdLM-_VhzLcG~}Tzgd28Z&f+;;P*t^+lPWl57%8)v`jfg znZHt#j?Q}&BeOMY*1WecP;sghKi+=g3HZs{wGhyL9M^nE5C-$cjc~#0)!f4#KrP?6 z>N*&|d;5&b7aIRmw#a`YOz^l_1O@I#36S7vpuIRR!WROoS^*G5!87#0t)#5#8AQPk z;DGj{BJ_(CFa6E`pXBLY0iq}mv5_oFy@6?9op}gS9c9pxi6N(;ttd}!!I%WmMJvQ< zPTY9cW&oc(Vo=gB8?<4sM7mtJ=r+=kgr3Eruo9>cLJ^30h${ru0NQDu^btzo}c3U?eCgR{*y( z^%5eI?>)FR{tyL$Ex7`yvQOz6DM-~Sv}!9+0S@8pe+r=g9WVkJA{7O@-1O8<^{&79 zSo+g#pIi9ggZuqoUAXy$mT{+1gulk)Z=wKnzho<}DrZ+N_z?TCZ((=_j6lH$iGjk+ z@xfUT*Y(v8GoBH}iT{=Dq^Mz0DPJaBYl?y-rkQLtewZ6W;I;z)SO#x`d zCs>6Kk2KcKTIv0vYnHd1Rd@vL3bBv)@xN7<1B+ZDcqfQ^3fNG>tztp5Vu1~rnuYH< z`e&RH=R0ST{_y81L_R8x=YLPoh_x838#qv%5jQjf2ofW4QP#4pATXa~zie6*s!BxpRDS=PS!Dz2n8C`K0eZiUJ&b z@g>-{>YAzRSC|h(mIf|nwWeI_4HQ0l$CWtaLsP_H+Wom)K;c>|9VqI>;w9K}kck<} za!OkPrmfcnWK5dS6j7713@ZF9unJD0LKU0#96&oe!)%7qQH3GzOR;BJRH|-i4rvLJ z2!A~)!nGJRpl{H3LI6X!7?|@}?UD-DqjgUu?|$rE_)ZUi{dZM>1Dm(N8`oa5;3I3i z5BV4Q$3m6K%{@7KELg#X&+GH4KaU1NaV=W9r_Ff$|NO6CgqNS#1_6u?e5N3u_m=r# z@|?*qXW4A1CSEq`!?Wz7Uz2VMthMM={wO%O;2eEfSe`^oy zd36u$*|ryAy#un*#evvh3MS5)1h;-+HFzirvb1nCM~z?$-kAyyI%eaZ`i0BSqTeQ&Vd<=rs7wdLwTrjiok}t2POQ;(gGjueP{T!9@pw@ zA`SaqKLp#K+XbD?J>cd{C2q*tqBb!W7kvkPF$cmugTQx&sU09&qyXA$M%&mpuZaJK zIj97X;#1ye1Q@%DtzW~E?x)|*ety-9PbB(AmkoalxRL}Pc@R7+R-e5B5PLEa3Z@~) z)FQ%JJWf)>NQBM0{%YUP{TKThfHHZM)bWv*Uxl-O0`J7-j-DaSaDf6Sz#eHL`{Quk zZL?wY*f4zS?iV25X`vz{!D}WdM24V;K?p5_(-wv2e)Tf^;ioTvKj4A+D=vgfSIh*H zl1Z67W)2jUehm@+87VAJ=i#eR&JFS2IK27CJ@D41y^v03!1TB|6Lc(*fq_I8266C` zcwH!e6u#IC`^2Ya!>zZ^BZ{azbHA8dPO zKco^u=m`{le=H6C)bNP{A4rI0e*EMLSbBK_EL%1XMve~g{0HY4OZMf>y*&&&u6oaw zj68-Pt-&Z@Rx{^R=ZI$w4oqL_+!c*E$KPtPHY^SZx5pEZ>4|~7TjO%xrw>3Am^h!d z;flRrhWjg37n@hGa<|Cn(VFc+57w;U88>DP3c*V19+5-Q5-CiyT5${xOR?|BD;*Sy zQeDa5mRrZeE$b$66PxKz!3(Gmo1S3Ki zdp>TAFnKDMcI`M=kvk|B3KTx4SF=@2$BO8dS+1`QB*2qk8Z+{IbB1)8iQY#28 zJsNDNXOAj_oHG_GwC2I9aR-Cys8ma-Z~Wmql04FXC#|fHU)~` zCeMGT@!=^-I4B|<)6R1gt*p$i3aktd--lrCIF3EO5pWzt?@l0P7gni3mXb&cm-+Bj(R=?({UeLySzmX>j00&aFptoi<-` zw9-uRCl%63O94}&qoXAO+h6T~p6(RH2Ly-{Pt!Y+wGHGTI8LssSFkZ=c{67gXLBHA zLOekZRu-cz#;GM;cwM`;wZOKmC*b-|Oo62zog}$@i}MR5riLSm4yY&b{%`ylcE8>U z!Jue9N%T_5xRay*Bml}+pKF5cn~rm^DIYq()Q?CVOD=Vvs%6}ea5V%th09pD+=Qwc zFIo4#uK6o^7!_LU$pUoQQINmKM zSaw7L(h)S?xD^wpAJb(JHyWzzxo!|>F=<6qR zG4;ES>MOy+;^XAT0Wi?xGgz8OfdaNp^duS*-G-FKln4EK(+O%xx8V1WH^D8pG{Tiv z)N*#K{IcL^J1de5PByvl%`H%0j^9TOv7=qSDbvi4?0&uHsqxFEw0l>_S*Eq!NxYqf zbiWOwt#ed>N{g`!`g6V4ltD#hxzqY|XJllhwZdIR-5N~n#8It1ml_FP@)}EGwOpM6 z*IF$C;MPDe;`XAIY>nAqxNI(HnxtveqhOFhRTY(Yn@}D$Aslu?gkDG7oI%%Z3N~G` z7!L2nv-r{5n}I0K(pU_gvSof5(%io{qy!M|jnt1AVqtx0^Q*J)_)phi#X zfy9-?6cdc(NZDTcJP~R-2|KUp`i4Uev(AxAfhGQ=QKaG=VhKZ^qjqfel2CJOUM6Gw zAsC+xu51f9p?%CX??=n|VbFw|q`f15eS&dIIuOj0^ZkBUOLxQ*ep#f9%R zL&e$1nH5E*Y0LMR$AMKRR9l0bXJ7G4FZr&53;hLGuG_~zr(Z& zS}AajohM^@LAA@|Ku8714U(n=vIIb|Q!_1z=g5FT^W2#hCfZU7oYM(Sp6g+d!5MdG ze~bf1OqyOM1~BUkuM=*$yeR>v?ZULLQ?yTz180DtN}*W-ZW*#5m7(x8WFa?RxzDqF z@k=fuatQ@txv`LnpzWn5_+pEwOr`ka1TkuPFD@&y`*uv4D!n;N)k$kuL-xQ`_B{ zg6djt-rT#zm+yWf3V(Q{75dRHAckK0ig?_DNi#xl)4F=79F2=&O6Cc0EgwXmVe?b% zu>DUxkQfxTgoF+@daMtwSzQOyXNBcvj>8qiPFm=1WY9N|n^$_Mr>cO|b<0@}It{zz zrq185EQXR{Dg$K&w5=<-)9El>=^Q!9#H7LqvD{#ehaizt7ov@j4f%ixIR!C`jJ>Nsk<#m!helQolgU2b#?4cdg_O}zP>&{-(} z72n!}j^m4<=ZZ5F#~~)Z3l%}tR@#!ySaDW!#0rC>ZVTlQ@a&GG?p_MtU|PAI{Ja5L zJ%CfX0!M;|0>=GIuCIluGt1!hXFIt+VR~ITVhCR6kJng(!ko4!4B;A+|902$6zqMi z530f${+rxcLq}}H#4tCfWtAS7z9<4UV+5GhU^EK{-WY(^BMF#b$U*1mB1Bw~<)Qec zS5-m%)F8j6!VF(g=};~Y=H#;9OfPZBIz>4uf%*l8i~!^q^Up(`RGGh)OARNcPB}@x z&zuJ1&EM{Gab!6d>Je$o zVJ^&fNdeh;7Wdq9krS9x0GDu(^Us>Y!yIj?W`%1#MiL{(df|r8je%%u1`fOxhiHez z*~=ixboI&$YRKNWOp3en?%uO?N}2g&JLpabjiI0F_Vei zdhS)I94rhi2NL+1BqT6w4c8ekZ9dxCI+Ig`=lleotkJ`Gr=Z-yk@wHsPGJG1id<~X z>M=R%W%$PoDQsrvNU0r_7?L#MP6|WOxZRw!TnRhnVF4qB!9kzXV#T;sjGT)Cbhn~K z>q$9*;1L$6C_^)A?n?~Xu>dLn@1o(Ddm;+R?-z)$hv)fiK{C&s7QNJmX?p{PB%hZM zKDlSZ$z_fq2kT(xH;$O*Z=i6?(bUhsHYC=6xt8X_K31eSX@MIw<>DYrnHS90vk4Ta z5~fgmaP$N(jGp8bifPI8ZOSe*<5GZ3Qd8uFNAEC6y{>*wnS6>IltXM4*BLkk@jp|A zsQeH`CA{^^5(;49r0DLm_NCLVepiOd=HnQAG(&|S9IwYYHy_|l`pIKBP)~Qj^r;~@ zR24qn+R^<^MWefpc~Km+PG)Th<0?!WlbbyJ_T54`9ME$Fpv`WUE4vqhm+!mu9bJ}R z2X!ys)_n>2oRwizaZ#w_lr9U?9m`VXU_&B|BGaxHh7=clIznNULkEVoh8s|@B=B=p z_~_Pa4Q#DPL3a75S#OKPn`4WTcPA@At5buvH4yW>Ib(8F%xO4m^c-q|*lS70eHiSFtoZr?l{_oq(23PpG9?g%E!oiTc=ls_niwECLAo-%@hC3)uC0007QP)t-s0001? zI}@5E3HXK#ofQF$90bj32c9hft{nmSdJ3Z&0L^_4_FM(;NdcxV0n#A==t>07fDp%J z1-DKE=sf|+C<63v3CMU0$aoCaKLpQ!5bs|IyjuhNaR=I62dO{-v`PZUcnrsQ49R&6 z$y)}wR|DXa8uX?k+mIRHkQnr&BLDyY$94(;0095hF#pag|Gyvq#3KE(7W~yp|F{|d z&@TC|6#LRf|JpYE*iZkw9RJ`tg@lIx^Sb=rSO5Co|Hmi#%02(*K#Yoq|H>!)>1pqt z4*&A5{N`ieg9-ok$LNs@^|LMi>X*28AN{!<{@r8#*HiVV68qv^|KDx@_tE;!Lgb1H z|MkK2r4s9x4gdJo|MI2(@|^$s>G;Gt`?eeRzc&Bwq5to8_PR3v_00a+Tk@h1|L~0a zrxb&MfB)`j%6tvpdkFvYvj6dw^sOoX<%R#zIRDm0|L=m(f)SjWnDeM5`JNK`kPiRo zjsNRR|Lj|olaT-6cB`tW|L&;&f&`pa| z4_H`O!G|8IX%>`O5a6me?(OZtw}!~JU)q}?uBV3Coi3DS6VJnjrJHndad6hdUi8{T zzN=yNxFW2481&_l-qDWfwKp*_FojtW-OO|*CMNIKWj{VWPEJnx-g#zaVy~zL(EtDd zD|Av$QveDR{v{jpQbYGQP|l!eR=hgqsEBv<+On=8xeY8+L?z z000rZNklWV5$Es;;t&6YIf#g-(iN}a2GEmc8L8!bLf;#eniDRdggNy@h*RS~`}5`rR2Vw!-q z|I}`G4rsT1zpH~0VoO$p$`??rtDqj6diRNHJ4e{Wil?q_#v4&mYu63~r^qehyHC_@ z$I*;cZ_*F4Y`M&`pg-xY3=NDRHu$=kq!0$~n%)z6h&=V((N?`+kt1(pz5JoPSfdE# zI0Gw~4UiG3*tnVr)tW4BV*Qo+Zp;IW{z+2`GY}4X%!XGTcA{~ejSy7gy-%FiRsr^` zmk+SKaWL0NI{11F8&SVP^d&x_-aE!%hAgULS-TDf7|Coqfmyg17!Hj>!b?r=lkP+G zsr$Au0p}T8*<#K{S{V_Z7&Z;UMwIKHbf0d%tqpKw6^wRbh2y)&dnRZs6;eqloe5mC z#oTx1vydsUVzI^s=;^S(0Pq%bhXvtY~x5&$zdzlf?A3O23w`#g|h}zD_o*h|5M-Reb29*b7tQu z$o9O?^Ld|NJ9y-%Xn>yKrzHFM(9qCot-83lSX&*ELWm)}Yza-m1#f?|m;PUbZL$E7 z?qRnE25J??w1kkxS+X|JNY$juO+#>0Rv)?C^hGEIJC1Gjbg%~#a0LZ;{=(Go3!HpZ zpwMg-cZo>=+ z_KtrQ1&q>};5TF_D07p+3RUxtWCD47}A5XmIR_zs|U(m+K8PAWh2HLR*jG zb|e5hKQ%0QTy6Fuwp2KVT`-102;KpdfJl#&JkUFh#xD8+ayr&Q zrz?JEl5^eg8x}!29VJ)Nt_C zDRGAUVz2{L!p)rcy~tE4(9R&z)>hMLHj5erx8Yt?fR;d(^w5G>;tYNp-E7ka*yO>P zf(nc+g=KU|QK$xEC-wwY;KmgIDDn79NCLE=()nP&Wo-JD(a~qmM(Kr8X-2SN9_>2! z@a04D8jmYV?0R4gXa?{k7K=pU5NrveZIUzB#d3z>l*34k55-cbn-0#Za+D(-?xRv1VAWaBS-+PDBY%}nxsqbP^1|MkX?f1CYP4wA^ST0lqR-G-0aFZq1-3WD+0* znEbm)QfO)axRlZ^atRM=am8a?rbt;O=l8On?App>Y z_s8nC@wT&8_>qZ;i4pPF#CsxGVyO}?;qg0_kr$h@0Whx&Z|Y5c(t^sCB9I5b-G#@` z$>?tuKF#49Xl`W)9l^5qqJBha0t4<_Ca)kmiG8X0oaNNFCp66+NcXsdVLMnN?a}h z5gzgV0EcPd-rcbQh`>(4BtH8{>o}E|uS)>MpAli{_LgSQhuVhQkZUlMBLLX|*IfW- z|8;M+FHMF~7|*CF1_S4ZB1YPaMG?!)UJMDPlESdENa{;Tkx&yNkiJ_VMo z_MsJB_*}9sEUWeH`yXIcptIn{yQd|hXcSFg=>#}|rXK~x#zWVU;<%gLk z!ed|ne~9vI<|SVEsy#-0Za`3=yQA|tPC~Z{<9A5lpa^IUbRW1OKodBJG)fl@{UnKL z7;gh;BLIQg3KqZ&vH%Qx0U82ahVi8eRs)0$H2g|kzfGX zJ-Ku`6VsFturNNb14sY`=gV`^*$b-m@jx0=;KYG0&)^AFF@Sgn&CZ4&|XW|4R3tl zbGgzZm4I)E9(Ch!H!zyvt6&z=p_eM<<&HXXw=KbDzKrRH*bgii|A0iHqZ0uxXJ zEkUWkz!N+vA4&3-jQR2DSbt_Nkr*4Bvi>U{d!X|99?IxZ7z{Y<@3{xvH_Uy3V=O8BYd|DcFn#-;p8k4R9J=A09Y+;@ml_fGyHvYcPMppDHx!@~r@UmpXgU0nQe5c!-C< zN?-<1crppT2+U#zKq{AG_}HJD6MomnHseD8d@cZvK~4=F1h;eud;=&*;BXH6ut;ZH zIX;q1IeypuuAK6Lr}euD=;-X}r#GfHg||=w2>1q2;IIL0!~A@P*BQ{TFXiSFWBKtZ zj}HMUK+p3~6~T1~;&-eBzJlZP69Tf^Dv?Mm%omF3T&B&jbLk@JSUus9;hgXh;v-G20agI(0i8u$0yFT-aD)o*Fxf>4 zQ{&V5)K~(*)WV$00)B_ZQ}K~PTJg4i@LdBsPxj+BV8K3+DY#|=W?&Kr=?VVy-t=%6 zJB&gC7Gut147Z)>aV*~9vyFy#d_?$Yz{yCppzSQeX{aUeY9POE$x;DmVQExBByiM^ zb4I7Ic9fCv8y^DjF7VBJza-W}1Umv4go@>3j|SN6Jm%q9y!`6(o`y7df?D8B>z z{wNMXzXb6iG$B|6UH^p(7utuZQG8|RkS>aZ!Ha38`*`p%fZPC?KyM1L70tjp;P^8ZUi(z4cY?+F#1HV=ysPihd>Ojbj4Hs zW&QmPUIXMTpq)@s1G_Ik;9&0n8R~@_%f;}9A2|bofdfr0&E;cs!E5^+Kd=G(E^H-%At`|foI&0|0GDdwtQfESTJX!Kh7Kg_ z0SOTQI0$a24In@TIPU~5!hjt#%d?GMx_t2K(f{8Q(5Isd zEO7q(3liw)yV$J`IIsjJ!lG<~D;;?1J}rNR0#cSc^it4&(NF7uIQSc9XC|XyA;;%d#MF0k+3L_$btgWn%MkXL(7Nu;! zCnC}M%9StP-lD`GJR$=qumco^SwJ1C!nM%|DuMKC1`(`060Hqa5&iE3Py;Bi1E#T8 z1S}P6t1Ij38=~7Hk&sIyvMt(BTNkeW%m4Mc+6fE|4Ly3K4luYjzyjW@*RH9qs&uKU zu3m$t|8*)<01D!O4RMME{z*0fwS5QpDuHp_u^n2QSN)r;-VD;}bvt+M036w|YkN(_ rs+!GP(As~Rij6hvkeZFF{_}hXxX*AjMCah<00000NkvXXu0mjfm|6G9 literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/036_擦汗.b46fa893.png b/frontend/dist/assets/036_擦汗.b46fa893.png new file mode 100644 index 0000000000000000000000000000000000000000..2b12443564d05e642ac9a696836c35c61deeae7c GIT binary patch literal 5603 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 literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/038_鼓掌.2a84e4c7.png b/frontend/dist/assets/038_鼓掌.2a84e4c7.png new file mode 100644 index 0000000000000000000000000000000000000000..403989253631ceba0c9add211e97557db0f329f1 GIT binary patch literal 6203 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 ZdC0007lP)t-s0001v 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 d_#gjhdC0007EP)t-s0002S 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 literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/041_鄙视.7e22890d.png b/frontend/dist/assets/041_鄙视.7e22890d.png new file mode 100644 index 0000000000000000000000000000000000000000..bf224636e8e8f3e709d2537a416e2122508e4e62 GIT binary patch literal 6545 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 DWOqyd literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/042_委屈.a5caf83a.png b/frontend/dist/assets/042_委屈.a5caf83a.png new file mode 100644 index 0000000000000000000000000000000000000000..f04d409c2869de363a4b10dc7874c904299fb82c GIT binary patch literal 6177 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 literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/043_快哭了.62b1b67c.png b/frontend/dist/assets/043_快哭了.62b1b67c.png new file mode 100644 index 0000000000000000000000000000000000000000..ce59b72059ce4fd2355accf154abdc535820e5f7 GIT binary patch literal 5960 zcmV-O7q{q%P)C00090P)t-s0001v zAQO}q3HgN#ogM+1AOe^u0H7=Znic}iYXr@5MB>~@T2+n5)`EUry900;z1;JMY;xhomVg z`fCQ;LFI=mf&bPs|MR%^sT2RvF7xyA|MkQ9uo(aO z-R_zX|Mb25u@(BW8vpX7|MkiL-Z=NG7XSL=|I;x4_}AZo34?=&`T6<(@2~&&(*O6) zgoTObjtl?utcr<-|Lt)9;XL}U6YG}^|K&jAiVFYjX!x!b|L1i0tP=n8vj6+(|L~KC zhJ^p-U;pf4>68rKdCj*I{AiT~|(=aCHDcL)FK zhX3A7|JX;eaU1{QPyf_H|JpwP>V5y>d;iQX|H~r(=#Bs2ZvWv|^qUd??Wq6lmjB^& z{?$A4kPrXql>gE<|Lmgw>zx1WS^wWfu5B3gpcDV*fB)r%|JPXm+EV(a744G_|J`Y} zbspAn2mj_+{HqrK-CY09HUG^g{Fo2xj12$YV*k`m{mwk(hYFC4f&b!VjaCrke+ib6 ze*fx9`=Ap4=u-W`C*4Xda*rlq8!p`V~&5()|l z+}qo;r)=cJN8zR*m|PKUKMcXZzn7Mj|Li{b$t`k247{#q|IbH;QxETY3((Kbot&Dd zn{e;lU&h76o|Smgv`_!ZHSohS?zkw^)6%h?X7AKT(Uu<<78Z9%4Ys0WT3T7dsaWc) zAg5&$wY9T%cXh|PX4=J7<+(dDGBV7|%W7z6#ETuRtg1;!NZhhP)2Aii&}JtlCb_V4 zs(Kfsauu0t6|u0dqnC27rFh@9DFOll_qrpifE;K$3J#?p7 zSR?oN8;;`sc4qwLwZnJx>*`F>!iL+ToNCahjMuoNt0p+8000xyNklz z6vwC0Ar`_Y3I+m3kwKVA%%T(DWLVKv5Fe6&AE3S#@>&qmt}JtC@=|T^!D?vtn3rx} zV$b_LJJ;Mw+Q}NN-BW+(n0qzc{LeY}^=pK7ua|C zO4D|TT$iX+0zDoV%qhVsZU0W0xy ^$0>|`UtOa`(qN-WQbqsixLr}r-u`Qql|8Mh3< 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 P00000NkvXXu0mjf>}hP% literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/045_亲亲.dfa6bbdf.png b/frontend/dist/assets/045_亲亲.dfa6bbdf.png new file mode 100644 index 0000000000000000000000000000000000000000..2896ca1d924dc20e971d701511642e42167ecf1c GIT binary patch literal 5458 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 IM6N<$g3hISd;kCd literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/046_可怜.634845ad.png b/frontend/dist/assets/046_可怜.634845ad.png new file mode 100644 index 0000000000000000000000000000000000000000..742ac567005a69bf7e6e017a687e4bb25ea800b0 GIT binary patch literal 6229 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≀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 literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/051_恐惧.7af18313.png b/frontend/dist/assets/051_恐惧.7af18313.png new file mode 100644 index 0000000000000000000000000000000000000000..976b7057c5fc07aec134fa777850f24ed32ae33e GIT binary patch literal 5653 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 C5FD_dzP3&!?{3SCXC#Wu52U=gV0D z`{H4=zoMrd^JR5CpzzEv4DotOIyMc2XAJEyN!mRKt|JTvgL2{#ZL=?rrqMjkUVB^G vWI7!;N~c{+@V_aRNQZgwkci#*uPgKmkUEZ@5{7C>00000NkvXXu0mjfZq&54 literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/052_失望.87e0479b.png b/frontend/dist/assets/052_失望.87e0479b.png new file mode 100644 index 0000000000000000000000000000000000000000..28f031eb4b160b3444aebd48ed31643b127b423f GIT binary patch literal 5723 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 Ef^J18M*si- literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/055_捂脸.28f3a0d3.png b/frontend/dist/assets/055_捂脸.28f3a0d3.png new file mode 100644 index 0000000000000000000000000000000000000000..c20cab81557580433fb19d03e119057e1b5aa5b9 GIT binary patch literal 6365 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 literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/056_奸笑.9cf99423.png b/frontend/dist/assets/056_奸笑.9cf99423.png new file mode 100644 index 0000000000000000000000000000000000000000..914890ba494913756fcc243c03f2a06b178cbb86 GIT binary patch literal 6061 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 literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/057_机智.93c3d05a.png b/frontend/dist/assets/057_机智.93c3d05a.png new file mode 100644 index 0000000000000000000000000000000000000000..e802d4d6d8b69c5bb33f033b9c0926dabae3a561 GIT binary patch literal 6162 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%0AZ^bR&s^w{03-9@|0i|RqPcep28+Uy^oF@u{GD^f zZHGyqb;A~44U9y(0~#YF4+Z$=H7hgscFq6@P9Y_Xr8msE`|Y`zvu5@eC0d}NA;9m; z_%4{8m-W|w<0LZ|aoF*`ps)mMc)z~`YtPNJ{nA@T9uS1GQCxXh`1#+_tU0&j&P61E zVG7n*`P|%F=FGZIW#{MR#hI*002ovPDHLkV1fkuS~&m! literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/060_吃瓜.a2a158de.png b/frontend/dist/assets/060_吃瓜.a2a158de.png new file mode 100644 index 0000000000000000000000000000000000000000..bd99b78c159831fb513896b08b6c34623827c5e3 GIT binary patch literal 5850 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 V0yq@%^6~%x002ovPDHLkV1n##1w#M; literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/062_汗.be95535c.png b/frontend/dist/assets/062_汗.be95535c.png new file mode 100644 index 0000000000000000000000000000000000000000..aa8e7e3f5f12f24d3e3f373480c93e2ff5af1de7 GIT binary patch literal 5498 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 literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/063_天啊.a8355bf9.png b/frontend/dist/assets/063_天啊.a8355bf9.png new file mode 100644 index 0000000000000000000000000000000000000000..95aefcd85212098056168285947843bcbcea957c GIT binary patch literal 5881 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 P00000NkvXXu0mjfHy=Wf literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/064_Emm.787be530.png b/frontend/dist/assets/064_Emm.787be530.png new file mode 100644 index 0000000000000000000000000000000000000000..94f777d4f539ec553619993ce71cb64794cafcb3 GIT binary patch literal 5395 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 literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/065_社会社会.a5f5902a.png b/frontend/dist/assets/065_社会社会.a5f5902a.png new file mode 100644 index 0000000000000000000000000000000000000000..0770fa52836146ef896995b67ed6c6035999c3f8 GIT binary patch literal 6429 zcmV+&8RF)NP)C0008_P)t-s0001? zDh-`10h$;C`GO0a9s;Kv0rqza_;3jEV+Zk00>@|t#&rtKXa=h=0liiP}~C z3d3Lp=cz69UIni{0?8Zz;i4?qIRnds6W=iaT;`_V`Lxf%PrLG`B-_p22D<2?J$ zLB((h`LY`Fq7m<%5dZt+_`^EEV+QxXH~7XrgM*0kttkKZ&h_>6|L~LSm=5rvApiEs z|MRB*@tFVdjQ{u2{^fD$lnu#x4f3ZX=8g;Cg9`un*8lCL|LcbR*i*x52;+$ghlh!b ziG}~>K>zi@|MH*y?2Z29d;j*u{M1Z`g@l5EfB)`z{@PlRkB-fM5czN$??ymgc zYX9tF-hBxF@V5Jx5C8SG|MRZ@?}Gm7f7*8m`rKas`|9e8694UM{@!A;a2ni;760gy z{H+#!N)4i*p8v}u`k@m4=3D*AFYS>M^_&rYe0u-tocFsj{p5%L-Aek%JNu^<&~Xg^ z)r$0i50{mc znv{H|WfT6}Xp@hD_taDW{O{ezQ~lXK>aQ=$%E`{UWaY$S)3Z?Rxi#jYC5253=zPR^_H@<`@!otAp?CiR^ zxWTMn@Xk-Ipl>51BizJ$j%6a;s6wB0DB9WC)z#FosD91AdQwqP^4Lh%oj1~>D7T$n z;jAvIgDZwu73b21^y8jpWMiv|NaEt*-{0N^jayFu001X+QchC<5KtieFg*M1;-}y8 z?rpn>c+1vI(2GtWrGIKUw*9^?WyhfPn44bjzE1!E6|PA{K~#9!?36ud8etg6dyStr z6dgp$ZH`*+>WR>RV8?))iv~9jC*|zma)rBg30O|4gmMUnf|ALrNW|NlPE^S+NBc;JDhp{O-ikn#I`G{NU%n4oiw zdh~ywoI!>Tc|8t8xx#RG0<@0_u06VED3_lOK)R{dlgUIPu}(-NlF4LUZz={{FwXmn z1Qqm!Jca`8L_EgxJjZb?fdhOj9#16e#01T_?#06zLwk&-Zi;hkH2VHeqEVLPVWO@p zhL;Ym+=9y&aA5CH=U8ZmpY__s+UtH_6vcl3b*AP$ZYv(j>K`n*Q7 zo?JK8!_V8bmL`|-sr1%o!d5z!=}MYdZFdj|jz=zZ#S!qY%)%Ox$L4ts>b+V^%A}xd zX#@LpI+Yc~YA=jj#MV&`jsUZgL{Ln?Vaj9ky{ak~wr(Mvm&D?;_aqF-y5gpTD@Z== zR_e((VjphzrFseWf28k@%WtoxP8CZK;g$Y$cu6+4KUqBLF)Gqg?NJG z;h%!wq#X*P&#{rV*iEHV^I}?vuzcJM!t%u!3>ZyppN)22ONCSl{Z0yY&kNOXl#7ud z(5_{}?@{z*9MLaonL?qE#{hWVK;D|{xzcJQ2so0)a%rG^s6LYYPG8RF^BFSG<{)Da zsfHksGwcBRdaQ zKf{`e`YOVr5KxNL;`%RncDpZEN|)gOur)F&w@@MtbW0XO)pFp5gT?oc^mi|*RJzm2 z(GVP6$k6#aUD5z18>wbG_^^lr>Z!T^Xh)Q7O4G^c)9&s&u>0xsNGk2zLU*St@5naN z;kK0p{{r=I?O&8kWciIeIfeB8{$McJ$BV(~bmz?tKoY|im$6(h9pFlOGN%E*=ej<4 zBMkQ;esFT!XdIs$?CtFxj3D(E12ekaY^1l+bxa2vIE}&i?mw@hZ^Tf4!f!@{!QM%u zaWeW(F}kQ*LA{_OjO zkORVG))AB$eL^Ff~Kj(DE|_-@>6Qw0*q8u?UJ&3j?jOf=5l2ML@tiL;oTpU zb7k}^@QJk;4?^pObrk$}7l8YNjtlTrOT7g4e~iy2x$-8VylHvBym_seY+5sUs2{%! zN2Alx@asoaQwd^+Gt1!d9r~_cjF@R?l5rfz=?;QkbwekCxvW;L8m+==>wu02W-p4> zD-EB4;$wRj*sG0!9caxGEII~CmRhJCc57QG9yKZ}XlrfN*0r@o7acG9{-0w$F0DR~ z$6iR^uixMCe+&(P0-U^hAcHFKIRv?0x68_WdhzF2UPes90wY0qzGrH z4*8z~*cu%Uwc6ou=s2LuzaP-4{!QR97RGtZEZB!XE+=&kf@Th8@n1z4J(3h)jz<6O z_3Lji0r0}16WNv*-8Mmf-|Z`y*=91bWNjqX4sdlTCILkl{1%6i-~-g;U|aA>u!gfx6MS<1{0*`(-aSqR^m=sSo2M2muIKpq0t^jG zL@+Xc9}XLP79H@3Vm%((>9mLaRxitH8Ja{9(C;GD=J1iavhRsI7z`#qUdEQbW%>Fe ziBI6O_;f|`ou&EK6*p&~@z?_8O7!8Nzm6c$x3{Hd&6?HK>+yT6UT>HsQG|Lvz(fve zOy_Umgt!d#8<4kr3GM3{r+h@xAF0-f0tG-u-@nD^}2bAeo-zP_FluM*K{G=`;!;1G5}&LwyjGx$l% zw#}0ALY75&2cjU;K}CXlascuAJ&-2q*G z>gwvryQnR4l;?!u1jo|dsKM%7hvJ~AsDN@oilTd^`sr?2PRc#3Hd5cOp6H20BB9nq zu>K}tp!!ik{mhy(yKQ6+hK|cofy0MZD(Bs&8K=}huPhJmS(-`S|0`q%#q{ zbMx7=XAl?R)z6$b15Tc_VGfSuIF(0}3Md-G0HEiaAd^jfm>+m+4ZH$`3<&$mlPbN`90{D<;QP?0g#}u zyVJtfV1G%LChGAr+82v0S+ZD^hrW$lhS)_pS^x%S7uY`G3pjh*y4sxaj&crJd9D%| zsh802Ys%W)er$^Fc5I5w(riuLUsYHrhq^)m{W&mzCYUiKM+?Bf95_fdX(=s@QW$Bk zKmHRgpf}LOPllnQBmiyLn3inLU;LQ<#JZA3kvb_?C<+Q@&z=nf%F^|R2R6Ytv;gjf zpbs9r?1TrD!j8KFBkO7JZh?ucB+C7Erm3&8@>wSp&YD|e<|8eVD5%hV=odhLE)1+Z zbY#ltfj6UDwqM^5&OK}>P{8#b+HehrA zB2mDDmQE=+1Ne_4t_!m_!L(7wOR8PhfUA0k>r#VUA(zWf-cPlLB9bWlh=P-Ed0|HY zuVA1rqD2KHq%$dHqKNz9fN?`#G=MIY>Q5R~{n4Eaf~5QHwdxYrB?YliSh%?GK@|0n zL}B%}xBFSUk)orO|7QRoG2CH>Y?1_|$H9cjJKhHP-vDa;)u8*MtEA+dO%8|!5Q`>S zLrs)m0uNCigeWF&38cisER{M4eZj!t%q|==>RQsFBfo35sc{!sVY>6VdToiz#v9-) zELpN7_9_zvMQKCO=V+B~PGFbiKRiMtfVqN!vBSjgKk8c0LF9Eh=<6#?byb=NuC;4j zwnEVW9DuT-A}$JY>O{*b1)^HonU+-Gy(|yiG)-?33}6vt=5Vr$=&MxQps&aG-&?0C zF5XnVv*er{NF5Xv6_u5h#rpbUWdy-PXV&>?mF1&_WoY-ojDeYhh5jpX2UIHV>x=q^ z;#HgP?$}wfLJlMb;D8{gu=h0 zZ{yl?3Ni_QI)H^DT%wT#Lov>_u371>?{QLWTsaef0XOvLF32)4eTO@sQw#F=`e*>d z(p4KyEnjhbW3^IZK#~$)gOP~!Y}SWT*QqGeOENFy5GR>_RTM} ztuhSb>qKw*4_X;AR;g44+fA*tw(BvWi`cW3oYY)27h+FZ(BmIatjI}_U71nv;1o8- zqy#6JP*7r+kco+)E4_$lVws>tlrpCz4F56{ob6tiD$9mrWfJ^)%}6}p6_|z z@BPmC(stxOdrnpl{1Wj)KEK~FwA`tK(gq#}Xv$~U#?RlWp*dTf6yJXOHSuecfT7o3 zca#VB;wuKa^-X$nRmDg8Pb>|OApcUam(&Xm#)7kM!i1^flM;;ol8n`pH@Y0E;MOr>qKT*u2Oik15tm722Y0DW! z4H`RuI0Na;Axw(zDT-N&0td#s-+ubjZ$EwdE`EtkNCs37!T@i>jyw!(Y@qtU@1#t7 zYjbmRE1xn=JDE0|%QzXufmjd^A~M2%IkxgSqLB0B>De=HV|ITIzH8vv&sArhIrGBo zBcIR^0v{jfv4K{aga=ykD<@8Dlu9e5qHQmn=L6~G4;ME!^QNg~C&d8?|L)q_y|hq~ z`VG>r{CM)@&ciOARiP-JCVlc`OJcaaX#qs>C))a&500o8-YPA{v|@MbN) zg67{S<%mzWam4=+6Y0e#Mlw1aj8hv(AH4S^?jU~sal7)s(8E<>)oZ`}N;g56w~MLh<3_S6_yF}KdY@uF86zoUX?El?iU0>B za&Q3`e{>f^*C7!7?@PKOdS&~8A&Fns4}2Y;DnKo8Ya1J|OV1BK|2zfoxQoY?0`mhC zDNA!y1d_q2?R9kzdJ!KQKu8|+_g-0FtH;-`zdiu80PjK=(9I&=*#qX*XSfS=C$hTA zpqU&j>XwNOkQ1 ziLVTVLK#D^Mj&MX>D1bGetrFd(t3V-?OwqP|0?T80ICAqgJeL{%7MUeCbh8mnBe&; zgAAPW>y{ly7mx$7piERMCG=paRJm)2;X?P|h3{72)_wdq(xPRk)ELMR@Jts2J{-!0 z)uV6qk^{CNCRkp&iUfD?@dpMefbqFy%t56NEftIvO>9PngF8}dfF6uY)ZkDrBq=o1K`&p{PX$l` zOwMr&KwX*{nlI93B=i_*ge#bWdG^RZYU5P$-4q1WT70S46; zz#d%gl>3fLpN$@}pBmy|dP#cck!w$rPSAv)LA?A~TqbdNjV9n*k9hzAT z6-`Tzgrm`@a&Q(7yb+AveF*BSsxe$v&vaS8>OgdW3<2&!y?pjuMlKlS%#4|G~I|J0x>`iLS;+0$B(iDrN($! zz3?IMALIf^0PZNlB%tmuf2NQ5mq~}vOpl@V_3$KJ-PZvHHVCHx`&j3-EZsuGE{#-fB5d$6rjEard5dMqOJvsAnRiXV{kAc z4s>#$Lg;Tm_u%W-pKKGXsN1x%(MV2NDB>$;>sHxU-3e|6C__v+m>NHZUW5gY1Wt5! z`A22_GYNhS@CY@CMGV4x8kcv(G`U&EIM@azL8 z5|2Qzkjq6Pv=upm7#t{#!9pw+QS!;w(-yBR14YyrP1*(gJHit6y-U?V!?W%+-` z=j%d)9L$|2%|SD!l?=NMK;;0~Lden4i{gO6ta?0kpW+`Ee&Zq-iMbltn1?hQ&#?m% zhY&+6mQ8XnIezTOgNi9^rZb+G&-`}Oe>VqK+7b&1el+1en3pn;fq5Lyj)hj79DfK7 z1TA#N^YXz@qW^c*e)K`wNG20dlAet;Jeq{BIA9C-0w3=Xe$z6iCnr&a8odfSFJ9rP z`fB;DJ=p)d>p+)gSw@;&Woq;8J}!N`~7v@a^Pm@ zKodW#8CEQv`%% zHp7X|cv=46Ra2LiPO<~C01qMH!4F3xk)&ZyPfz1yA_*LH!FRU(z2!?mI`lNXF|h@B zAUyNqhNTSPSYS;Goalt#N1N~39a!W*9#?<|Kax#rS)fn_1}iqxuM1ur(8mTS1ABm? z;8OsGIrHQU94Ikc=&kK-*Nm4wu+qsw1k@-iLVPQ&*)t?ST{6KzPb8ar_Fh}oQzP7#p+)sTr-PYBj*B%s2dzx;z@ut01-Slt#z-c!f r6dKghvA=uIzb`o`y7&CA|BikKEi^?}-$hG400000NkvXXu0mjfT{?8H literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/066_旺柴.7825a175.png b/frontend/dist/assets/066_旺柴.7825a175.png new file mode 100644 index 0000000000000000000000000000000000000000..796419ec12742ea2937053d356ee9ea74d8d01a9 GIT binary patch literal 5690 zcmV-A7RBj_P)C00090P)t-s0001r ziH4ga4%WoM*Kh-wCky$C4D@jbn=cZjF9*M01C$^O_fiGFR|3R}dYOD{ygCM_VJ_-( z2GdIjFMd^<>lDe*zoZ2(a_M;)YSjT zD8RtL&CSm3?d|{7GQ`8fqoSYR-{0cmy}kd_FS4?;|LKJP=zst0ga6(+|IaJ7wzmAgB($)jQ#k|p zuo?ZZ7J7Jg_p29AH3R?bdjIHp|LAo8;5+}@IRDKm;C%%D>0|!1DD<8YtE{d5y&bQw zu=b`D{JS6j<81r29RKWe|L1J;q!azEBmKA=SUm*)%`^9=A@Y|IOfdof```c9GXKji zw4!J6o*w_@djIQf|K)Z6;6X(y0Ni*2|KoK3-)H=*6{xJT|Kvvh&^zUU1+}Pb|K4E# z=vn{OL-dgj|KxuE+gShIP5hw}tEZuhij9$vjsMk6=#m`&=1~93Blor-|HB;orW5Om z3;DYuied-!dJ6vSoY#mRU_%V}feZfj(U_K#|KD}{n-K1T2Y!8e>Xi*`Oal1w;l`Iy(v2_sl?}(bq_d-oSy)%lYXHlSI%rZX{`AAc zv};L8NXV26^<@UBcm(9!#Qx-uqL_I3%w5^RTJqOP3JMCLas|xBw(Gx9epmvRXaV-> zy}zxHqM3=ipnKG*YVzG@ zLj?c;60=D}K~#9!?3K@J(_k3KCBpv#Gw3bRNG1TiATrz)>YmtDnxyTaj!aIq?^85-5>k-FyUEg#f zx9L`fQ$Y|}yFDj=Ipz44)$LlUX>U+24IIY_Qp@w;!|Q=>bqz&PjIwI3hN%{B*{o@@ zHXPl|Nv0eZ@YQ;~S}3YIcZW)T(KJ;!J7;!-rN9S#y;9LMFet0eU8*a{nYwCOuFKA7 zz^pqiR=MkEqCGe%xJK%#deiyr6Ng!AV~R2wOG?vX_{)|TvyA6 zVa#X{U-e=4HN=Z)Q2>ELS&uHz+(A<>m&yH|#URPKP<|fi>3q9=DWINH+`{lGoInxy zV*|Qw+~h2{d=lVy#m3;`q5%ddK=GD^YXLX~=!GN=-|1rc>2$i(KO12BQXg+2MH}4a zPymmB3=!QUVSP!Qc!s7zzD$v1V>ibfK+-K%t;0g+j4h(@i@uo1QY9OlDG@_4BtN^{MV2xfd>=<$DTL5jCXF^4r`6adZ*LT zG{t=kjShcBvDFeq5uVi*@Oo@$P<}?1W&RiP5sv~#Akc?F@L>8;c<;D}2Bdb!@8VPy zfCg84w*}0O)@ij$xk*YTeAcO7mM`=C+jqc+^5+nE(eoft&SuASVB^Wku)Vnwq05lB z5T55{87#nz;DOIK2!9eH&@QU?rxpmUyto(~M>)p@dLHRHe0BEV+vy)^Hk$_r*=!a) z&<*w;lI2HZ{!8+^7MOmTt$h3#aE>)DzLep=d^;NS&S;(6ap8v~9KtLdqXnKKABH+m0<4DPT`T67Xr|&?1auxV{9Z-3Gcyijry}+Qt zuWLLA98n6ye^X+9p-Dw?9OpLL3ZkN-o_dHy^wNKbbgsX2tF@@LquehaSYiB~^9g7hk=^381Qe;s0hNK_H%@H_53cx7oL0*n5UzwUMU z^7G*c#s`DFLB*gGfPr0*!Hfr7@a_?)a6csm9k4$+9yl!RxEE6aX8s$@ceLT`V>}$e zKp;T!DUi>?RXGctgYoMqfO|L3mj%`?sv-Xj<|A%*kPtxV$SxNg1T%S2u2DLX00E`} z4Nd`m3l9QU=lwXYYb@u#f3m?y{z!0!nC23bsTy=0j~L z+CdC1Sok)_ovZWpz=kCcZ(q5eOr>!g0+&bvQ_WCej0y&iNW}%?_Gem{H?DG;=8Qr zPvi9O%(B=Z=Esw#K)}+D>!ADfV*Oju4?j3j7fzBSPLvCiT@?p>y_ZD_vyA&uj1!{J z1K0%EhU;~2#C8ar+^WaT){N7ck!0ZuF`!I-5ut#|@J-1HWpY9oAOcAr5x^$UzdhT< zNsx8o?4dcFK07sAGMP-XqjDlQIatZh2@rn^&e!GS@YoDgm8P9CF-RuEAb>joV;yYc zBzgGYZlhr?d&f))(}~2F$-y%4{smdSc&y35;LvYcHYN*&r%Av^1@6|b(Y7Gw?=@&? z!hC8V2?Y#?ufc*K$tNJ5!NHkI*{H-#pg|Y~U?;eIcW9;V1=wfMK{gTSP%sIE$s8x$ zV&@xCn^JNn29iJ&HiB{&Y8PT1$8l#3Ivki*3;gDUVp*UlaME!DlS3voV^S^|1$fNO1H3plH)W<+iR1;Tt;0Cs}8O|Y30CFlSxw@g)x zCI+4p1_be@ku5M>X+9laE>i7T)RL91j2xi=gR_`E?fqC;BkY_ zh^IAE&`$&kf++7X8f%||FcDC$fc8;U9Vcea8R>w`CY;F##eU#+rZ!tpJo=?L=eVt>xqcq z1>X4LlMg;92yr24Orwc4iB{1lUZCiD>_b#g@c?nf#VXkK0IR4Kiy~5jEFKX-4XF@| z@t`qU(6M z!VA}3@%f#$aZO$JlXpP4%jDPA*0KtaLvzt!U4_l6Hml_W>Hmidp#vgy5OBawfErwf z1uKAH4UiS+KvEZpv^{-r+%EfBx}J9ISqhu6T385? z4+2|Fff2%^^ojj8ZzIPN@Q4Qw`Zum5XOej8hsSO=ZfqcYl89Z%cTjRZW*_}r4tO|3 z{mcI=Fjf#43?EC@>?EhLAV3XJVc$%Yz`)N11rudOTkwoOkMb8G9{HxgUK@eoeNkXL z5hyeG{^;f-o?pLy9pglVb2^6MIiD2(`6#fv8-YQ6H?LoV=W^8G0%qgNnct()Z0k*) z)_nH+4GiNlI>U4RJkDnYK!G*uci9OHJw*l3V9v#hwI>^noPK=i{tLAj&1bW%X0q9Q zG!Z?0kQ|C~jSZYHwx4$Z3P2B_fH(+8P=Uqp1Yl3Y<6D=TC32guR#l^zi_+wB2}3pf z4$0L_jscFqxhScJ4W73j!uVUe6BsaLFA>-}_uRMVE@>)@Bbd@;)kq`~#Y6(&sw^w1 zN(cR}1S0n@E#J{lcVi!f^J)8q4uBpo1%`@G%J=SCzjpU0pijkBk*A=^5EUb16z!!1 zubAe`&o7;B*f1Z#miALVD*zdT@px>!_@o>v&{6WZpivTpv>soMYFUy0Mo|>K zP)Qok!u~ZBxsoXCLxcK`x^cSotpmpnhDzi>XZH|?+V`?&z^0lXHZbPe&ku6>;CnQ9lw8k9J4 z64&30X0}3BefnMUdVRjmrry>a(Uf5a(v=ng;L~ebLBkjyR|h2r`%8TBkTJ>eaKW!m z7!}{HKB4(mN{2$zyj4Em=a}&Mc*3xFzzqgOfb-eqPU*U?ob|XEoZtnCG6NE)3r3a4 z?}r~<=?(@0A+NWprY0U6*FzKty4@h)F$K!_4u|WDrf7zb>^JQ$aYUd2z!47t1KLr?#wKxofoY(&J9xMWt%gtq7d0^XAmC;K$)-*H?FFDvWda!T#c$vw zOv3N^i^Q%FlBEW`0>H;1@T#fz06T#I7~mkF0?1$%RjRDYTE@X6Y7k{X0S%}CE5HIW z1Vn)l5%8O%knnl#;=Nc-xg6bx^+uTigbMH;fV)8bXgh&vp@7@X`hd2drJ$*pq{vNw zE?K%mr~w*qfg0bd7~BP{nKI^mRVc)Up+pRL+$jb5Mzqq(|J<6*Pj(SDx3COF6yQAo z_u<&Up5jUQ!1L`;f?#(hFU;&r_-UjP! z&T4y&Yf4U=7NWzD3A7u<{AbCLj;b=QM`|MX0}IaZoj>w`SM(&Ii{n882U39YAz0tr z?wQ4?Sf|&^4A?MC>T)7~?@l(MD#}M$Q`AH>d*^q$8Imr&`jL$$RN$uq!rWl9!oo)Z zD8Q&5HW@wSRh8G;30^}}U_SHWS24T8)71*Df6ti(t$7C1b&;SVy~Am)nLdQH~~UK>6c0=)nEO%Mw(&i+60 z46IN3(15Q=px}Qg!y2sXsU<-1oHcM+CfhTzH3R&Y)&6c<&zg_*XYH?kUw?=cK+K>& z?VG)7+h7!ig{wlUA{%wIgR8}O>yR~&w6sMDYK!pV$!HRux@j<;dj}cPK?B{sry{Btqo4JYG!RZC`aOJC`qdJwE*Xvoyt7aLqCJtP7B!ZqIh!_WG}$^A2JA zMeyb1gScfAC*MDLFSeo7RBmO*@=Ja7{PX>z!;~kXU#UG!zwPy2u>c8W12RfbvGe?O z^yc)_>FKcd?&U78z4GoiCtvC@zM8-9``&pPH;r{XO1}EN9(GVAs0grAQ4PmS7OHkN zy!2?h*5mMdo*V#c{Vz^yc6!$DqX0`l0wV;5K)fE_dR(%L9@{Vdi$i=1uE#MCk5qwL z0vZ@W_6a<{vQIVTV!x~(434ri>8x?{bR3_1zRv_42sEHVbyO+32T9Zte3lx$v_p^W zD}R)yal5uo&P!r^=6OE1pc=3UWH5v+Z9}L<$CyfGwy7i6HD)3)OJL&f(ScK@h_4 z7}rvN8fS~afC*?&5zJu66)4tj$i=SpQ8diyzm^Rf1pyM+fCyIT3=PGirkiruv3uyl z1^qWHm@b0=30MOgbOrt^=u}>1rdxm<_JOj8;WA4T3&;P41xdV$ss!$#r!zG0QVi&Z zT-$}=Y#N(SH;fze*frzxVZa7P=n6t9pdkI4JukwL z5v)K4Q?!?AxG9HyG%EF`?HG5$Y0r@`4s`@G2!WXHO0MjqQg5~DcYbXe65@P03`wLr zG&En5WBBDv={wNhnYz>NCUG_^M&kqd$~uJ5O2$CkGJ7%0<*7HfTMgq+ahjHihUMe{ z4WqFlL=4{m&JFvdklDpC00093P)t-s0001% z7y^|d3Z_a9mKp=EAq4VT2FQ5~oh<_OeGAMX0l;1b*fIj8HUax=2F)S>_HGH!X$Hx8 z3(!gg%YYI5dI|Jr2*+gx?nnagR|Tp%0oz{)txp8RdKA7@1ieiI)|MQ{cnr*42*-E} zwM+!&Jp#RN4z8eS@J<8t)@{dl4Davn0RaK)>+8jJ3je+y|H&x-!65#+8~?{8|GXT> zcnklwNdWE&0eX z`K}c8rxO41pa0!9{ntw7=H~OO9_y737K^~L$H8UOj+hJ=Fu=wa=f4*uO=+l~|e`{V!JYX9wF`>+-8pb-D#TIi7s z|MtxP`Pl#MsECJ$U0hrG$Se8z`v2>m|K)-Ax+MIn760*))`$`R=#~HQjQ`?zwsju+ zqZ8M22d%8B|LR(rT@nA&O!cuJq+=8R@wWBXMyzWW{qe#7=tA9k2><1Z|JPfxavJW4 z4FBto_T5VV%{%v;5|CIB_>m6(-c$9^LA!e*nUs9~=uF<48vp(9|M|%4o*4U?5Ozfi z+`v@+#xLfY7|_qoqoSbRrZv-!9Q%n3*x1Mv zDmu~4Q2t-fk!;y`^YiP-T=MDVn8AbIk9WYcIiXFnq<1R5tsjzS0!EDh02R|oL_t(| z+U%9TYZ_r3#-qteBVw~Cx)y|NdgmcJ8LW*?F3k`mWAq;oM|(q1GI+O~7>@J?MahAY z&_w9aV(8>hTr&xB4H|@oP>2Kq{qek>Ni=O5^Q%)oFQ@ks!}Gk)_xrt@`p-0Hiz*ArJMQ(=yjCCW;a_JwR&Ba^8;kLUavJQX1mQn z>7F)=8Kcc$Y1HNX`a+NaEbDZ#ECYfI>v_4}uo!H{nW-m2_X6rQIlr{Puuj_R@p?QS zH^3J*w3B5Pmhy6K)@(CAMKNX^cA^e(+6!TqZ@?n(E&6~9PQ1j#x?Hmu9MmJrQzmnx zo?i+=9jEp!zFJv(os&c%3a>^7;bfgu2TgS=$r? z2`-)da7i-FB@{8Y7V*1C4kU(#)kHm3?Hw2LZnr;@5fwg}{E&p|2-srJDdOge|I&il z^cel9H`)M#hwcJEH0=4a*g5L(}#5fU7K zGaTO|;so;D>ZxgtFK1pNgb+fo-?I$Q5I;G-t0-mp#2?@<7T+svffB$?wOVcUVK^%l zT_gm#W-#8X{MH(YAIA?T5?O#xtUtgX7QkM!`583#3Z<>;R!4=c@H_9sc@}SA|5Xr%Gc-M;EwupWca;^Kb1-; zsWCnhMn1D@_xnNjTVGXx`tw_N{|G6x)GU507F}qB<+{Z*eMkM>e8}l>Z41g3BSw^Q zM~D3%N&BTvKZY4dfjHB)ER7qjNju7 z<##Q2sDja|>8}apYXl~M{Osf5@lm1B3zUJ7`GhKvKA3p^(Ek{J=!b`t%c~Pp9$bO* zuSa{w=c{3G;lMiKG*X5d=HKhu76py4wyra-8(zKkR{;*%s{%oU159JhKuz@goyX&! zp-jCV458aK(Qhcgm_du zX}8-a6-kT}qF6T(y}AQ&sfROYNJTdtTHc+VU=)nn1K?dw0%BBZcUtc?&c0OQ(QCxD zYaEd*5RDJjK_xO6g}GbXUd6Y__URBa$L*BgUf=8<8$wMw*oP zGDtn5lG+j?YPA+=eW6Mel{QwhB`m3DSS%|Z35ox`Gkwg=?Ur9>n{9f}`TysfGj}Gt zWB}@dKBE8pDN%oL|2hG88QgI48;%}7di3JaN*t%UCFv4AU$Cxv6Z(#(4TyMsKA-8v zg|nyI?%#j&vFrEmu8(iN{keYsZT_g~xaoLB@MRh2eI~q$_#?Oy(1ZcKZNY;ttz0%W z9`gJBzQ-3%x4eDOb>lNqLDTpA_s?%X@u50qliBPu`*0MsDWNzi!Qf%lCJ+U{>Q^UF z{g2PBW~+?ZY_j_CuEIor%E5X>_^bu|c7G9Xu#T2sVATS6y%z7&mbSLM-EQ}jgJLbm ztV8v+-D(F!-Qu?pyabd$wHdGrP-pbQ!0VQ_mK%19g1y9!Y7|#mig*=h3D#U5HLywn zJRa|>vv1pOAkaavSa1-w1N-(J+u73i!j9K=%XUSW1{cIVUQdXWU?nL*}?8$4o3lI#DiGZ{P=Y{qJUFzvB$Az z5Av3POi7fy6o@)jW4W^=4tbeid=^T;z7YD4xI;P+2?m>*nws}F%Xs!v_LNcPVlO#V zlrN-_9yw1FB^ZoMUxpHl?#q4*K?ioj04z|hfaYc-(V5s=Vq@u7tv0}UkSvNiFz!YV zE)5^VFd*NCo9cx-3b|$zQ9o%<)t{y2G zI~M~fcNQUfdYCcw^XeB8sDU-}u@`A(fbU>rJJhXD_SKa-N684C=^94N2Yt+USE_y~ zm7g|kCLT-35cE+oNf2{uIeoHQ`eYwm8QH*lK}@g=WSKGZAU}5+^y{XRDQq2~9)fX_ z_%6wDoHkiPpUf@2Keuxy3_O(Fxtf2B5%L-Xm&dAyU?eYfCf1Tq zSx#kuhA?BK_Ic2U0sJ*rHZV%P8xQG{q+FV0(~!`QKr{>kuz(?uP_=^V-eVpuEg8UL z(dPMshpKPIKO`}mBqdN40H-7AI*@@r0X+}{Wj)|}iz#*h24>OAV2sMZnAR@>pG&W0 z)Zl|=o~4I76=EsDl_U<-1>jgQbC#k2)Bt9H7*Owp{U+XdEs?#5)7AiQ-RhG`?JRKa zz2pvX)IfQVHm2ueSJ&OU2bV&h8jvf{I=+9of$^=&zX;+xG=WirKxsSbCIx6{Xiyxa z1hJ#0_n4lREsJYw8*8`TQ$_&)TcHL<^jAF%wO+c-OMFgtpc(`8v?k%|{`&Pmw_C(r z1^Pgl0$y|_5KuYhP3;zgVR3C^qrq@Z9s#8V*a*}H<{!yR!~vND{VCB+KKV`(qTvPw zxd{TOcY6{lZjlG zSM=2m&;`VF=8{m9;qU^Gf0=q}*z(Haa5mfOS8v<2weeUT4B#rLWZ-Y}W*5^|8OHH# zxInUS0Wl$&jBT37cpxI4bYm6D^!i@{V1+h^x zvtTrmXiSLAG-+76w6Ptag?&-RBy$&w7Z?*SW_IKMdCxh0dkXGLo&JriWGnyQd7kHe z-shaRyu0_MPH@7ExHj>kk^IFMi(bg1UhqB@xW`ylu&TPfAT;97h2R^tFcK z3X8>d4nl#OV%_Y45`?tT#m6ixHDf5Rot_qe)as&b{p<8dPZp+UdSuokuC!hABTFlAGTqZQBgHoRd1yz&Z8$X<0{nZIai ze$wUIXUb(FNCqdwH=obViMPznO}YSFzc0;r+T(V24s^7J0{$rDEOqAyEy}dUlrqO= zL;zhj03Ay2F^`7pN%;D3g6;x=xSkYI)R+hUsDQzMKgO9x{-}Uz@<|Zt?P7A>Ak1J~S$g$%?JyerXR$7>YvT++=cRmCV z03Zn<3BcgOqNM-G|H{pqo^IP;0yLutR@?(t1iYG>ZKJM)n#7{4EWAD2_}tgMXHW!K z2hI@47)S(%$acTy-qiVA_bU6Q`ZQA)O@I&pqN;x9IJy$mWRz7FE`w*#2&f3G5J&V6!83Re+EXVze6Ldti zvZjA?j43&fU4=dkjmZpvSK+&yQ|UP>f-WKefTIwd2w;#x>92e>b@}{fpDnqhJM7IA z;GJpC7F&=6GXznlO?pIEN^oAfWoKa#pb8tT5XdAr2~2AnfYxFzdvEI6%y}Hw=3KTt zA=ZyX!r{nBQ}e6T33}{S=r6j7KHBFBiv2?^xQsW-m-|mhn&qs4FT=<&|3sdZ8Tx zivR!)g65U;Q{sGfW@2Ju=68B|ZE6PgIL=tKW52H{9n-jKi*Y^5l=*L4%(zo0NV)MU z;MG`aVL8P(e>UHWD!v{*-G7)?Vx3JOV*rHuMHtfo^^_1DQ`0&1Cpc0O{-Q?GDK2cY zNhqs}eNSCJD+YpA07RMIK`-K14`+Kk8HMNj;d+?^gkUX#$X6&f=)4e})Z-xM!Y7|B z<@Ujy{6}JpsY>?ZuXJvJ$JZauV-`WW1EIidF#jz|BgSM1s%MY(o~9f~ z0+|L1nu#|3wz3@-#$ZGPZ4{@sU8a+J61NI}w7E-Eq!sR}b?xAw0KV zRu-uL3V^uAjJ}X)%9A1}IxEeugRLS2NP;5<&RPto7qi(VQZ~Do&Nb0$x0K;3TYl|L z1RvMlWKHh^`p30hB5?Ivqy(dizFNXK{0}4kRlZNnqg{Egr4lF^$QIQ zfT8CkJ*{uC0DL;reO`PSpw$?)R-p_5dVxqn`vC%Q5=aCv6v@D-AwuslcmGzQzP^qD zM4<=rxGexIz(gE<5Z{R%iF_SZfFyvxj6t15a55BgL@;cfMdGaiG!z;X3WY$>Nr|A{ zK(t^lhLT_cHAq{smahQ05GV;KgS80+f@F{&t(+yl&D&%AGZh#Nwf1$0T5#I{FgE~^ zL0>eOTmt!iJdO~c3{Z$5kO-1NKooO~Vb@2LM})oK@Adk8ai7oY_k)1a0CidbapWIk zK_(PH1y<%OP;NSZk?KXjo0wG8SsW5hZj2-6i3ll?E6h$`@AP`x=Xl??43@bom z`k<)5Evt|3tIxe7l7JY1z=`05kRbTOP_>+UAS`BIpP?|u=%I{aPzVHp1>pDj49>9> zL)aGNSn8<5@uR_F0w;n+Q3&!gDuV(71VJK56#{syK6zjzpQx=9yfL4PsZ=Gom|8}(K zoQG5dpm9{-g9%Uv=m!!(5)>os#u~(SV*+Flf`fZuFZ|!fdahhmLIlKz}(#HAn!W0v}Egv&0BTTUO6`V6 z{AB$O5Qs`J5hMdBqz)X$jDgrg@F#$lp84fua(Urnn$p`&U?S|yuYqBO>l+{W!|j`q z1_VJMpcX_J1cczoOJ`c36%qs^Bc7I?v$!2NLidMu0K#?vkgsa#@Mvie2*ZRx3<5%O z5D7-CMC;ht7!WLgQ$rx2+e4HfS`-psRsb@<<>R?WN<(#3Ap$V~LQqKcW5fvr0)s#x z0x^o?mIxASP;@9e09-==9!DF>YAVJp1e*a6L?MNh7Yq0U0h^!&1mZJD<_eVly&BiB z1Rqc9%aI2YAxPB#2th$0LTCC!$?BG34@9ytXLug+`6fl{{Pgk0ha9CSXN%WV{6SOp_;8bs>{nZ zKC?yPObZG-pC#MAH_D~|Kle+oCF_Ms>|c7_R*E3#KqykLLF4+al6C*OO13Mo(v99i z_h6LlOUu?h6>Y5L;%HQh21(|<5sBl=HKCC~1vEd>Rsvb1)~ pwsrr3Htc-z4l7ii0hi!D|=ikWJgFck`*CYnb)<8uS>pB)>Rpm9iqg&%Bt){ zGOp~s_xSw2|Nnz?&g+~9??>;~d2muJ%?%mpxaj}@U^F(;zy6=%{|`vmf4oc0I069Z zv8Abv!GAV`hw-^2kZ}Q#jfK6Eggi$>k7DWn6@dJ>OLOv=VLzB|DTwa7H_bbJNQp9} z-ga^H~u( zB@J}(0J}D@S`+A`J8gp{v|kmzgaejrXzH#5V7D0fLmcdr0taQm4q` za4~blR%<*I3GS4GTRGse71)ghr)v^MfI~`P?-g(+8eDY*M;*>5 zb(Yc?Kx#mZXD+5qmQM0)Vgy&rn2dAC^{rJ)}qg;FhILUL0M3bdhsiN3+DpS=> z6!=}E$5f@=P!Svu%W&s41v(TynQY6#OAv>Tv-a zw0SEb@zj>N)j@ozP;@*A8*aidQeoAWsnGjYd^F;6&jZ1&(ZDW}(HmXif5uL?C^s*E7o^Ax?>Ap5&Px-UU; z?kQIw7Iu>Zx-&`mc1ue4Aff%g@0Sd^Zf*@QnR3b87Ccp-JwHC(Ci)#WRL=bw%#94S z+*|q4c5n83YLaSg{zBR7=wXV{k58Te!2a4;U&khFY&EOTXUqlNxw6VIdJAF2@Y_;` zNvi4jPdX7Dug8;*iMq|Hvtq1pR&GlTBsbhx=N7yuJ3m~?J#1nk?oWk!IoQDz!N>lt z^3{3S#G688|J3QIsf~lEf`y)59{=VVR;DD0*-|WPl|lT=(@*A|y&$D#rL@`A0v{0S z*$9KkuNLc8=G%2}J&y0jfAaa~cu6QAne4AN!T;PP4$fY65oIVw`1@+-HF;-CA4{o~ z{DR%&T}TjW1lXtTwy7`MARkaX+JD(4^+u#RW@^s#-=`c7xNh@mgf&MmG|cJgWG?>9}| zi7iVaZz_b^j5Fd<+bE)cLonhX>eymavy?lVwjn{9bzj|y?@V@Jjh`NCoqi=e;pdXV z-E#HP8#Hb&(&(40lvyHO`FORGqaCO>)k56GFoid1#*8kg#mNb7cRzfJIg=Tfnn+p` zeUy=+lq z&C18PJ|)Q@X#e);`WbSiQYIak@*1Mwm5SqRyW8qTROlBt#o1{^RP05;GK&uk{m!#H zbYf39)+;N}hqhWV6wNa249J6b;axlI2W!IUjvexmcONT}~&x+Wgtprfeba|Owy5#3Q_p@k~ zQ-se5$xJokFkHR)b5(4$S%vLT^=*xpf*r~k+OhIsAM`=y8TZu}S2;Q#j9up*Eb5nD z%euRg(@F_S?ja7;JR$1nr1IVHO1xHmxeT*(bH=58AV621H?RyD80T{BnL4jV68j~2 z@9xF^jg3joLT|;Tg~^%S&FHC(le5W)(8~K+m7$tWnlW|w74r3!4gd;me4(Ux;|8sQ z7`t|VLM!JcuO{y_cJe za$NmDL)L;;4aW8Gh8`R73!KCjO){=N(V%9-J|`$fS+Q0&Z*2PRXaQ5HqqDwIg7uqb zU5TQ)n*Dx3m!X@GaHY8bD@iAoo|pHBZwxO6tH1ZC>E>RzJNSF!3&FK4n8f{JSaL8e zkHgb(f0cSRd-k-`!$sn0Xk!kOBoC-5E0#IJZFhG0&J@Dj(%m*I(XKDabbz{_AZg_>7qjNQoxmH+TX$^hI!WC7x`Y3K8qv#Z$f{Vig2gZ-on=M z7MhBtMC zrW6aStoL$*KrA}_Bz->e{mr4lOb4TWid(_6V+OtJVkq_aI1VDx51()u z@F3Oe4Q(#f(%ERaFfO)|m2sTt;d|1wqA57(PAO!LfMXJjNG{FO+iP^FpbMr;>H27X zMJ1-Dz8rcXoOQ4XMs+Bg_gj9U#C>Xv@xuxTJI)^`P>d9om1E)4-xl8Dx)h@PNVTtN zs_YTx@*W+P_hDA(q%0*p7#Ds1m~cGyPmN^C-GM>L`!r{$Gi?nT{W1lwmF3X@f*P@X z#?>o{=~p*2IFMp*!ayOm$CtTH4Gk?thQN-(QJds`61*z41qB{@EU-jn)O~3jWO&f1`a54%XsXF-Zfu#WeSRmhI zIA)EZsMM=lUwLSYbu5-VR?Qv<<_RH_*F!A7i3WG^ouOQ+>z{;>5WN6-apd0K_wQF@ zU0!Tk?W5FRSKIc0`z8aD?`Uo)nwF{+6VPVcdWjt{h=0`qL&xpSTeI9yuw zNpz)xE2VK2?uX}m;Y5HV*8RDMg4+*?E2f^YKA%?DD3X`Hskt@bB4kBlpw*H~&afD` z3XkL3=kal1g?$3Xae%40PW-*>JAgMldYd*w8$w1qPOaop5xXQN z9306~^2ODg$b`Zf1AxSLHqsl&BE%9ZOY0pDyq z^A>cE-_ctFiKYOsS)tDlMUlp;F=d>>1eJOO*35m7a zE*tj(#38#%K^?3XTs-m}dXMe(SZ<=XU*>IlNj97*`%@d?hom%$76ixaJEg-%Kv<|U z3pPUD)T<|d3q;RXz5p)Zm0)n-2^9wm(*rhr;LyeUiyHb?$&bU<+opLKunX?0;Vi>D z{-OBhSaxV*_@`G@vGTEQQc$cH1oGH((E?6K;p8ekhRs#c0@nd?hy$D(NSp4?@cmMM zn|jxcueN8n2J#*gU%X$8BMwDGKLQ*4Q@Ql9y_t`KG9j>m zE%6E=7G`H>KDOqU+PqmQv86~mU7h}ub8uld zL~Z{JqGRDaPg*#LnOx9Zun*%>LUECk2Fi%v3vUz=LRfYQwN0CrRO>aWv)!P};UB{7sC&8%HEctWdYzZ3-g z{dXW960b=LP^FFem1!w)Olge(0YJsi?-`_gA{pq{O~yN5_@N2p;-JpGsd`0vVEPds zu5BhL5k4O4pw&v$`Y8w}n4Uz5c;rU;k%D5dW-jbv3fZ6o3WEG=a6lr}#NUcdO=kPwaKkGXG`BQwhOa(=^CZF2>y zqhX;XnhYw^1vdY+*$t~$fWD?v?DL5@Ya-nCqni3nVC$Z=-7eNxB?{ms10*P9Ngfx0 z4&djl`@$CheV>PC5uzC^xF}KOyf$5B)^VW>H*PKaoQ|(aEDIsFqmiroo1PpVGZboq_s|{LZ%{E0$k!#~ zi$wtE_gJSESa;g0t&oh);2Kq7ac%8c0uK2VkHuSxWsFe@wM>erv$I~0P|@7^KR82M z3|T}uNq-{kjYi6o{k%F5*GNWya_EaH)HG|i;XO_Naxk+w zbSF4SktZ#Dazi;Zml^pyT+?~!gX*}kGmq+b4?HVIN2U*7vgr;VdItyKdea0H@C{Ag zN^j$RS^Y#aAX*^r+VF~hIqjubv>Cpx7h?eE;h^70ss#O7LB`K8f&siN5Fce~UFNIU zIJ=>A(S%y~4QYE3&hkf>9pgO`!wqrAFzckayp_d=HT%l#CKNW zc@2!ZKpjlJ-Z#-K9*K9U(#N?G6e;&%R#A&1dE>wf)GWDw-*Z!-+<|Uh(X^2i>S}zLtnTUW$_~5lagR7DcUG%Et+-oG@A-j$dpH5eQRov=(Hr29w>#qEU#SFL6`P~?95dcO;=z}Ra zRdLd7&b+$nKXK+{Ot_ySnI8q<_cCWYpU71T9L1?8Um*>qFN8LVc61Coa{-#q^%LFU zSi+pc3@4;(uBw)es6F-&Km*_T>Crw(jE4=sf)A7NEa8R8D9I@)dwU6EPP;Y*RW$@~ zH~lZH+T=XL%pUJ=;tmip1XBTB;(Wl7c^slYERe@RXCjB}Ti2%7I0$ zh5yiPu3?$dTxg_`(;Qg5w07$+dnYG9$HH7rh!JO)Sjs=|18xB~FnY*8*ybJq^HZFuAyQB> zx~Jrd_DMHQMTfG6hCUJvOQH^8YC=~Jg&TKjOk_&>{;BdiIb!B2ck*G;b3u0DS@H-E z1Kc=TG*uP@DZk|+tCN;auxe#fGDh{q6G=!tUY$EG975|-O*8Wf5gIKa6IIcTWj!pe zNcQUt$XE`cf!tiZeXsPTldcT^Ww>{&$bJ_ufM zShM|1b2*YsLC8=(-F`K4-|OhQJV-3%OV<>rIzv|xF nNIAa!73^bsHWG98?ik3Jr-jhR9?1T;^8v;N=K7VoE`C00090P)t-s0001` zJ`A2E2$mEAsVD)SApxf%0QrOq_>2vn9|Fx~2KRUhvqA#BRs`HF0N!i~*DL_2G6CH_ z1jS$l(rX6pNdc=i0{nLf>R$--Sp>IA1MO}K*lY*iQU>%>1K4T?_GAd(eG2+)2GwN- z|HdW%!y^C5DF4kX|NsC0z#!{c0RO!n|GOOj&@TSC8Tqaib3z3CxgGws7yGXi`LY@Q zz#;$QJ^QsA|M}hjh*fVTA1E66N|K2(9pAbkV0{`%gUoQdw`{?9{3T83^r)CpcECB!a(*N?f z|L?5nk_`X%&j0nqVle^#?4;p=33WsW|L=mgcOGXu1pn-tPA35W_}1)}4w_sN|Mj`E za2jDa1^@A$|M8f3NDcq`;{V-dS~LXz+c%_R6MIe)^P3R=@st1Jd*OQs?py^>EdP`EY58ZbMLL~*iNCE%tWB=M)Hy{Q7^vM6bz5&!ndo_taEfjoax8{ppC|K*F7aYXZTCrL3Dgia2;S`1Y&1pNH`^?EXdS|tDK ziT~J6kZC#aXBPkb?v#XUr-)zw&`ABmDDiC`)6>)c=#}S!3h3qH+Nvn~p%U-!?`l{> ze_u0-VlB~~B~m;hG93e+nUau;hK7NB{?t_Yh)3&(4ENA8Wkw*2byxTI_mq;8UrRRY zc?zqch;n3Ad2eI&^z+BZ$hWz>{*O@0j~=nHu%efLe|K=}zAf>`G3%uiz_Ej@UKFII zrLB}|;hYrG!>{n(ir2kK?$JbgVnnl&KIOPAUq2W9=yJ%WIKOBx>aro3a2>$G!NIVb z(Yj&PlM=F|a@Wa(<;`*N+GMAME6!jVFc<*Vb2gxQE@Q^Hq5uE@By>_vQveGSAXhm@ z{r)cG`jEVC^nz%t*7KNp>*UI#^`OnKdF4OY#Ii@gCIA2w@x>QMkw~U8X_BO9nl58fB$>^pl4t*iL_SN>~pFELO@inN6L2GRZ6nZNgkTogT+=?F}5)>vf#9nJboPGXH6jfI3xzxYOaw(>c6tzpbhY}pOSK9YtrpjD%v^;|pF9j1s**E3^`@`g zxSY9`uG>vsAr~jLkf$mHyEFF&&u z(rEA=qC9`T^isicj#((DKVFX6a=~=EEaV%mEsMU&czjTNyjc}ZM;H(VB%(;?KYIKN zV%=kzTD9)ZC1JdW;7^R*CnMR01-|9y;X^^lpBKyy$MTS$^dWPIF~;5_STO9FmxnHb zKpkI<=~8g~nQe>&0V4vzK2fzARi5#JP|h6L^vMe^`$+z?ri@172n5SPM2zjH(}i0{ z5PA+#N*|Se3f0H?$CpG=5#ymKn6i!_c(r&z#xH~vU08Rze67A*O%>%yQKne%6$yVM zUhB_M2~772g^-A=f9_p==v(S^hbM2o#dM$HYFUSaj^`l0KB~WA8^gZOFdpGss)a&8 z3<^~82>pkN(U&Bt?}2rXVfZ;f_=>Ct4r0V0Nr(EVB4RE?G=*LZ4Ta8G{1YsW(%?bVr9<201VswxqM1VOG99sj zL@5aMGF;-IcZac)83fVxK&KObY<=Ful-fIOKZ+Gge?r=KL(IX90ZhoU=c}0_J+eDY&Szesd&VfACx1wJg_P@ zs@vFve+=Q?Biev!BV7zA7lRB3vtGM>e0~-zaQy88CyFDwfDH|yhk>adPazOHKZ;0Xq4dH42_Wcb<^4&Xm zYCtB71R)>NJ=;FD4Z|?yi~X))!*lj_1G6s4f!y7{Ai3R36WMH|`izdF8|#mNhg)yZ zfJ!18Fh-8?yzAITOO<8QG;7R2Ra=hj^or}s7kl`7DIYL3S#24%)17CDghVaCeYm~> zNi-nWNPsZI+;+SpOO;K~KVkM|SwA{=oN4;Qm5is3bAF^l4)&SDzN}hDo?{~cOoJ9Y zy0P{QEaab3146Qi@!arSQB!50s^%dAAc4~CINkB3+Vtu=ou;A(a+Lz$izd2`F(<=J z*n-Us$bdw^!tl;{MORf_w=@L-YBGLULbKyd--8eDSDAX9reL8q$#n#n(zObA?iq^& zY%5hPLh{kAbt^y(kQ#o1AVuGEV}j*Z7X_}(FekEtpBje*llPaHpgyOCa{W8QT!?hF z5OcjgIX0y2m+KY*XFvfvSgka`GQ-4kN1S58Pl!fYZon{1KdNY!Ch*OUvDn?Es=M^^ zSs0xrFKARAdftS5Ac&e}Dcs2QCK>or3-VW=1=sH1&cAy3M59XT0(mq*svtqY zrwJKG6~8{q@)rzY@`9*{EI)G5f)y5qJK|X}l*@-CA8=7oQKA%hg8CKA;8lL>@fEk> zgFDIB&!6QGpalE`rrV6+`lX@C_|$YHK!Es}JNdZ6q;nSM*-)<40)3x{LzIg(U9(g| z0LFhg9mP4;mvcN; zAmF6WasmRx>#d)qk|eF00Zo8*K$1RxF8RFp;hydAaHR4&4K%duX*|!zcIvH_`k(x~ ztY2PhBW}n*g#o{F=Kd&22oTKR`lTJXlf*Gx{l%F1yfzKSVf^9`#DRG6;I7(uDfF_6 z1}{CVtVr+=7!<}%fk9-)~2^1^^U;cpmL~T(MC9@Y{csF6Vr`szPz_I#mPk zvgPv1`ni)??*IOWOaqc?8=fLVllaAW!opalRR2v9FaF+ky$*iDvUecl_MqybKb zSY9c}@8CXFhg|@S0I;^kn&8##d(%@0EikvehRVkP3!@GJfV^V4uAi0LICTBowF0E{pFTZe*AHu4}2JGs@>7&xhgEEV{v3KmbU2R7n7!3EItGXgd%Ua;_Eh z`bTu00hCeVTMQt}dq@2+u-uJHSSJX3&2|j{lEeY7YJ$55tOe$_w{y9iBuM}$l>orD zRFJFmOaIIQLF{k$zJ0GR)ieNbXHfvqR2-RHsQ+k&HV9&WE9`%vl@|>L0QCn9V0swN z!~hQ;2mlZ)L>V zx^VXH#1#079%KOj2o`oaL}6{ktKAPAKi*K2%5p_*C>|}w)=&7WNIiuo#t>*TU{ z=6SX8#CQok766X{aPxi!;1+st3ZV3dD~dg>G|>iJP!@u%C=NjQm!nn+SZ=dJ@U64Y zRk?rwmUZtB`~mO~2|Rm+ze*-A!P6K31d=#|sHLa&L=l1S1V>CzMF4~jxN%bD0VP`WSJM>3JdMg3_aeTcQ`1mz z3Yed)3$VP)aN%!|aZZX)U@iu@lL43!0Fx0M*BOC^5WrB`vaK_^SZiSa2DyN3V$WW@ zE{K5)8bHANB@HZlYf)`z%)gE+kO7#zHVN=d0HoRwvtU(+q{1}S#i8x=PBo@yXyfO? z6B{p=li&BpngL?ITy6CndpNHtOks5=FZ==Um;oGI1%Q7?Wg{qoKrud0CVHDP?1xrJb1{b0f zQ4ycjv?|65wfJb98brrMKq`@tVG03Fgs6q1?0;{!bZ+?m`Y*Y|7XQL#ep`R+OYy)#WG+iL)vV9vTb_W1GG#3;7p>laTx z;vW+u@6W=~)uG8~wCH>^G&Hoc@_uB({q%_^FJ6z*|GjI?dHw*PqZqs3O8~n7&=dg( zDrO=)@fcrcZ0yO)M<2%~?pj5xxK_YaG#XWlyUCsihKk1Bi81>8kB?qH0c|*8UfHsq z2fzTt1kO1CAmCHrL@*EvO`54QDE{%sJI}%wMyyhW+_=9A0CjFR12~HiO4bPG6y9_( zNtu%a{3oNDCd-;Zy17On*VG2M%2t#KpQ&UqRW?ln0Ta2o* zVx+937A+3#Jj)ac0irTBIaLXT2DV`NZ2h$cdV~89WII|LPeKCdbpV7pga`pkJL}1< zd(KqVq;8*?*rrRGTB@)FLNyJ*9{x3ebv1zN*|vtGcyUMe!2TeHzysg}9Kn$XuoF2~ zqpGGDi8G@U;Zug9sb;a_K)U9z7yRiM!Y;fPFRxl!53r=8e0@I~f(<+Z5ddQAuS^zA z*kk#p?uKKraBPolC4o?yo2pa>1}alqLV`a5Yybc@!I5}*O~ci2QCm5Fgbe`zH~~lC z1eK||V#$n>y=5duVvfS$k%Xbhni@6DDr8nGu0IDL{|%dP5O?<<$(DT$x5X`M%2@zl z2pEA_!j)3BM5>x5nX8(t=yu}t!Pr5jSop%}lwn~M)F{D8rI6@P0c^$y^dHC;8t;e} zt|+)e0Dxu!c4bDuQ6`ut73{K8BaZzEjxdt2bp@YD-I$>Ue;xoDz$Qp9XU=>d0su!5 zBG|x7fII+`zA{^zq8oMscR8^b+_?xLeD^fQQIZtfnj7%^c>y#5?g-E^(6kNW)WNRJ zA_0UuRLKB>>;#WHvV-W|aX;#c2nbM`dI*IfJUHgX(ParwlYqFAd8?@ z0?%Omz*Mn_6qH1G6drKr_H_v08XW_GwVwO)0_qwl_*xnPT6{DFv=KLp1SGmFl?=<; zHo@!@V8 zy17MMKKXA309^=#5uhO`N7z2t%rX!|7${kilnT25%>H;yi~s;apaxbnH-M8MU3NPl0ug}$$OZtI zzvs>g7{DnxnS8sY!JZf3j9{dkp;JKYz!^hUf(QVDw*b&lL2U@d2moNqlJ;Qz7yY-g z0K^7JOFIkh7%~D8!2wYA*viZsM>C3j>iBVBGyud5S&1@x9zQDp{w#nrYe3iscr>8&?2_F*7!fP=cMm=u8E?@d6YKzl$`tDhp+A0&dUAZS7W z!vjf@rHFpnj%Xd?mxVJ4-6zmLJa!xqb|Tni2y`@tltUXK&0S}pg4wzz%9Wc5D=mO$e+If z1Tc_l6hJt6!Z`;H+Ngzyj$Bo71AaOwmB zoR(#&c(chL0IYx`C?Mk=!=je42v9-=w&gjLzzF&R0>QdjD=E)30C;6E1Sl^7 zfctMH|3Hu9ABVqx@pqme@@0lm0tOKocnF+fmm*;ZE&+fDxL69L8w9Y69lhkw*G~g5 zoWmCUwpvlbHwdDZEaxwQfCKO%NavjdzU)6ZoDmBUOYjQ>KyVq>&FjES-JOm*0Vk64qZUiC%{>m#Zz*fP3*w1&scgBDbU=q9g7=j0} z!PL>gMK=Rc`}Pq)5bia5?w?!H@?(!NcM?I|A)pXg5AL}%txMX>I3p1KL3I%T(_Z?0 zJ>58em_HwY?`m;d+RFen^z;FNGibW3Z5#x28i@W^FG@(jTYeDnd;Xoc2K_jJpAoPSXc9PsY9In45a$5?S1-;0 z0Pe8I^6UItf9i?aWo?-nf!6~Nh+*1NG!U>kfEok1L;$m}?{V!9M7aM?6V!)*6i6U2 zZAsHEkGnNM_5J{mle10B|9O9CG4_HNf{W0@5PD@Jsj7?s2w-q^75)SuIRG?$%s-v; zq5q#&YiEuIfg{j3k^<9~E`xv&7z0H1wEm0ZG6TTXm+YDU(qDU9gD=Nw@DOSQvj!35 zfxsA;$Q}TiEKT?IAOJ6ZfBT|eeOpPppK72Uyiw?31oJisq99-hp2nfPmQ?lvpr5XO zwEVVZ!uj_TqewNlJ>XUi03Ly1NNN-z5Ca$frD}@Y4FKGJ(DHM>*57+~$qIkQL!j^8 zYXq~Ft;o@+dbv?~Rh100uP1ozNW@t_;{QFhAOs+w2O`+Z38v+gA!$I!*V{+ouTS^k zhr{tfwC`(O_y^wO(%!}p+}l;gfGt_o2|*ildl0DJr_AiWaye?cuvmis#WV2DJr*RSEbXdZ+k?7n__ z4KBm|{{q9Zc3+!+c(_o$e(qX7F4cR3p6KdFF97BKl0SdH=hDSpE7x?S3)yV^z&Yp$ ze&d&W=h4x%;O}eU!j{!5J2L6QF&qz`=;Y7j)~sIeue5rlKbOg5(ys7fF1M!ZZ^kbo zbgk*g)zq=33!Cp>t7Uap*Gj0XYjw+l|M~@e1__&EupHxX6aWAK07*qoM6N<$f`W9f A@Bjb+ literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/070_翻白眼.ecb744e2.png b/frontend/dist/assets/070_翻白眼.ecb744e2.png new file mode 100644 index 0000000000000000000000000000000000000000..81ad9851fa075f7ea793de3ea18cfcf90d9f3631 GIT binary patch literal 5106 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 UqzrT3cmMzZ07*qoM6N<$g49m)*#H0l literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/071_666.281fb9b6.png b/frontend/dist/assets/071_666.281fb9b6.png new file mode 100644 index 0000000000000000000000000000000000000000..ff6aa92e174bf7dc929fd9796f573464c61eebb8 GIT binary patch literal 6623 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 b|A{^Ws(Gp;K0*BX00000NkvXXu0mjfDI-Bb literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/074_苦涩.4edf4f58.png b/frontend/dist/assets/074_苦涩.4edf4f58.png new file mode 100644 index 0000000000000000000000000000000000000000..7b2314d11261727f93ecd6993d10d5640c66fb62 GIT binary patch literal 5438 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 literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/075_裂开.3fb97804.png b/frontend/dist/assets/075_裂开.3fb97804.png new file mode 100644 index 0000000000000000000000000000000000000000..16d0001d24c1707dcb2bf92a9eb4096218ccd048 GIT binary patch literal 6395 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

VZ=pYXx66vxL&8Z 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 HR)PNqTU7Vi literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/079_拥抱.e529a46b.png b/frontend/dist/assets/079_拥抱.e529a46b.png new file mode 100644 index 0000000000000000000000000000000000000000..9cd2f50f64a356718a9ed52698c36078425d5cd5 GIT binary patch literal 5018 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 KMNUMnLSTZijYB;E literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/082_握手.aeb86265.png b/frontend/dist/assets/082_握手.aeb86265.png new file mode 100644 index 0000000000000000000000000000000000000000..b625691ff957bebf922cd8fc9fe94f8cca7d0b93 GIT binary patch literal 6325 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 literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/083_胜利.e9ff0663.png b/frontend/dist/assets/083_胜利.e9ff0663.png new file mode 100644 index 0000000000000000000000000000000000000000..86621275e89df8aae754b16bcc1ac4ff1ab7c559 GIT binary patch literal 6266 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 BuK)l5 literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/086_拳头.2829fdbe.png b/frontend/dist/assets/086_拳头.2829fdbe.png new file mode 100644 index 0000000000000000000000000000000000000000..4d40db2e9528702eb7b5dda6b5f27995685ac32f GIT binary patch literal 6776 zcmV-;8i(bHP)C00093P)t-s0002! zr%cOqA=`>A&v_)xcO%MkA?=$e+m1HObRo=kBIl({%yuHqcq7huBh7as<&q}Ocq7ny zBi4f`%5fgfcqGnvBiMx~*McSMnJLwPB-n~D>ZwfVtytTTINFCP<)>2DjXlkFBFuFn z%5)<9wlw^vBKxQ%%yS?7sw4cWC;YoP{H`thq#*sUF#qqi&UhpK%}o5fI{wX1{kS&$ zry|R89Q>^-%5oq4t1AEW#r?fM{j)Iru`d0nAOGl~{kAv%>8Aa(HvP3S{>n-HxjE2z zBmd%%{G}lKqaXgzQ~uq4{>o4O;D!I}uKwME%5WO}vNP3yB>vlY{@Zo_)nER|NB-Dx z{?lCk#7X_UME$@*|K^?k<(mDhC(nB)|Ldy$(pLSsKL4pA{?}&y)noq8QvT$Y|K*YX z&0_x2TK&UN{k}*3;fwy+ZT+@8|M$=T@VfoOM*hV_{i`JZ`Ply7iT=)5{kuH-x;Ov$ z)Bp0o__{d$*J}R9P5r=4{lGu};DG+rZ2#kv{?umv(O><;LEDBT|MkiL@V@`@z5nT+ z{>WJVuqyxd%>V7H{>ond%v1foJpbpK|E(qDkR<=xaQ@I~{@Q&0$W;BoN&eS^|J{23 zxhYv^vv*Ezo`|*Mukk@3a5rmjBju{=`-NxUG~A3U|F0WC1XbaCsZhO$sna%(6NLwA?Tt-@%ojpQ=Sb(oD| zW^08?;HE!sbJQqVqSJQwlrx$)I^?@Uj$ z{bs)&j3$kqZvl2+Md6WqIG+mRa5>k@xuT>nhXBTw?(GXq65M%i)92jcYlGK}IIq=|e?|NV0Ot|8 zIVp1^BCA9g0Q~ro)jfuK_Fb`X_D^L@Xl15_TqBsaS*u5o@JeHq@BU46I-D5RU4BdB zyMNp})4L^tYk8D+H29B|F~#LgWAG+-N+17)vy%o_iQt5_ph4x~p;9rC39Q9)^%h_z z2!&r6yz2x0b$b--%$RQ7X2h;uleKh8!1~RR4ksBa{EGA2&Y3l`Pe1UlO4!K{uPwNB z^vIDfzx?Uy&U6pFBetn0{}asw-@}|=vTp88J={G#afa>cHQ@43oxM23Wv8gvF&#ER zRye&pcgdu@h`}+gAF9X#d++3|SU7iO(%=wxzYi-J6B^f3!E+j>{~94j)&+l`B}Wvj z@KR!|?do7>a7AyJJlI8<&NPR~C&&s}QQiR?!0+c&0)G9Kk>l6x{$lpZ$W<|}evTQX zFoM{&ej%v!-SP3;+`7SJ-IQ9bqC7U%c5U!!IAB5eyvPtY`!eQx=A9YfUz0U*iht^& z#UZXv_C<`bE2lmC_DdNxJ0db9##L!!|9%M+G<&8#0-6h&!{erRqnztJvd@x~yxXE; zJNW1H$by{c(UToqoDQiNyVlLN*auF5QR4BQGNXhcT?7xojgSPm_(4F>`x{}G=Jn}1 zkc2Le;oe2alXY?9_S>%Y>EXOQYRZDJd5c5bGAaZ`;Wsna`oJk`cd3V=!RgFV-|leeo%s|)B6>;0oM|JoTv8T0s`G#l`w#nmDT)> zNC)yw&`MD3h>eAJo#B85X}tsUDc~;laLyW$J7odL96*-MG&_7&!zhS=1^ws6xjWjt zzZIe`%|xn{1UPU3Vccmkav!9<10T*GEsSp_!Phk;M?ZH&nrq3)69

vA-?EtQIXD2v@liY&lje8MAy*s!9gQzj;r$}}~yog>~i z`H2dcq82#w)O>3b+$t+DWjHiCn@7(vl1`VhLuu6U3`Qn{N@cLVuF6;Y5~W2NwY<1O zuGPS%&)z$DVA+{Dd@ogbnR9FQmskUqUQo8EM}$$8nDnXnviL%kMpja!(Cai#mtN;| zYcx)`PVaQ3ZGuKy_w&cO88j+m0md1IF3Oc;{RwbjlR8TBRQlXLO_E2R-BM6l*;2g(h9VJcOCZ{$j*{L>}9O~pGht`lA5efO`wpJ)XIh} z=BvOsJjTgHka{`RI6U<=4S3EJlZkO;Ci5>Kwv{TFm%M9O8+fi#3`ruo^C#9YD0imH zf&(e!g#NH_B)omAT%0VJAj`$oPz$cE|WZpAk;v- zBT21xS1}$?BNY1?iLO+`JLU}%=?n;-A(3t{j`OG#fX3rR0+a|%{}|#xehI7vN3#F# zp(~6=znhh|%!1piD4S*zM1pMd1O9qWd}Q-;C%F}QnJ>^&Ur zS1$V%KXtUV_WMj$*Zs~^dBBg^!g$E zgFi8LJ~n3B*sy(Q?0%PrjZMJL9~-fTh{q8zYsOCF{XR?}OX*pka_>^vyW{z0f}DHq zW=m{MIW@su?luTO2mL<7WWwVP;9g;|uNp>)&&bh`-BOOs{+&8B97ek8D_x^!VF@HY z#etc0F%CQ)pJR}4&fS_GJGGdaSbsIQyFv=~h#Y*8P0Z)p9b&1_$rITnBB9M8Ahr5; zr76Z&jlo#aC~H{t7{vtJuKn{`C53lW>%8-A2AbF4!mKE?6=Up?kGHM6NFY7usq{%u zpec4)A}x+cQ*$5X(ui@i;@Bl#5~&2gpqKF60l9>*V8s*Hc!}ui!0g$qi(6yoe_F?T z)NA+Ir>wZ4e0e{A%JQ4}&=Ei$!gh0ZSN@Cp_8Tj@pjg(4fxB?`s@x-8*_>D+xm{Z; zxs_PjL#|lKEM%T3DFM$g3RhMD5tW;JMU8#i&R!~Eou(JftswU##MrwN@o`ur6^*ci zdyxMkk?&6S1hYntbJU?lC{zGS%;7x%n?HVR1|RY`VpJd!B|Odbumj2lGB#j9^yE6p)(`1Fg>ofA3l3|_QAzkEX9GQCgN9NS8c1oTiG0( zrDeM`elBkH>f7lAHftRIaoOs=&Q-WAonp0{gST|A9_X6f)7g2uql?W>Cp=bPp3@oRPdulnj5)aJ-^lpbLfitK>6-Exxm&l}9 z-gsq@3q?hvBq-OJe45~!_I?fC9xF@FG9>YvUKB<7B6D2^XG2MDNVk%A2CS^BBXWur z8IBAMN9uz`k%rR<&Cab+&7B=((g~D!RPlG=5p6WXke`jo=?<+vBy#-0Ef$o357Od?ad4+CT(aJc8#LJuO6 zJG&{Plls>$W!-K3;H;*dVbPlZdj1LNNw`7B&6udU77?BCwC^gsE&hh&#~Lzlpu3KI zCjeXr7&$YeF4dpju{AFCFy}iiMn`YiHT$kT#G3uO1i;B~RkA$I;?TXV=}(}QBeY?P zRI^AxUzQwn7$@UEx|dZocenRGq~klgf0}8}t}7|YuC?28Y6G8BXI1dytrr(>;R~b| zG)b+YdF}AJl48SVhhj`rL7LUF2>3Q?qhEg8gMrrL73F7U6{PkzHuk3Z8h4EMZt#2f ztuCEhbUgcrmCLncdR?Z(dY>xQOSF{R$ka^cKk_I|vfR*8mhYUm#8Twnl%Kb~VUlM{ ze~#bO#99*fr=57KOVAO+(@L3nDYYeBof!1Ulk?{jVHHh2yVm4037?*%rZe??;0CBBx0RPj`I<;^VGpM*`jbtX9 zWC@HCX0_NxPqxWuWbLK}8}PCOTRuCvLMwz*hdF1=Q4E<;p1>$(R!i*kBwHe#q&YZ$ zBVLwh^RiE&XqSG<c(L@bCCAAY;kufTh&2)X8Gga7c zZTLFk)AiaYce=NUQv^_bAlRWbs$>&#BR-VRq2x9uU}BnC)pM2j)Nbk%U#7v3=_|h& zO`%kVlTqlWRr9~i`&RWCjUh192LC zApTuL5GU{@c_N`uBxZ_C5~pa*y47p6=*UU9YYms)gJ>pLoAR`B*2rKNyKI{sgwA!Bmdtx_%FN`0T1g&e#FFF z$rIbv&8CZ$gS*;2xi*dv8~2VFOCT}>Phg5ZK4b-a$fDriVPYAu`-|Q;7E=&b$9bjtQ@|LI*>ZEJ6?hq|V1>u)Yte`a@`_Lm=p z=KmNOKDX90g+nGMxu>i>H@w~3fc`HjSBEn3t{`^5z-?4<84MM7Bksj+#1$UOl&fQX zJZUE+LUe>8evMsvhev=On;nS<(zQwgZqP68Ics(Ij%L!fJ<@*M^rcnJ3qjo^=4T41 zU(iuCsk?RtjL!fxkO2u0pc4{M12K4_M|ij&>tQ}r$bcC0*dCB$K|z|KvqJ*39`45q zW--|zkm})ntYC?ppVcQy4llQohx@S}mW>W*OGrZ!I=@^^9`45qmSoXj1B_{OPGx}| zDVEF1&W7Z#iD8nrho?WfNe7EgrZg{O$=gGu^D9Na4>O&K%xz40Sy`OrOC|F5@YF>O zXja5Q0=zxM)RY4QD+oYl3f43NPw68FGR~KFcmb;zZcceqOT(TCu2Lj`fAwGZ|KBqoy>Z)X{rux( zlD+T#?;!O42BFm+0J8Fb|55M$yrXXz+M=P?wVHJIZ`Mg~<)+rtmw>P@JH>#}oo`q} zFSV*C{ka%)-t(ELH*}-ZP+?v_+ps09Z@&BPr=3wtK^I@1r{Y@gzROLqhOMJt^41*g@a}Nr7`HWK6xO7 z{lA$qY7)5^+E~Z#p;~J$eD3u}$7uLYgXId}!)n|N#bXa2g{`xCBQ#sxy1skB@w=t0 zmHqH8@XG4y$+<6Hk;rU*Yg=}lU!u#dhbrTqxgH3FaH%4IAbrR;F_oz(bK$NaKo00d zrUMbi3mwkZ?bcY?FWTwhN%6FqruI*whV)MZKM#liB2 z&CZbw_2gTdTy2@ZBZkYTum{0sq$^gKx&5fz@k|le*}G2&3!9om@<1R3NgXd+iD4m!Ic9hv zcoI!>nbV0*qa>Q0d!#Ob88wu{921 zXN4|NNL_P5;ss|(oy^LZ+5T?_#ruvv#7>e!^HStnc@lCEXXeFr?lzC{I2b@6^$JaO z7nk-P2R)AdwZ~;S;ZDwQf*fC&HKHCx%_(-%U=^y$ZjLRP@$!Ipwi1X%@JSg|5<{X&RUCg@3pa`hg)MXC20|m%q?g=A$qV6i27ZY?t8hdCw zi*nYK`s%78EL2GDG!fz004aihpx6X@YO0q9u)@LXLV;~uE;W@M@}a*vGA~4a!>vE= zBpczq$Lh(P^2+=(d@-wi8TMSa~00Tj6eoa3i4FoMNSjTg#3hIWBXh2LRS zq-I`BVE291lMy%fj}#kQ!Uun}g+SNBY?K5E?39N1lugZQAQSb33g$M}YfE`rSftS{ zqQ2c$6VM;qZMQ9RlVGm98tavb z7kV7c?Gy0{w#JtS#h=*953|SXE5PaT{cyS)`?fCZ?gqDEJAT46#^u2o z71@a3F4uJ5Lg^O^blqUuv}Gj2Z<&X@^)k}5US2U0DufWqt)4JDWttWnnfrp3le53% zEr(>Bn-zftzX!oZ+eo1&>R)edySP|h4D_J4%QgbcLgpUYt*#g)XnA}s3@!a=!D?}# z2apEJq?S(fZnrlTc$5d)+BobB*z5jTkn%v6Ka?;-5zBw2MrQe}iFRac4_ZzgiLjjq zV{Y4YLV|b*-$T0t3>Mw4-?<{y8LFZQO~Zyp7D3P!O}jg4pGeuy$yQ~9zKPUil2RHk z?GrT-@9rZ*%XR&>zh_~mjn!F&CruJ-G|Q+$X?I!b=&x|w8iF0uqin5TlWx-P`2tm? zyKMP#f=^?oJ#TV%P908JDK;@agWz;wqnb{0dj%SDuw<}Ebh)1u#}ZN_qcaCo5oTNC zJ3U>q=~;pdz9y0bF5T@@-c0GFZeKf_Dv{vg00ucR`iMosmdAXA&%MWV`hjhwF%t&M z${ljODjCgY92)y(UkMsK`bf)8yI&7$cGL36ycktueKfH09hy(i!Edq7SqXie76tBQ zs~ME(f8aKCZcg?Tl^hALaL8XDbe-A{eC3<*W*h)pXPcYt&2llU$93(r>ioTJXnV8~ z3o+d}M#`W=N*$YSktuCpEID&$HdyhkMmuwM2BygaY9hxu)2K!pi%9gaRhJj3{68 zj7VDDs9ItIt+!z1AL1@J%h&vbP_~&-!l7_4MJi)0XzBIk1z7I$5o7EpZ>%%W- z?URMtniaA`81s5VyX=;gi{?Fo`C%wSbKc@s-R=XGz+zyN35hq5<-!ly{jdsXwdLr> zR>U;ms`MJ?4my(L1j8FYRDHTVoh_F<^x%O#E z))WeWLUuF2KN@D!)uWnNb}Q9=-yg_HOKs;YKg0bK)}>Vocw=y9wyasjgA9a}BMs6m zHlj#<3xE77wGhzh+_GAlgb~x$EUyAqn|%tjgqxI)nPQ|nqglab^WD+vS`7(gp zQX&Z^J_uP_83MT)M0YThgrv~MJh3U1cqP^bEbsyMw(CEL`lodgkDDhCckKrMD5RcB?i`7nC1}=|00RiR-8TNiEX>7!CkI-t$oX)Tg>-;YL9NpJ^ry2>*`e3lnGd3T^ z1~nt{RYVoXEWa<)d)!ZwG&}NTPzZ>wiAr*OsXsNZGD7Wjg8$Oww^A%uzj?ZI`Sfu4 z(au@AS&Fupm{%h2zEj#4#(7G_A8uZ?51;x}5{UQ&1|f44GGkB6U|tYe4L|UWSDq5a z>#8JJIu7B`*UY#I=#6f9%xb8f9O48r!C22Q818%=++JUv?l!9sUTow;xU!44b9>R$$w~A*iTKe86n=sJO>z z&UuT@ryu#LiAA1HG~8gPJ!uk!4y~&UL03cGl_k511aQ7>(*vg`60!ZXljGN$JSxhU-)FH7p4p z5N!4L_qg+P5hs2$InR>`_>xfSrAQ{B^dc^b!1x9UiEhsEMbbSFXK;|`ombSMuBCta z18PNWhH8WoFtKu+NZP8*&0m{fq0bPz`>oyG$sHnM=~cP~yemVouX<=oE7vHTOtsW+ zs8T(Kz8~Hx(*mvGg;UDw=t+I7Z6GYXk^c7V<;qv5CxGkA7vH@6=63gVx11A3ET-Nt zvT#hFdwut|RC{Zu%TvJ-gk%FrSDKTKRIS75Ej&xxTk|npVC(VnaXg=&*Y3804s_TZ zMxa9wU*S$PZVmy{%Ta;tcGgt===$g^dr1FtM_o&xl6TbU3L9D2gFU(F@(Vx;agPY7 ziri2=UF91!4X~4;4aE8hGu-QSr2xzxZmzcL@sr*~wJZiXObvYS9Rs0l|H1!0Bi%Tw zQC=$7AAMC!i|$e;@yzBt=uWqdYyLfb{PNk;^k%ynU-VA8GrZ&GU*@@pdln16^Wp`b zP>!!WtaIQyDzmO^i&!R?4=7T8v|8kYjoVebz>bITIqRr3(KaAQj!u`lh%EKd(Y%h_ zP(s^D2V9Qfi-g0bVHi35K)ncH$Cp7yN7*jXkp%af*#yj2KN3Cp-e|$Vxo~mhRQa4$ zS<3C!H_hD-w42?{lJPBQp9v=z1#k!k;+#sZM1dZt;4NF}DE!RjSu&T|1RA6m8`@Cd zeu~*aC(IwdR0M$^#5cQRBHJx54?b_eXqV-{)#|c=DwPaqxtX2#pcWi!Lc-OHJTSM+ z18x@(w#15VdMU|$gvMp;^{q2Qosr!l721Mv@7`SgzBcL4;M<%iURF(#A4l+6>||Wm z1%2lBhtz-geK`vq^`UxQ03P^bf&jwDzjuOt|Ku<2Ux*gI1mK;m8*V(4efK}+yqf;L z3H2uiAjJRxL2{Ke}= z@;MhmuXTXydwKnSb$ECmhG8(SKBaiJtl`)*MW?D6?o6{-EAH)nQI*r*c3Vx@=mN!5 zF0i_Yl}Xt{QD~=MFJ}qVGx8px49fC?h~6@Q@KHq8#X_hOs+TGArA)-idRrxSkK7xy z@;5mrhmE^d;Y?S*6Dr3X8VK;Iw3pf`>~jRe##Q|kit5}WRulFA+o#z^LGOLI;_gpWrA!2l4@dUa&FNHG4IYz0hR zJA-2Yxjq7#6aWr_kP}-6bH?7;To7X<=RAF%OEg58OL@k-vA-_zppTb*`UcRL{%oT7}BddDrB1?ss>n0G>ItKt$MQYCP@(~QoqA$pu}Aw zbb~09CM>Sd&zLU0kA>M}lSDG7>*eNpdh}iu$RdMMz>0BjTqaywIapU3N%L{Jdhr;w0Ud zg&KcesEB+DMiCAso*t=EfikQMIji|w{}$4EfWN20@K~2Kx}CLNfIvNhd?i?~C!Y3< z5PG4)JnK2nd!d}=4?S9+7%zHBzgKK<&UvxE6IbZ+*Wy*L8SuJfDN?2RMta5|&!AyO zL(EL}%U8gn(ASELKYzz3C@v)FywSO))50-Dc_bw=e_+$qm|>RLW;$Sw3u=AeEhn{N zbn;yDEilixVwykHZ{5@yDamlh-N;FSJ@#@b+Q|xD{$JUHXW(Q*wq!^4u4P!i%FJw{B6jglqU5?jM!?*~6RNaV}MCY=t;j-H$!h2@r7Wu?^? zg%el1FB2X=LBd3dlO!#^gc7ZlYmGO(=Phr0KS{|`lvHvlrIwa5@2!HW3hIlSio;C4 z!ikN=`Q!Li{=zD&SsPN$zuin{`q+szb@ZI4%~&H=c=yc81J>wh4?~7Fo3>=;})(LfN^AA^)vR z+#XaHgj_h3TLxFmK7uNwvAn8i9+QrX6GJ`m--7W_V|E~Q<*;gWi08u+bd`%r7>+$h z5>L8J2K}*=Uj=gVsjjo0I*@*ujJ}!d9=-)Ms|(2Nk!-_5e2tY}bE~#h+S%^NcgVIw z*0DDmo0HpzZPm8k-FK+}{_@aDpR()Z`=~AI38XiR + + + + + wechatDataBackup + + + + +

+ + + + diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..eab7e5e --- /dev/null +++ b/go.mod @@ -0,0 +1,70 @@ +module wechatDataBackup + +go 1.21 + +toolchain go1.21.0 + +require ( + github.com/beevik/etree v1.3.0 + github.com/mattn/go-sqlite3 v1.14.22 + github.com/pierrec/lz4 v2.6.1+incompatible + github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 + github.com/shirou/gopsutil v2.21.11+incompatible + github.com/shirou/gopsutil/v3 v3.24.2 + github.com/spf13/viper v1.18.2 + github.com/wailsapp/wails/v2 v2.9.1 + golang.org/x/sys v0.20.0 + google.golang.org/protobuf v1.31.0 +) + +require ( + github.com/bep/debounce v1.2.1 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect + github.com/godbus/dbus/v5 v5.1.0 // indirect + github.com/google/uuid v1.4.0 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect + github.com/labstack/echo/v4 v4.10.2 // indirect + github.com/labstack/gommon v0.4.0 // indirect + github.com/leaanthony/go-ansi-parser v1.6.0 // indirect + github.com/leaanthony/gosod v1.0.3 // indirect + github.com/leaanthony/slicer v1.6.0 // indirect + github.com/leaanthony/u v1.1.0 // indirect + github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/pelletier/go-toml/v2 v2.1.0 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect + github.com/rivo/uniseg v0.4.4 // indirect + github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/samber/lo v1.38.1 // indirect + github.com/shoenig/go-m1cpu v0.1.6 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/cast v1.6.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/subosito/gotenv v1.6.0 // indirect + github.com/tklauser/go-sysconf v0.3.13 // indirect + github.com/tklauser/numcpus v0.7.0 // indirect + github.com/tkrajina/go-reflector v0.5.6 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasttemplate v1.2.2 // indirect + github.com/wailsapp/go-webview2 v1.0.10 // indirect + github.com/wailsapp/mimetype v1.4.1 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect + go.uber.org/atomic v1.9.0 // indirect + go.uber.org/multierr v1.9.0 // indirect + golang.org/x/crypto v0.23.0 // indirect + golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect + golang.org/x/net v0.25.0 // indirect + golang.org/x/text v0.15.0 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) + +// replace github.com/wailsapp/wails/v2 v2.8.0 => C:\Users\HAL\go\pkg\mod diff --git a/main.go b/main.go new file mode 100644 index 0000000..74987f2 --- /dev/null +++ b/main.go @@ -0,0 +1,79 @@ +package main + +import ( + "embed" + "fmt" + "io" + "log" + "net/http" + "os" + "strings" + + "github.com/wailsapp/wails/v2" + "github.com/wailsapp/wails/v2/pkg/options" + "github.com/wailsapp/wails/v2/pkg/options/assetserver" +) + +//go:embed all:frontend/dist +var assets embed.FS + +type FileLoader struct { + http.Handler +} + +func NewFileLoader() *FileLoader { + return &FileLoader{} +} + +func (h *FileLoader) ServeHTTP(res http.ResponseWriter, req *http.Request) { + var err error + requestedFilename := strings.TrimPrefix(req.URL.Path, "/") + // println("Requesting file:", requestedFilename) + fileData, err := os.ReadFile(requestedFilename) + if err != nil { + res.WriteHeader(http.StatusBadRequest) + res.Write([]byte(fmt.Sprintf("Could not load file %s", requestedFilename))) + } + + res.Write(fileData) +} + +func init() { + log.SetFlags(log.Ldate | log.Lmicroseconds | log.Lshortfile) +} + +func main() { + file, _ := os.OpenFile("app.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) + defer file.Close() + + multiWriter := io.MultiWriter(file, os.Stdout) + // 设置日志输出目标为文件 + log.SetOutput(multiWriter) + log.Println("====================== wechatDataBackup ======================") + // Create an instance of the app structure + app := NewApp() + + // Create application with options + err := wails.Run(&options.App{ + Title: "wechatDataBackup", + MinWidth: 800, + MinHeight: 600, + Width: 1024, + Height: 768, + AssetServer: &assetserver.Options{ + Assets: assets, + Handler: NewFileLoader(), + }, + BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1}, + OnStartup: app.startup, + OnBeforeClose: app.beforeClose, + Bind: []interface{}{ + app, + }, + Frameless: true, + }) + + if err != nil { + println("Error:", err.Error()) + } +} diff --git a/pkg/lame/.gitignore b/pkg/lame/.gitignore new file mode 100644 index 0000000..8365624 --- /dev/null +++ b/pkg/lame/.gitignore @@ -0,0 +1,23 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test diff --git a/pkg/lame/LICENSE b/pkg/lame/LICENSE new file mode 100644 index 0000000..63280d0 --- /dev/null +++ b/pkg/lame/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2019 Pavel Vorobyov + +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. diff --git a/pkg/lame/README.md b/pkg/lame/README.md new file mode 100644 index 0000000..b618755 --- /dev/null +++ b/pkg/lame/README.md @@ -0,0 +1,43 @@ +lame +==== + +Simple libmp3lame powered mp3 encoder for Go + +**Note:** this project is obsolete, consider moving to https://github.com/viert/go-lame + +Example: + +```Go +package main + +import ( + "bufio" + "lame" + "os" +) + +func main() { + f, err := os.Open("input.raw") + if err != nil { + panic(err) + } + defer f.Close() + reader := bufio.NewReader(f) + + of, err := os.Create("output.mp3") + if err != nil { + panic(err) + } + defer of.Close() + + wr := lame.NewWriter(of) + wr.Encoder.SetBitrate(112) + wr.Encoder.SetQuality(1) + + // IMPORTANT! + wr.Encoder.InitParams() + + reader.WriteTo(wr) + +} +``` diff --git a/pkg/lame/clame/VbrTag.c b/pkg/lame/clame/VbrTag.c new file mode 100644 index 0000000..5800a44 --- /dev/null +++ b/pkg/lame/clame/VbrTag.c @@ -0,0 +1,1082 @@ +/* + * Xing VBR tagging for LAME. + * + * Copyright (c) 1999 A.L. Faber + * Copyright (c) 2001 Jonathan Dee + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* $Id: VbrTag.c,v 1.106 2017/08/06 18:15:47 robert Exp $ */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "lame.h" +#include "machine.h" +#include "encoder.h" +#include "util.h" +#include "bitstream.h" +#include "VbrTag.h" +#include "lame_global_flags.h" +#include "tables.h" + +#ifdef __sun__ +/* woraround for SunOS 4.x, it has SEEK_* defined here */ +#include +#endif + + +#ifdef _DEBUG +/* #define DEBUG_VBRTAG */ +#endif + +/* + * 4 bytes for Header Tag + * 4 bytes for Header Flags + * 100 bytes for entry (NUMTOCENTRIES) + * 4 bytes for FRAME SIZE + * 4 bytes for STREAM_SIZE + * 4 bytes for VBR SCALE. a VBR quality indicator: 0=best 100=worst + * 20 bytes for LAME tag. for example, "LAME3.12 (beta 6)" + * ___________ + * 140 bytes +*/ +#define VBRHEADERSIZE (NUMTOCENTRIES+4+4+4+4+4) + +#define LAMEHEADERSIZE (VBRHEADERSIZE + 9 + 1 + 1 + 8 + 1 + 1 + 3 + 1 + 1 + 2 + 4 + 2 + 2) + +/* the size of the Xing header (MPEG1 and MPEG2) in kbps */ +#define XING_BITRATE1 128 +#define XING_BITRATE2 64 +#define XING_BITRATE25 32 + +extern const char* get_lame_tag_encoder_short_version(void); + +static const char VBRTag0[] = { "Xing" }; +static const char VBRTag1[] = { "Info" }; + + + + +/* Lookup table for fast CRC computation + * See 'CRC_update_lookup' + * Uses the polynomial x^16+x^15+x^2+1 */ + +static const unsigned int crc16_lookup[256] = { + 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, + 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, + 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, + 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, + 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, + 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, + 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, + 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, + 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, + 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, + 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, + 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, + 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, + 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, + 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, + 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, + 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, + 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, + 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, + 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, + 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, + 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, + 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, + 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, + 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, + 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, + 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, + 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, + 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, + 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, + 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, + 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 +}; + + + + + +/*********************************************************************** + * Robert Hegemann 2001-01-17 + ***********************************************************************/ + +static void +addVbr(VBR_seek_info_t * v, int bitrate) +{ + int i; + + v->nVbrNumFrames++; + v->sum += bitrate; + v->seen++; + + if (v->seen < v->want) { + return; + } + + if (v->pos < v->size) { + v->bag[v->pos] = v->sum; + v->pos++; + v->seen = 0; + } + if (v->pos == v->size) { + for (i = 1; i < v->size; i += 2) { + v->bag[i / 2] = v->bag[i]; + } + v->want *= 2; + v->pos /= 2; + } +} + +static void +Xing_seek_table(VBR_seek_info_t const* v, unsigned char *t) +{ + int i, indx; + int seek_point; + + if (v->pos <= 0) + return; + + for (i = 1; i < NUMTOCENTRIES; ++i) { + float j = i / (float) NUMTOCENTRIES, act, sum; + indx = (int) (floor(j * v->pos)); + if (indx > v->pos - 1) + indx = v->pos - 1; + act = v->bag[indx]; + sum = v->sum; + seek_point = (int) (256. * act / sum); + if (seek_point > 255) + seek_point = 255; + t[i] = seek_point; + } +} + +#ifdef DEBUG_VBR_SEEKING_TABLE +static void +print_seeking(unsigned char *t) +{ + int i; + + printf("seeking table "); + for (i = 0; i < NUMTOCENTRIES; ++i) { + printf(" %d ", t[i]); + } + printf("\n"); +} +#endif + + +/**************************************************************************** + * AddVbrFrame: Add VBR entry, used to fill the VBR the TOC entries + * Paramters: + * nStreamPos: how many bytes did we write to the bitstream so far + * (in Bytes NOT Bits) + **************************************************************************** +*/ +void +AddVbrFrame(lame_internal_flags * gfc) +{ + int kbps = bitrate_table[gfc->cfg.version][gfc->ov_enc.bitrate_index]; + assert(gfc->VBR_seek_table.bag); + addVbr(&gfc->VBR_seek_table, kbps); +} + + +/*-------------------------------------------------------------*/ +static int +ExtractI4(const unsigned char *buf) +{ + int x; + /* big endian extract */ + x = buf[0]; + x <<= 8; + x |= buf[1]; + x <<= 8; + x |= buf[2]; + x <<= 8; + x |= buf[3]; + return x; +} + +static void +CreateI4(unsigned char *buf, uint32_t nValue) +{ + /* big endian create */ + buf[0] = (nValue >> 24) & 0xff; + buf[1] = (nValue >> 16) & 0xff; + buf[2] = (nValue >> 8) & 0xff; + buf[3] = (nValue) & 0xff; +} + + + +static void +CreateI2(unsigned char *buf, int nValue) +{ + /* big endian create */ + buf[0] = (nValue >> 8) & 0xff; + buf[1] = (nValue) & 0xff; +} + +/* check for magic strings*/ +static int +IsVbrTag(const unsigned char *buf) +{ + int isTag0, isTag1; + + isTag0 = ((buf[0] == VBRTag0[0]) && (buf[1] == VBRTag0[1]) && (buf[2] == VBRTag0[2]) + && (buf[3] == VBRTag0[3])); + isTag1 = ((buf[0] == VBRTag1[0]) && (buf[1] == VBRTag1[1]) && (buf[2] == VBRTag1[2]) + && (buf[3] == VBRTag1[3])); + + return (isTag0 || isTag1); +} + +#define SHIFT_IN_BITS_VALUE(x,n,v) ( x = (x << (n)) | ( (v) & ~(-1 << (n)) ) ) + +static void +setLameTagFrameHeader(lame_internal_flags const *gfc, unsigned char *buffer) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncResult_t const *const eov = &gfc->ov_enc; + char abyte, bbyte; + + SHIFT_IN_BITS_VALUE(buffer[0], 8u, 0xffu); + + SHIFT_IN_BITS_VALUE(buffer[1], 3u, 7); + SHIFT_IN_BITS_VALUE(buffer[1], 1u, (cfg->samplerate_out < 16000) ? 0 : 1); + SHIFT_IN_BITS_VALUE(buffer[1], 1u, cfg->version); + SHIFT_IN_BITS_VALUE(buffer[1], 2u, 4 - 3); + SHIFT_IN_BITS_VALUE(buffer[1], 1u, (!cfg->error_protection) ? 1 : 0); + + SHIFT_IN_BITS_VALUE(buffer[2], 4u, eov->bitrate_index); + SHIFT_IN_BITS_VALUE(buffer[2], 2u, cfg->samplerate_index); + SHIFT_IN_BITS_VALUE(buffer[2], 1u, 0); + SHIFT_IN_BITS_VALUE(buffer[2], 1u, cfg->extension); + + SHIFT_IN_BITS_VALUE(buffer[3], 2u, cfg->mode); + SHIFT_IN_BITS_VALUE(buffer[3], 2u, eov->mode_ext); + SHIFT_IN_BITS_VALUE(buffer[3], 1u, cfg->copyright); + SHIFT_IN_BITS_VALUE(buffer[3], 1u, cfg->original); + SHIFT_IN_BITS_VALUE(buffer[3], 2u, cfg->emphasis); + + /* the default VBR header. 48 kbps layer III, no padding, no crc */ + /* but sampling freq, mode andy copyright/copy protection taken */ + /* from first valid frame */ + buffer[0] = (uint8_t) 0xff; + abyte = (buffer[1] & (unsigned char) 0xf1); + { + int bitrate; + if (1 == cfg->version) { + bitrate = XING_BITRATE1; + } + else { + if (cfg->samplerate_out < 16000) + bitrate = XING_BITRATE25; + else + bitrate = XING_BITRATE2; + } + + if (cfg->vbr == vbr_off) + bitrate = cfg->avg_bitrate; + + if (cfg->free_format) + bbyte = 0x00; + else + bbyte = 16 * BitrateIndex(bitrate, cfg->version, cfg->samplerate_out); + } + + /* Use as much of the info from the real frames in the + * Xing header: samplerate, channels, crc, etc... + */ + if (cfg->version == 1) { + /* MPEG1 */ + buffer[1] = abyte | (char) 0x0a; /* was 0x0b; */ + abyte = buffer[2] & (char) 0x0d; /* AF keep also private bit */ + buffer[2] = (char) bbyte | abyte; /* 64kbs MPEG1 frame */ + } + else { + /* MPEG2 */ + buffer[1] = abyte | (char) 0x02; /* was 0x03; */ + abyte = buffer[2] & (char) 0x0d; /* AF keep also private bit */ + buffer[2] = (char) bbyte | abyte; /* 64kbs MPEG2 frame */ + } +} + +#if 0 +static int CheckVbrTag(unsigned char *buf); + +/*-------------------------------------------------------------*/ +/* Same as GetVbrTag below, but only checks for the Xing tag. + requires buf to contain only 40 bytes */ +/*-------------------------------------------------------------*/ +int +CheckVbrTag(unsigned char *buf) +{ + int h_id, h_mode; + + /* get selected MPEG header data */ + h_id = (buf[1] >> 3) & 1; + h_mode = (buf[3] >> 6) & 3; + + /* determine offset of header */ + if (h_id) { + /* mpeg1 */ + if (h_mode != 3) + buf += (32 + 4); + else + buf += (17 + 4); + } + else { + /* mpeg2 */ + if (h_mode != 3) + buf += (17 + 4); + else + buf += (9 + 4); + } + + return IsVbrTag(buf); +} +#endif + +int +GetVbrTag(VBRTAGDATA * pTagData, const unsigned char *buf) +{ + int i, head_flags; + int h_bitrate, h_id, h_mode, h_sr_index, h_layer; + int enc_delay, enc_padding; + + /* get Vbr header data */ + pTagData->flags = 0; + + /* get selected MPEG header data */ + h_layer = (buf[1] >> 1) & 3; + if ( h_layer != 0x01 ) { + /* the following code assumes Layer-3, so give up here */ + return 0; + } + h_id = (buf[1] >> 3) & 1; + h_sr_index = (buf[2] >> 2) & 3; + h_mode = (buf[3] >> 6) & 3; + h_bitrate = ((buf[2] >> 4) & 0xf); + h_bitrate = bitrate_table[h_id][h_bitrate]; + + /* check for FFE syncword */ + if ((buf[1] >> 4) == 0xE) + pTagData->samprate = samplerate_table[2][h_sr_index]; + else + pTagData->samprate = samplerate_table[h_id][h_sr_index]; + /* if( h_id == 0 ) */ + /* pTagData->samprate >>= 1; */ + + + + /* determine offset of header */ + if (h_id) { + /* mpeg1 */ + if (h_mode != 3) + buf += (32 + 4); + else + buf += (17 + 4); + } + else { + /* mpeg2 */ + if (h_mode != 3) + buf += (17 + 4); + else + buf += (9 + 4); + } + + if (!IsVbrTag(buf)) + return 0; + + buf += 4; + + pTagData->h_id = h_id; + + head_flags = pTagData->flags = ExtractI4(buf); + buf += 4; /* get flags */ + + if (head_flags & FRAMES_FLAG) { + pTagData->frames = ExtractI4(buf); + buf += 4; + } + + if (head_flags & BYTES_FLAG) { + pTagData->bytes = ExtractI4(buf); + buf += 4; + } + + if (head_flags & TOC_FLAG) { + if (pTagData->toc != NULL) { + for (i = 0; i < NUMTOCENTRIES; i++) + pTagData->toc[i] = buf[i]; + } + buf += NUMTOCENTRIES; + } + + pTagData->vbr_scale = -1; + + if (head_flags & VBR_SCALE_FLAG) { + pTagData->vbr_scale = ExtractI4(buf); + buf += 4; + } + + pTagData->headersize = ((h_id + 1) * 72000 * h_bitrate) / pTagData->samprate; + + buf += 21; + enc_delay = buf[0] << 4; + enc_delay += buf[1] >> 4; + enc_padding = (buf[1] & 0x0F) << 8; + enc_padding += buf[2]; + /* check for reasonable values (this may be an old Xing header, */ + /* not a INFO tag) */ + if (enc_delay < 0 || enc_delay > 3000) + enc_delay = -1; + if (enc_padding < 0 || enc_padding > 3000) + enc_padding = -1; + + pTagData->enc_delay = enc_delay; + pTagData->enc_padding = enc_padding; + +#ifdef DEBUG_VBRTAG + fprintf(stderr, "\n\n********************* VBR TAG INFO *****************\n"); + fprintf(stderr, "tag :%s\n", VBRTag); + fprintf(stderr, "head_flags :%d\n", head_flags); + fprintf(stderr, "bytes :%d\n", pTagData->bytes); + fprintf(stderr, "frames :%d\n", pTagData->frames); + fprintf(stderr, "VBR Scale :%d\n", pTagData->vbr_scale); + fprintf(stderr, "enc_delay = %i \n", enc_delay); + fprintf(stderr, "enc_padding= %i \n", enc_padding); + fprintf(stderr, "toc:\n"); + if (pTagData->toc != NULL) { + for (i = 0; i < NUMTOCENTRIES; i++) { + if ((i % 10) == 0) + fprintf(stderr, "\n"); + fprintf(stderr, " %3d", (int) (pTagData->toc[i])); + } + } + fprintf(stderr, "\n***************** END OF VBR TAG INFO ***************\n"); +#endif + return 1; /* success */ +} + + +/**************************************************************************** + * InitVbrTag: Initializes the header, and write empty frame to stream + * Paramters: + * fpStream: pointer to output file stream + * nMode : Channel Mode: 0=STEREO 1=JS 2=DS 3=MONO + **************************************************************************** +*/ +int +InitVbrTag(lame_global_flags * gfp) +{ + lame_internal_flags *gfc = gfp->internal_flags; + SessionConfig_t const *const cfg = &gfc->cfg; + int kbps_header; + +#define MAXFRAMESIZE 2880 /* or 0xB40, the max freeformat 640 32kHz framesize */ + + /* + * Xing VBR pretends to be a 48kbs layer III frame. (at 44.1kHz). + * (at 48kHz they use 56kbs since 48kbs frame not big enough for + * table of contents) + * let's always embed Xing header inside a 64kbs layer III frame. + * this gives us enough room for a LAME version string too. + * size determined by sampling frequency (MPEG1) + * 32kHz: 216 bytes@48kbs 288bytes@ 64kbs + * 44.1kHz: 156 bytes 208bytes@64kbs (+1 if padding = 1) + * 48kHz: 144 bytes 192 + * + * MPEG 2 values are the same since the framesize and samplerate + * are each reduced by a factor of 2. + */ + + + if (1 == cfg->version) { + kbps_header = XING_BITRATE1; + } + else { + if (cfg->samplerate_out < 16000) + kbps_header = XING_BITRATE25; + else + kbps_header = XING_BITRATE2; + } + + if (cfg->vbr == vbr_off) + kbps_header = cfg->avg_bitrate; + + /** make sure LAME Header fits into Frame + */ + { + int total_frame_size = ((cfg->version + 1) * 72000 * kbps_header) / cfg->samplerate_out; + int header_size = (cfg->sideinfo_len + LAMEHEADERSIZE); + gfc->VBR_seek_table.TotalFrameSize = total_frame_size; + if (total_frame_size < header_size || total_frame_size > MAXFRAMESIZE) { + /* disable tag, it wont fit */ + gfc->cfg.write_lame_tag = 0; + return 0; + } + } + + gfc->VBR_seek_table.nVbrNumFrames = 0; + gfc->VBR_seek_table.nBytesWritten = 0; + gfc->VBR_seek_table.sum = 0; + + gfc->VBR_seek_table.seen = 0; + gfc->VBR_seek_table.want = 1; + gfc->VBR_seek_table.pos = 0; + + if (gfc->VBR_seek_table.bag == NULL) { + gfc->VBR_seek_table.bag = lame_calloc(int, 400); + if (gfc->VBR_seek_table.bag != NULL) { + gfc->VBR_seek_table.size = 400; + } + else { + gfc->VBR_seek_table.size = 0; + ERRORF(gfc, "Error: can't allocate VbrFrames buffer\n"); + gfc->cfg.write_lame_tag = 0; + return -1; + } + } + + /* write dummy VBR tag of all 0's into bitstream */ + { + uint8_t buffer[MAXFRAMESIZE]; + size_t i, n; + + memset(buffer, 0, sizeof(buffer)); + setLameTagFrameHeader(gfc, buffer); + n = gfc->VBR_seek_table.TotalFrameSize; + for (i = 0; i < n; ++i) { + add_dummy_byte(gfc, buffer[i], 1); + } + } + /* Success */ + return 0; +} + + + +/* fast CRC-16 computation - uses table crc16_lookup 8*/ +static uint16_t +CRC_update_lookup(uint16_t value, uint16_t crc) +{ + uint16_t tmp; + tmp = crc ^ value; + crc = (crc >> 8) ^ crc16_lookup[tmp & 0xff]; + return crc; +} + +void +UpdateMusicCRC(uint16_t * crc, unsigned char const *buffer, int size) +{ + int i; + for (i = 0; i < size; ++i) + *crc = CRC_update_lookup(buffer[i], *crc); +} + + + + + +/**************************************************************************** + * Jonathan Dee 2001/08/31 + * + * PutLameVBR: Write LAME info: mini version + info on various switches used + * Paramters: + * pbtStreamBuffer : pointer to output buffer + * id3v2size : size of id3v2 tag in bytes + * crc : computation of crc-16 of Lame Tag so far (starting at frame sync) + * + **************************************************************************** +*/ +static int +PutLameVBR(lame_global_flags const *gfp, size_t nMusicLength, uint8_t * pbtStreamBuffer, uint16_t crc) +{ + lame_internal_flags const *gfc = gfp->internal_flags; + SessionConfig_t const *const cfg = &gfc->cfg; + + int nBytesWritten = 0; + int i; + + int enc_delay = gfc->ov_enc.encoder_delay; /* encoder delay */ + int enc_padding = gfc->ov_enc.encoder_padding; /* encoder padding */ + + /*recall: cfg->vbr_q is for example set by the switch -V */ + /* gfp->quality by -q, -h, -f, etc */ + + int nQuality = (100 - 10 * gfp->VBR_q - gfp->quality); + + + /* + NOTE: + Even though the specification for the LAME VBR tag + did explicitly mention other encoders than LAME, + many SW/HW decoder seem to be able to make use of + this tag only, if the encoder version starts with LAME. + To be compatible with such decoders, ANY encoder will + be forced to write a fake LAME version string! + As a result, the encoder version info becomes worthless. + */ + const char *szVersion = get_lame_tag_encoder_short_version(); + uint8_t nVBR; + uint8_t nRevision = 0x00; + uint8_t nRevMethod; + uint8_t vbr_type_translator[] = { 1, 5, 3, 2, 4, 0, 3 }; /*numbering different in vbr_mode vs. Lame tag */ + + uint8_t nLowpass = + (((cfg->lowpassfreq / 100.0) + .5) > 255 ? 255 : (cfg->lowpassfreq / 100.0) + .5); + + uint32_t nPeakSignalAmplitude = 0; + + uint16_t nRadioReplayGain = 0; + uint16_t nAudiophileReplayGain = 0; + + uint8_t nNoiseShaping = cfg->noise_shaping; + uint8_t nStereoMode = 0; + int bNonOptimal = 0; + uint8_t nSourceFreq = 0; + uint8_t nMisc = 0; + uint16_t nMusicCRC = 0; + + /*psy model type: Gpsycho or NsPsytune */ + unsigned char bExpNPsyTune = 1; /* only NsPsytune */ + unsigned char bSafeJoint = (cfg->use_safe_joint_stereo) != 0; + + unsigned char bNoGapMore = 0; + unsigned char bNoGapPrevious = 0; + + int nNoGapCount = gfp->nogap_total; + int nNoGapCurr = gfp->nogap_current; + + + uint8_t nAthType = cfg->ATHtype; /*4 bits. */ + + uint8_t nFlags = 0; + + /* if ABR, {store bitrate <=255} else { store "-b"} */ + int nABRBitrate; + switch (cfg->vbr) { + case vbr_abr:{ + nABRBitrate = cfg->vbr_avg_bitrate_kbps; + break; + } + case vbr_off:{ + nABRBitrate = cfg->avg_bitrate; + break; + } + default:{ /*vbr modes */ + nABRBitrate = bitrate_table[cfg->version][cfg->vbr_min_bitrate_index];; + } + } + + + /*revision and vbr method */ + if (cfg->vbr < sizeof(vbr_type_translator)) + nVBR = vbr_type_translator[cfg->vbr]; + else + nVBR = 0x00; /*unknown. */ + + nRevMethod = 0x10 * nRevision + nVBR; + + + /* ReplayGain */ + if (cfg->findReplayGain) { + int RadioGain = gfc->ov_rpg.RadioGain; + if (RadioGain > 0x1FE) + RadioGain = 0x1FE; + if (RadioGain < -0x1FE) + RadioGain = -0x1FE; + + nRadioReplayGain = 0x2000; /* set name code */ + nRadioReplayGain |= 0xC00; /* set originator code to `determined automatically' */ + + if (RadioGain >= 0) + nRadioReplayGain |= RadioGain; /* set gain adjustment */ + else { + nRadioReplayGain |= 0x200; /* set the sign bit */ + nRadioReplayGain |= -RadioGain; /* set gain adjustment */ + } + } + + /* peak sample */ + if (cfg->findPeakSample) + nPeakSignalAmplitude = + abs((int) ((((FLOAT) gfc->ov_rpg.PeakSample) / 32767.0) * pow(2, 23) + .5)); + + /*nogap */ + if (nNoGapCount != -1) { + if (nNoGapCurr > 0) + bNoGapPrevious = 1; + + if (nNoGapCurr < nNoGapCount - 1) + bNoGapMore = 1; + } + + /*flags */ + + nFlags = nAthType + (bExpNPsyTune << 4) + + (bSafeJoint << 5) + + (bNoGapMore << 6) + + (bNoGapPrevious << 7); + + + if (nQuality < 0) + nQuality = 0; + + /*stereo mode field... a bit ugly. */ + + switch (cfg->mode) { + case MONO: + nStereoMode = 0; + break; + case STEREO: + nStereoMode = 1; + break; + case DUAL_CHANNEL: + nStereoMode = 2; + break; + case JOINT_STEREO: + if (cfg->force_ms) + nStereoMode = 4; + else + nStereoMode = 3; + break; + case NOT_SET: + /* FALLTHROUGH */ + default: + nStereoMode = 7; + break; + } + + /*Intensity stereo : nStereoMode = 6. IS is not implemented */ + + if (cfg->samplerate_in <= 32000) + nSourceFreq = 0x00; + else if (cfg->samplerate_in == 48000) + nSourceFreq = 0x02; + else if (cfg->samplerate_in > 48000) + nSourceFreq = 0x03; + else + nSourceFreq = 0x01; /*default is 44100Hz. */ + + + /*Check if the user overrided the default LAME behaviour with some nasty options */ + + if (cfg->short_blocks == short_block_forced || cfg->short_blocks == short_block_dispensed || ((cfg->lowpassfreq == -1) && (cfg->highpassfreq == -1)) || /* "-k" */ + (cfg->disable_reservoir && cfg->avg_bitrate < 320) || + cfg->noATH || cfg->ATHonly || (nAthType == 0) || cfg->samplerate_in <= 32000) + bNonOptimal = 1; + + nMisc = nNoiseShaping + (nStereoMode << 2) + + (bNonOptimal << 5) + + (nSourceFreq << 6); + + + nMusicCRC = gfc->nMusicCRC; + + + /*Write all this information into the stream */ + CreateI4(&pbtStreamBuffer[nBytesWritten], nQuality); + nBytesWritten += 4; + + strncpy((char *) &pbtStreamBuffer[nBytesWritten], szVersion, 9); + nBytesWritten += 9; + + pbtStreamBuffer[nBytesWritten] = nRevMethod; + nBytesWritten++; + + pbtStreamBuffer[nBytesWritten] = nLowpass; + nBytesWritten++; + + CreateI4(&pbtStreamBuffer[nBytesWritten], nPeakSignalAmplitude); + nBytesWritten += 4; + + CreateI2(&pbtStreamBuffer[nBytesWritten], nRadioReplayGain); + nBytesWritten += 2; + + CreateI2(&pbtStreamBuffer[nBytesWritten], nAudiophileReplayGain); + nBytesWritten += 2; + + pbtStreamBuffer[nBytesWritten] = nFlags; + nBytesWritten++; + + if (nABRBitrate >= 255) + pbtStreamBuffer[nBytesWritten] = 0xFF; + else + pbtStreamBuffer[nBytesWritten] = nABRBitrate; + nBytesWritten++; + + pbtStreamBuffer[nBytesWritten] = enc_delay >> 4; /* works for win32, does it for unix? */ + pbtStreamBuffer[nBytesWritten + 1] = (enc_delay << 4) + (enc_padding >> 8); + pbtStreamBuffer[nBytesWritten + 2] = enc_padding; + + nBytesWritten += 3; + + pbtStreamBuffer[nBytesWritten] = nMisc; + nBytesWritten++; + + + pbtStreamBuffer[nBytesWritten++] = 0; /*unused in rev0 */ + + CreateI2(&pbtStreamBuffer[nBytesWritten], cfg->preset); + nBytesWritten += 2; + + CreateI4(&pbtStreamBuffer[nBytesWritten], (int) nMusicLength); + nBytesWritten += 4; + + CreateI2(&pbtStreamBuffer[nBytesWritten], nMusicCRC); + nBytesWritten += 2; + + /*Calculate tag CRC.... must be done here, since it includes + *previous information*/ + + for (i = 0; i < nBytesWritten; i++) + crc = CRC_update_lookup(pbtStreamBuffer[i], crc); + + CreateI2(&pbtStreamBuffer[nBytesWritten], crc); + nBytesWritten += 2; + + return nBytesWritten; +} + +static long +skipId3v2(FILE * fpStream) +{ + size_t nbytes; + long id3v2TagSize; + unsigned char id3v2Header[10]; + + /* seek to the beginning of the stream */ + if (fseek(fpStream, 0, SEEK_SET) != 0) { + return -2; /* not seekable, abort */ + } + /* read 10 bytes in case there's an ID3 version 2 header here */ + nbytes = fread(id3v2Header, 1, sizeof(id3v2Header), fpStream); + if (nbytes != sizeof(id3v2Header)) { + return -3; /* not readable, maybe opened Write-Only */ + } + /* does the stream begin with the ID3 version 2 file identifier? */ + if (!strncmp((char *) id3v2Header, "ID3", 3)) { + /* the tag size (minus the 10-byte header) is encoded into four + * bytes where the most significant bit is clear in each byte */ + id3v2TagSize = (((id3v2Header[6] & 0x7f) << 21) + | ((id3v2Header[7] & 0x7f) << 14) + | ((id3v2Header[8] & 0x7f) << 7) + | (id3v2Header[9] & 0x7f)) + + sizeof id3v2Header; + } + else { + /* no ID3 version 2 tag in this stream */ + id3v2TagSize = 0; + } + return id3v2TagSize; +} + + + +size_t +lame_get_lametag_frame(lame_global_flags const *gfp, unsigned char *buffer, size_t size) +{ + lame_internal_flags *gfc; + SessionConfig_t const *cfg; + unsigned long stream_size; + unsigned int nStreamIndex; + uint8_t btToc[NUMTOCENTRIES]; + + if (gfp == 0) { + return 0; + } + gfc = gfp->internal_flags; + if (gfc == 0) { + return 0; + } + if (!is_lame_internal_flags_valid(gfc)) { + return 0; + } + cfg = &gfc->cfg; + if (cfg->write_lame_tag == 0) { + return 0; + } + if (gfc->VBR_seek_table.pos <= 0) { + return 0; + } + if (size < gfc->VBR_seek_table.TotalFrameSize) { + return gfc->VBR_seek_table.TotalFrameSize; + } + if (buffer == 0) { + return 0; + } + + memset(buffer, 0, gfc->VBR_seek_table.TotalFrameSize); + + /* 4 bytes frame header */ + + setLameTagFrameHeader(gfc, buffer); + + /* Clear all TOC entries */ + memset(btToc, 0, sizeof(btToc)); + + if (cfg->free_format) { + int i; + for (i = 1; i < NUMTOCENTRIES; ++i) + btToc[i] = 255 * i / 100; + } + else { + Xing_seek_table(&gfc->VBR_seek_table, btToc); + } +#ifdef DEBUG_VBR_SEEKING_TABLE + print_seeking(btToc); +#endif + + /* Start writing the tag after the zero frame */ + nStreamIndex = cfg->sideinfo_len; + /* note! Xing header specifies that Xing data goes in the + * ancillary data with NO ERROR PROTECTION. If error protecton + * in enabled, the Xing data still starts at the same offset, + * and now it is in sideinfo data block, and thus will not + * decode correctly by non-Xing tag aware players */ + if (cfg->error_protection) + nStreamIndex -= 2; + + /* Put Vbr tag */ + if (cfg->vbr == vbr_off) { + buffer[nStreamIndex++] = VBRTag1[0]; + buffer[nStreamIndex++] = VBRTag1[1]; + buffer[nStreamIndex++] = VBRTag1[2]; + buffer[nStreamIndex++] = VBRTag1[3]; + + } + else { + buffer[nStreamIndex++] = VBRTag0[0]; + buffer[nStreamIndex++] = VBRTag0[1]; + buffer[nStreamIndex++] = VBRTag0[2]; + buffer[nStreamIndex++] = VBRTag0[3]; + } + + /* Put header flags */ + CreateI4(&buffer[nStreamIndex], FRAMES_FLAG + BYTES_FLAG + TOC_FLAG + VBR_SCALE_FLAG); + nStreamIndex += 4; + + /* Put Total Number of frames */ + CreateI4(&buffer[nStreamIndex], gfc->VBR_seek_table.nVbrNumFrames); + nStreamIndex += 4; + + /* Put total audio stream size, including Xing/LAME Header */ + stream_size = gfc->VBR_seek_table.nBytesWritten + gfc->VBR_seek_table.TotalFrameSize; + CreateI4(&buffer[nStreamIndex], stream_size); + nStreamIndex += 4; + + /* Put TOC */ + memcpy(&buffer[nStreamIndex], btToc, sizeof(btToc)); + nStreamIndex += sizeof(btToc); + + + if (cfg->error_protection) { + /* (jo) error_protection: add crc16 information to header */ + CRC_writeheader(gfc, (char *) buffer); + } + { + /*work out CRC so far: initially crc = 0 */ + uint16_t crc = 0x00; + unsigned int i; + for (i = 0; i < nStreamIndex; i++) + crc = CRC_update_lookup(buffer[i], crc); + /*Put LAME VBR info */ + nStreamIndex += PutLameVBR(gfp, stream_size, buffer + nStreamIndex, crc); + } + +#ifdef DEBUG_VBRTAG + { + VBRTAGDATA TestHeader; + GetVbrTag(&TestHeader, buffer); + } +#endif + + return gfc->VBR_seek_table.TotalFrameSize; +} + +/*********************************************************************** + * + * PutVbrTag: Write final VBR tag to the file + * Paramters: + * lpszFileName: filename of MP3 bit stream + * nVbrScale : encoder quality indicator (0..100) + **************************************************************************** + */ + +int +PutVbrTag(lame_global_flags const *gfp, FILE * fpStream) +{ + lame_internal_flags *gfc = gfp->internal_flags; + + long lFileSize; + long id3v2TagSize; + size_t nbytes; + uint8_t buffer[MAXFRAMESIZE]; + + if (gfc->VBR_seek_table.pos <= 0) + return -1; + + /* Seek to end of file */ + fseek(fpStream, 0, SEEK_END); + + /* Get file size */ + lFileSize = ftell(fpStream); + + /* Abort if file has zero length. Yes, it can happen :) */ + if (lFileSize == 0) + return -1; + + /* + * The VBR tag may NOT be located at the beginning of the stream. + * If an ID3 version 2 tag was added, then it must be skipped to write + * the VBR tag data. + */ + + id3v2TagSize = skipId3v2(fpStream); + + if (id3v2TagSize < 0) { + return id3v2TagSize; + } + + /*Seek to the beginning of the stream */ + fseek(fpStream, id3v2TagSize, SEEK_SET); + + nbytes = lame_get_lametag_frame(gfp, buffer, sizeof(buffer)); + if (nbytes > sizeof(buffer)) { + return -1; + } + + if (nbytes < 1) { + return 0; + } + + /* Put it all to disk again */ + if (fwrite(buffer, nbytes, 1, fpStream) != 1) { + return -1; + } + + return 0; /* success */ +} diff --git a/pkg/lame/clame/VbrTag.h b/pkg/lame/clame/VbrTag.h new file mode 100644 index 0000000..406af36 --- /dev/null +++ b/pkg/lame/clame/VbrTag.h @@ -0,0 +1,79 @@ +/* + * Xing VBR tagging for LAME. + * + * Copyright (c) 1999 A.L. Faber + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef LAME_VRBTAG_H +#define LAME_VRBTAG_H + + +/* ----------------------------------------------------------- + * A Vbr header may be present in the ancillary + * data field of the first frame of an mp3 bitstream + * The Vbr header (optionally) contains + * frames total number of audio frames in the bitstream + * bytes total number of bytes in the bitstream + * toc table of contents + + * toc (table of contents) gives seek points + * for random access + * the ith entry determines the seek point for + * i-percent duration + * seek point in bytes = (toc[i]/256.0) * total_bitstream_bytes + * e.g. half duration seek point = (toc[50]/256.0) * total_bitstream_bytes + */ + + +#define FRAMES_FLAG 0x0001 +#define BYTES_FLAG 0x0002 +#define TOC_FLAG 0x0004 +#define VBR_SCALE_FLAG 0x0008 + +#define NUMTOCENTRIES 100 + +#ifndef lame_internal_flags_defined +#define lame_internal_flags_defined +struct lame_internal_flags; +typedef struct lame_internal_flags lame_internal_flags; +#endif + + +/*structure to receive extracted header */ +/* toc may be NULL*/ +typedef struct { + int h_id; /* from MPEG header, 0=MPEG2, 1=MPEG1 */ + int samprate; /* determined from MPEG header */ + int flags; /* from Vbr header data */ + int frames; /* total bit stream frames from Vbr header data */ + int bytes; /* total bit stream bytes from Vbr header data */ + int vbr_scale; /* encoded vbr scale from Vbr header data */ + unsigned char toc[NUMTOCENTRIES]; /* may be NULL if toc not desired */ + int headersize; /* size of VBR header, in bytes */ + int enc_delay; /* encoder delay */ + int enc_padding; /* encoder paddign added at end of stream */ +} VBRTAGDATA; + +int GetVbrTag(VBRTAGDATA * pTagData, const unsigned char *buf); + +int InitVbrTag(lame_global_flags * gfp); +int PutVbrTag(lame_global_flags const *gfp, FILE * fid); +void AddVbrFrame(lame_internal_flags * gfc); +void UpdateMusicCRC(uint16_t * crc, const unsigned char *buffer, int size); + +#endif diff --git a/pkg/lame/clame/bitstream.c b/pkg/lame/clame/bitstream.c new file mode 100644 index 0000000..aa35915 --- /dev/null +++ b/pkg/lame/clame/bitstream.c @@ -0,0 +1,1111 @@ +/* + * MP3 bitstream Output interface for LAME + * + * Copyright (c) 1999-2000 Mark Taylor + * Copyright (c) 1999-2002 Takehiro Tominaga + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * $Id: bitstream.c,v 1.99 2017/08/31 14:14:46 robert Exp $ + */ + + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "lame.h" +#include "machine.h" +#include "encoder.h" +#include "util.h" +#include "tables.h" +#include "quantize_pvt.h" +#include "lame_global_flags.h" +#include "gain_analysis.h" +#include "VbrTag.h" +#include "bitstream.h" +#include "tables.h" + + + +/* unsigned int is at least this large: */ +/* we work with ints, so when doing bit manipulation, we limit + * ourselves to MAX_LENGTH-2 just to be on the safe side */ +#define MAX_LENGTH 32 + + + +#ifdef DEBUG +static int hogege; +#endif + + + +static int +calcFrameLength(SessionConfig_t const *const cfg, int kbps, int pad) +{ + return 8 * ((cfg->version + 1) * 72000 * kbps / cfg->samplerate_out + pad); +} + + +/*********************************************************************** + * compute bitsperframe and mean_bits for a layer III frame + **********************************************************************/ +int +getframebits(const lame_internal_flags * gfc) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncResult_t const *const eov = &gfc->ov_enc; + int bit_rate; + + /* get bitrate in kbps [?] */ + if (eov->bitrate_index) + bit_rate = bitrate_table[cfg->version][eov->bitrate_index]; + else + bit_rate = cfg->avg_bitrate; + /*assert(bit_rate <= 550); */ + assert(8 <= bit_rate && bit_rate <= 640); + + /* main encoding routine toggles padding on and off */ + /* one Layer3 Slot consists of 8 bits */ + return calcFrameLength(cfg, bit_rate, eov->padding); +} + +int +get_max_frame_buffer_size_by_constraint(SessionConfig_t const * cfg, int constraint) +{ + int maxmp3buf = 0; + if (cfg->avg_bitrate > 320) { + /* in freeformat the buffer is constant */ + if (constraint == MDB_STRICT_ISO) { + maxmp3buf = calcFrameLength(cfg, cfg->avg_bitrate, 0); + } + else { + /* maximum allowed bits per granule are 7680 */ + maxmp3buf = 7680 * (cfg->version + 1); + } + } + else { + int max_kbps; + if (cfg->samplerate_out < 16000) { + max_kbps = bitrate_table[cfg->version][8]; /* default: allow 64 kbps (MPEG-2.5) */ + } + else { + max_kbps = bitrate_table[cfg->version][14]; + } + switch (constraint) + { + default: + case MDB_DEFAULT: + /* Bouvigne suggests this more lax interpretation of the ISO doc instead of using 8*960. */ + /* All mp3 decoders should have enough buffer to handle this value: size of a 320kbps 32kHz frame */ + maxmp3buf = 8 * 1440; + break; + case MDB_STRICT_ISO: + maxmp3buf = calcFrameLength(cfg, max_kbps, 0); + break; + case MDB_MAXIMUM: + maxmp3buf = 7680 * (cfg->version + 1); + break; + } + } + return maxmp3buf; +} + + +static void +putheader_bits(lame_internal_flags * gfc) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncStateVar_t *const esv = &gfc->sv_enc; + Bit_stream_struc *bs = &gfc->bs; +#ifdef DEBUG + hogege += cfg->sideinfo_len * 8; +#endif + memcpy(&bs->buf[bs->buf_byte_idx], esv->header[esv->w_ptr].buf, cfg->sideinfo_len); + bs->buf_byte_idx += cfg->sideinfo_len; + bs->totbit += cfg->sideinfo_len * 8; + esv->w_ptr = (esv->w_ptr + 1) & (MAX_HEADER_BUF - 1); +} + + + + +/*write j bits into the bit stream */ +inline static void +putbits2(lame_internal_flags * gfc, int val, int j) +{ + EncStateVar_t const *const esv = &gfc->sv_enc; + Bit_stream_struc *bs; + bs = &gfc->bs; + + assert(j < MAX_LENGTH - 2); + + while (j > 0) { + int k; + if (bs->buf_bit_idx == 0) { + bs->buf_bit_idx = 8; + bs->buf_byte_idx++; + assert(bs->buf_byte_idx < BUFFER_SIZE); + assert(esv->header[esv->w_ptr].write_timing >= bs->totbit); + if (esv->header[esv->w_ptr].write_timing == bs->totbit) { + putheader_bits(gfc); + } + bs->buf[bs->buf_byte_idx] = 0; + } + + k = Min(j, bs->buf_bit_idx); + j -= k; + + bs->buf_bit_idx -= k; + + assert(j < MAX_LENGTH); /* 32 too large on 32 bit machines */ + assert(bs->buf_bit_idx < MAX_LENGTH); + + bs->buf[bs->buf_byte_idx] |= ((val >> j) << bs->buf_bit_idx); + bs->totbit += k; + } +} + +/*write j bits into the bit stream, ignoring frame headers */ +inline static void +putbits_noheaders(lame_internal_flags * gfc, int val, int j) +{ + Bit_stream_struc *bs; + bs = &gfc->bs; + + assert(j < MAX_LENGTH - 2); + + while (j > 0) { + int k; + if (bs->buf_bit_idx == 0) { + bs->buf_bit_idx = 8; + bs->buf_byte_idx++; + assert(bs->buf_byte_idx < BUFFER_SIZE); + bs->buf[bs->buf_byte_idx] = 0; + } + + k = Min(j, bs->buf_bit_idx); + j -= k; + + bs->buf_bit_idx -= k; + + assert(j < MAX_LENGTH); /* 32 too large on 32 bit machines */ + assert(bs->buf_bit_idx < MAX_LENGTH); + + bs->buf[bs->buf_byte_idx] |= ((val >> j) << bs->buf_bit_idx); + bs->totbit += k; + } +} + + +/* + Some combinations of bitrate, Fs, and stereo make it impossible to stuff + out a frame using just main_data, due to the limited number of bits to + indicate main_data_length. In these situations, we put stuffing bits into + the ancillary data... +*/ + +inline static void +drain_into_ancillary(lame_internal_flags * gfc, int remainingBits) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncStateVar_t *const esv = &gfc->sv_enc; + int i; + assert(remainingBits >= 0); + + if (remainingBits >= 8) { + putbits2(gfc, 0x4c, 8); + remainingBits -= 8; + } + if (remainingBits >= 8) { + putbits2(gfc, 0x41, 8); + remainingBits -= 8; + } + if (remainingBits >= 8) { + putbits2(gfc, 0x4d, 8); + remainingBits -= 8; + } + if (remainingBits >= 8) { + putbits2(gfc, 0x45, 8); + remainingBits -= 8; + } + + if (remainingBits >= 32) { + const char *const version = get_lame_short_version(); + if (remainingBits >= 32) + for (i = 0; i < (int) strlen(version) && remainingBits >= 8; ++i) { + remainingBits -= 8; + putbits2(gfc, version[i], 8); + } + } + + for (; remainingBits >= 1; remainingBits -= 1) { + putbits2(gfc, esv->ancillary_flag, 1); + esv->ancillary_flag ^= !cfg->disable_reservoir; + } + + assert(remainingBits == 0); + +} + +/*write N bits into the header */ +inline static void +writeheader(lame_internal_flags * gfc, int val, int j) +{ + EncStateVar_t *const esv = &gfc->sv_enc; + int ptr = esv->header[esv->h_ptr].ptr; + + while (j > 0) { + int const k = Min(j, 8 - (ptr & 7)); + j -= k; + assert(j < MAX_LENGTH); /* >> 32 too large for 32 bit machines */ + esv->header[esv->h_ptr].buf[ptr >> 3] + |= ((val >> j)) << (8 - (ptr & 7) - k); + ptr += k; + } + esv->header[esv->h_ptr].ptr = ptr; +} + + +static int +CRC_update(int value, int crc) +{ + int i; + value <<= 8; + for (i = 0; i < 8; i++) { + value <<= 1; + crc <<= 1; + + if (((crc ^ value) & 0x10000)) + crc ^= CRC16_POLYNOMIAL; + } + return crc; +} + + +void +CRC_writeheader(lame_internal_flags const *gfc, char *header) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + int crc = 0xffff; /* (jo) init crc16 for error_protection */ + int i; + + crc = CRC_update(((unsigned char *) header)[2], crc); + crc = CRC_update(((unsigned char *) header)[3], crc); + for (i = 6; i < cfg->sideinfo_len; i++) { + crc = CRC_update(((unsigned char *) header)[i], crc); + } + + header[4] = crc >> 8; + header[5] = crc & 255; +} + +inline static void +encodeSideInfo2(lame_internal_flags * gfc, int bitsPerFrame) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncResult_t const *const eov = &gfc->ov_enc; + EncStateVar_t *const esv = &gfc->sv_enc; + III_side_info_t *l3_side; + int gr, ch; + + l3_side = &gfc->l3_side; + esv->header[esv->h_ptr].ptr = 0; + memset(esv->header[esv->h_ptr].buf, 0, cfg->sideinfo_len); + if (cfg->samplerate_out < 16000) + writeheader(gfc, 0xffe, 12); + else + writeheader(gfc, 0xfff, 12); + writeheader(gfc, (cfg->version), 1); + writeheader(gfc, 4 - 3, 2); + writeheader(gfc, (!cfg->error_protection), 1); + writeheader(gfc, (eov->bitrate_index), 4); + writeheader(gfc, (cfg->samplerate_index), 2); + writeheader(gfc, (eov->padding), 1); + writeheader(gfc, (cfg->extension), 1); + writeheader(gfc, (cfg->mode), 2); + writeheader(gfc, (eov->mode_ext), 2); + writeheader(gfc, (cfg->copyright), 1); + writeheader(gfc, (cfg->original), 1); + writeheader(gfc, (cfg->emphasis), 2); + if (cfg->error_protection) { + writeheader(gfc, 0, 16); /* dummy */ + } + + if (cfg->version == 1) { + /* MPEG1 */ + assert(l3_side->main_data_begin >= 0); + writeheader(gfc, (l3_side->main_data_begin), 9); + + if (cfg->channels_out == 2) + writeheader(gfc, l3_side->private_bits, 3); + else + writeheader(gfc, l3_side->private_bits, 5); + + for (ch = 0; ch < cfg->channels_out; ch++) { + int band; + for (band = 0; band < 4; band++) { + writeheader(gfc, l3_side->scfsi[ch][band], 1); + } + } + + for (gr = 0; gr < 2; gr++) { + for (ch = 0; ch < cfg->channels_out; ch++) { + gr_info *const gi = &l3_side->tt[gr][ch]; + writeheader(gfc, gi->part2_3_length + gi->part2_length, 12); + writeheader(gfc, gi->big_values / 2, 9); + writeheader(gfc, gi->global_gain, 8); + writeheader(gfc, gi->scalefac_compress, 4); + + if (gi->block_type != NORM_TYPE) { + writeheader(gfc, 1, 1); /* window_switching_flag */ + writeheader(gfc, gi->block_type, 2); + writeheader(gfc, gi->mixed_block_flag, 1); + + if (gi->table_select[0] == 14) + gi->table_select[0] = 16; + writeheader(gfc, gi->table_select[0], 5); + if (gi->table_select[1] == 14) + gi->table_select[1] = 16; + writeheader(gfc, gi->table_select[1], 5); + + writeheader(gfc, gi->subblock_gain[0], 3); + writeheader(gfc, gi->subblock_gain[1], 3); + writeheader(gfc, gi->subblock_gain[2], 3); + } + else { + writeheader(gfc, 0, 1); /* window_switching_flag */ + if (gi->table_select[0] == 14) + gi->table_select[0] = 16; + writeheader(gfc, gi->table_select[0], 5); + if (gi->table_select[1] == 14) + gi->table_select[1] = 16; + writeheader(gfc, gi->table_select[1], 5); + if (gi->table_select[2] == 14) + gi->table_select[2] = 16; + writeheader(gfc, gi->table_select[2], 5); + + assert(0 <= gi->region0_count && gi->region0_count < 16); + assert(0 <= gi->region1_count && gi->region1_count < 8); + writeheader(gfc, gi->region0_count, 4); + writeheader(gfc, gi->region1_count, 3); + } + writeheader(gfc, gi->preflag, 1); + writeheader(gfc, gi->scalefac_scale, 1); + writeheader(gfc, gi->count1table_select, 1); + } + } + } + else { + /* MPEG2 */ + assert(l3_side->main_data_begin >= 0); + writeheader(gfc, (l3_side->main_data_begin), 8); + writeheader(gfc, l3_side->private_bits, cfg->channels_out); + + gr = 0; + for (ch = 0; ch < cfg->channels_out; ch++) { + gr_info *const gi = &l3_side->tt[gr][ch]; + writeheader(gfc, gi->part2_3_length + gi->part2_length, 12); + writeheader(gfc, gi->big_values / 2, 9); + writeheader(gfc, gi->global_gain, 8); + writeheader(gfc, gi->scalefac_compress, 9); + + if (gi->block_type != NORM_TYPE) { + writeheader(gfc, 1, 1); /* window_switching_flag */ + writeheader(gfc, gi->block_type, 2); + writeheader(gfc, gi->mixed_block_flag, 1); + + if (gi->table_select[0] == 14) + gi->table_select[0] = 16; + writeheader(gfc, gi->table_select[0], 5); + if (gi->table_select[1] == 14) + gi->table_select[1] = 16; + writeheader(gfc, gi->table_select[1], 5); + + writeheader(gfc, gi->subblock_gain[0], 3); + writeheader(gfc, gi->subblock_gain[1], 3); + writeheader(gfc, gi->subblock_gain[2], 3); + } + else { + writeheader(gfc, 0, 1); /* window_switching_flag */ + if (gi->table_select[0] == 14) + gi->table_select[0] = 16; + writeheader(gfc, gi->table_select[0], 5); + if (gi->table_select[1] == 14) + gi->table_select[1] = 16; + writeheader(gfc, gi->table_select[1], 5); + if (gi->table_select[2] == 14) + gi->table_select[2] = 16; + writeheader(gfc, gi->table_select[2], 5); + + assert(0 <= gi->region0_count && gi->region0_count < 16); + assert(0 <= gi->region1_count && gi->region1_count < 8); + writeheader(gfc, gi->region0_count, 4); + writeheader(gfc, gi->region1_count, 3); + } + + writeheader(gfc, gi->scalefac_scale, 1); + writeheader(gfc, gi->count1table_select, 1); + } + } + + if (cfg->error_protection) { + /* (jo) error_protection: add crc16 information to header */ + CRC_writeheader(gfc, esv->header[esv->h_ptr].buf); + } + + { + int const old = esv->h_ptr; + assert(esv->header[old].ptr == cfg->sideinfo_len * 8); + + esv->h_ptr = (old + 1) & (MAX_HEADER_BUF - 1); + esv->header[esv->h_ptr].write_timing = esv->header[old].write_timing + bitsPerFrame; + + if (esv->h_ptr == esv->w_ptr) { + /* yikes! we are out of header buffer space */ + ERRORF(gfc, "Error: MAX_HEADER_BUF too small in bitstream.c \n"); + } + + } +} + + +inline static int +huffman_coder_count1(lame_internal_flags * gfc, gr_info const *gi) +{ + /* Write count1 area */ + struct huffcodetab const *const h = &ht[gi->count1table_select + 32]; + int i, bits = 0; +#ifdef DEBUG + int gegebo = gfc->bs.totbit; +#endif + + int const *ix = &gi->l3_enc[gi->big_values]; + FLOAT const *xr = &gi->xr[gi->big_values]; + assert(gi->count1table_select < 2); + + for (i = (gi->count1 - gi->big_values) / 4; i > 0; --i) { + int huffbits = 0; + int p = 0, v; + + v = ix[0]; + if (v) { + p += 8; + if (xr[0] < 0.0f) + huffbits++; + assert(v <= 1); + } + + v = ix[1]; + if (v) { + p += 4; + huffbits *= 2; + if (xr[1] < 0.0f) + huffbits++; + assert(v <= 1); + } + + v = ix[2]; + if (v) { + p += 2; + huffbits *= 2; + if (xr[2] < 0.0f) + huffbits++; + assert(v <= 1); + } + + v = ix[3]; + if (v) { + p++; + huffbits *= 2; + if (xr[3] < 0.0f) + huffbits++; + assert(v <= 1); + } + + ix += 4; + xr += 4; + putbits2(gfc, huffbits + h->table[p], h->hlen[p]); + bits += h->hlen[p]; + } +#ifdef DEBUG + DEBUGF(gfc, "count1: real: %ld counted:%d (bigv %d count1len %d)\n", + gfc->bs.totbit - gegebo, gi->count1bits, gi->big_values, gi->count1); +#endif + return bits; +} + + + +/* + Implements the pseudocode of page 98 of the IS + */ +inline static int +Huffmancode(lame_internal_flags * const gfc, const unsigned int tableindex, + int start, int end, gr_info const *gi) +{ + struct huffcodetab const *const h = &ht[tableindex]; + unsigned int const linbits = h->xlen; + int i, bits = 0; + + assert(tableindex < 32u); + if (!tableindex) + return bits; + + for (i = start; i < end; i += 2) { + int16_t cbits = 0; + uint16_t xbits = 0; + unsigned int xlen = h->xlen; + unsigned int ext = 0; + unsigned int x1 = gi->l3_enc[i]; + unsigned int x2 = gi->l3_enc[i + 1]; + + assert(gi->l3_enc[i] >= 0); + assert(gi->l3_enc[i+1] >= 0); + + if (x1 != 0u) { + if (gi->xr[i] < 0.0f) + ext++; + cbits--; + } + + if (tableindex > 15u) { + /* use ESC-words */ + if (x1 >= 15u) { + uint16_t const linbits_x1 = x1 - 15u; + assert(linbits_x1 <= h->linmax); + ext |= linbits_x1 << 1u; + xbits = linbits; + x1 = 15u; + } + + if (x2 >= 15u) { + uint16_t const linbits_x2 = x2 - 15u; + assert(linbits_x2 <= h->linmax); + ext <<= linbits; + ext |= linbits_x2; + xbits += linbits; + x2 = 15u; + } + xlen = 16; + } + + if (x2 != 0u) { + ext <<= 1; + if (gi->xr[i + 1] < 0.0f) + ext++; + cbits--; + } + + assert((x1 | x2) < 16u); + + x1 = x1 * xlen + x2; + xbits -= cbits; + cbits += h->hlen[x1]; + + assert(cbits <= MAX_LENGTH); + assert(xbits <= MAX_LENGTH); + + putbits2(gfc, h->table[x1], cbits); + putbits2(gfc, (int)ext, xbits); + bits += cbits + xbits; + } + return bits; +} + +/* + Note the discussion of huffmancodebits() on pages 28 + and 29 of the IS, as well as the definitions of the side + information on pages 26 and 27. + */ +static int +ShortHuffmancodebits(lame_internal_flags * gfc, gr_info const *gi) +{ + int bits; + int region1Start; + + region1Start = 3 * gfc->scalefac_band.s[3]; + if (region1Start > gi->big_values) + region1Start = gi->big_values; + + /* short blocks do not have a region2 */ + bits = Huffmancode(gfc, gi->table_select[0], 0, region1Start, gi); + bits += Huffmancode(gfc, gi->table_select[1], region1Start, gi->big_values, gi); + return bits; +} + +static int +LongHuffmancodebits(lame_internal_flags * gfc, gr_info const *gi) +{ + unsigned int i; + int bigvalues, bits; + int region1Start, region2Start; + + bigvalues = gi->big_values; + assert(0 <= bigvalues && bigvalues <= 576); + + assert(gi->region0_count >= -1); + assert(gi->region1_count >= -1); + i = gi->region0_count + 1; + assert((size_t) i < dimension_of(gfc->scalefac_band.l)); + region1Start = gfc->scalefac_band.l[i]; + i += gi->region1_count + 1; + assert((size_t) i < dimension_of(gfc->scalefac_band.l)); + region2Start = gfc->scalefac_band.l[i]; + + if (region1Start > bigvalues) + region1Start = bigvalues; + + if (region2Start > bigvalues) + region2Start = bigvalues; + + bits = Huffmancode(gfc, gi->table_select[0], 0, region1Start, gi); + bits += Huffmancode(gfc, gi->table_select[1], region1Start, region2Start, gi); + bits += Huffmancode(gfc, gi->table_select[2], region2Start, bigvalues, gi); + return bits; +} + +inline static int +writeMainData(lame_internal_flags * const gfc) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + III_side_info_t const *const l3_side = &gfc->l3_side; + int gr, ch, sfb, data_bits, tot_bits = 0; + + if (cfg->version == 1) { + /* MPEG 1 */ + for (gr = 0; gr < 2; gr++) { + for (ch = 0; ch < cfg->channels_out; ch++) { + gr_info const *const gi = &l3_side->tt[gr][ch]; + int const slen1 = slen1_tab[gi->scalefac_compress]; + int const slen2 = slen2_tab[gi->scalefac_compress]; + data_bits = 0; +#ifdef DEBUG + hogege = gfc->bs.totbit; +#endif + for (sfb = 0; sfb < gi->sfbdivide; sfb++) { + if (gi->scalefac[sfb] == -1) + continue; /* scfsi is used */ + putbits2(gfc, gi->scalefac[sfb], slen1); + data_bits += slen1; + } + for (; sfb < gi->sfbmax; sfb++) { + if (gi->scalefac[sfb] == -1) + continue; /* scfsi is used */ + putbits2(gfc, gi->scalefac[sfb], slen2); + data_bits += slen2; + } + assert(data_bits == gi->part2_length); + + if (gi->block_type == SHORT_TYPE) { + data_bits += ShortHuffmancodebits(gfc, gi); + } + else { + data_bits += LongHuffmancodebits(gfc, gi); + } + data_bits += huffman_coder_count1(gfc, gi); +#ifdef DEBUG + DEBUGF(gfc, "<%ld> ", gfc->bs.totbit - hogege); +#endif + /* does bitcount in quantize.c agree with actual bit count? */ + assert(data_bits == gi->part2_3_length + gi->part2_length); + tot_bits += data_bits; + } /* for ch */ + } /* for gr */ + } + else { + /* MPEG 2 */ + gr = 0; + for (ch = 0; ch < cfg->channels_out; ch++) { + gr_info const *const gi = &l3_side->tt[gr][ch]; + int i, sfb_partition, scale_bits = 0; + assert(gi->sfb_partition_table); + data_bits = 0; +#ifdef DEBUG + hogege = gfc->bs.totbit; +#endif + sfb = 0; + sfb_partition = 0; + + if (gi->block_type == SHORT_TYPE) { + for (; sfb_partition < 4; sfb_partition++) { + int const sfbs = gi->sfb_partition_table[sfb_partition] / 3; + int const slen = gi->slen[sfb_partition]; + for (i = 0; i < sfbs; i++, sfb++) { + putbits2(gfc, Max(gi->scalefac[sfb * 3 + 0], 0), slen); + putbits2(gfc, Max(gi->scalefac[sfb * 3 + 1], 0), slen); + putbits2(gfc, Max(gi->scalefac[sfb * 3 + 2], 0), slen); + scale_bits += 3 * slen; + } + } + data_bits += ShortHuffmancodebits(gfc, gi); + } + else { + for (; sfb_partition < 4; sfb_partition++) { + int const sfbs = gi->sfb_partition_table[sfb_partition]; + int const slen = gi->slen[sfb_partition]; + for (i = 0; i < sfbs; i++, sfb++) { + putbits2(gfc, Max(gi->scalefac[sfb], 0), slen); + scale_bits += slen; + } + } + data_bits += LongHuffmancodebits(gfc, gi); + } + data_bits += huffman_coder_count1(gfc, gi); +#ifdef DEBUG + DEBUGF(gfc, "<%ld> ", gfc->bs.totbit - hogege); +#endif + /* does bitcount in quantize.c agree with actual bit count? */ + assert(data_bits == gi->part2_3_length); + assert(scale_bits == gi->part2_length); + tot_bits += scale_bits + data_bits; + } /* for ch */ + } /* for gf */ + return tot_bits; +} /* main_data */ + + + +/* compute the number of bits required to flush all mp3 frames + currently in the buffer. This should be the same as the + reservoir size. Only call this routine between frames - i.e. + only after all headers and data have been added to the buffer + by format_bitstream(). + + Also compute total_bits_output = + size of mp3 buffer (including frame headers which may not + have yet been send to the mp3 buffer) + + number of bits needed to flush all mp3 frames. + + total_bytes_output is the size of the mp3 output buffer if + lame_encode_flush_nogap() was called right now. + + */ +int +compute_flushbits(const lame_internal_flags * gfc, int *total_bytes_output) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncStateVar_t const *const esv = &gfc->sv_enc; + int flushbits, remaining_headers; + int bitsPerFrame; + int last_ptr, first_ptr; + first_ptr = esv->w_ptr; /* first header to add to bitstream */ + last_ptr = esv->h_ptr - 1; /* last header to add to bitstream */ + if (last_ptr == -1) + last_ptr = MAX_HEADER_BUF - 1; + + /* add this many bits to bitstream so we can flush all headers */ + flushbits = esv->header[last_ptr].write_timing - gfc->bs.totbit; + *total_bytes_output = flushbits; + + if (flushbits >= 0) { + /* if flushbits >= 0, some headers have not yet been written */ + /* reduce flushbits by the size of the headers */ + remaining_headers = 1 + last_ptr - first_ptr; + if (last_ptr < first_ptr) + remaining_headers = 1 + last_ptr - first_ptr + MAX_HEADER_BUF; + flushbits -= remaining_headers * 8 * cfg->sideinfo_len; + } + + + /* finally, add some bits so that the last frame is complete + * these bits are not necessary to decode the last frame, but + * some decoders will ignore last frame if these bits are missing + */ + bitsPerFrame = getframebits(gfc); + flushbits += bitsPerFrame; + *total_bytes_output += bitsPerFrame; + /* round up: */ + if (*total_bytes_output % 8) + *total_bytes_output = 1 + (*total_bytes_output / 8); + else + *total_bytes_output = (*total_bytes_output / 8); + *total_bytes_output += gfc->bs.buf_byte_idx + 1; + + + if (flushbits < 0) { +#if 0 + /* if flushbits < 0, this would mean that the buffer looks like: + * (data...) last_header (data...) (extra data that should not be here...) + */ + DEBUGF(gfc, "last header write_timing = %i \n", esv->header[last_ptr].write_timing); + DEBUGF(gfc, "first header write_timing = %i \n", esv->header[first_ptr].write_timing); + DEBUGF(gfc, "bs.totbit: %i \n", gfc->bs.totbit); + DEBUGF(gfc, "first_ptr, last_ptr %i %i \n", first_ptr, last_ptr); + DEBUGF(gfc, "remaining_headers = %i \n", remaining_headers); + DEBUGF(gfc, "bitsperframe: %i \n", bitsPerFrame); + DEBUGF(gfc, "sidelen: %i \n", cfg->sideinfo_len); +#endif + ERRORF(gfc, "strange error flushing buffer ... \n"); + } + return flushbits; +} + + +void +flush_bitstream(lame_internal_flags * gfc) +{ + EncStateVar_t *const esv = &gfc->sv_enc; + III_side_info_t *l3_side; + int nbytes; + int flushbits; + int last_ptr = esv->h_ptr - 1; /* last header to add to bitstream */ + if (last_ptr == -1) + last_ptr = MAX_HEADER_BUF - 1; + l3_side = &gfc->l3_side; + + + if ((flushbits = compute_flushbits(gfc, &nbytes)) < 0) + return; + drain_into_ancillary(gfc, flushbits); + + /* check that the 100% of the last frame has been written to bitstream */ + assert(esv->header[last_ptr].write_timing + getframebits(gfc) + == gfc->bs.totbit); + + /* we have padded out all frames with ancillary data, which is the + same as filling the bitreservoir with ancillary data, so : */ + esv->ResvSize = 0; + l3_side->main_data_begin = 0; +} + + + + +void +add_dummy_byte(lame_internal_flags * gfc, unsigned char val, unsigned int n) +{ + EncStateVar_t *const esv = &gfc->sv_enc; + int i; + + while (n-- > 0u) { + putbits_noheaders(gfc, val, 8); + + for (i = 0; i < MAX_HEADER_BUF; ++i) + esv->header[i].write_timing += 8; + } +} + + +/* + format_bitstream() + + This is called after a frame of audio has been quantized and coded. + It will write the encoded audio to the bitstream. Note that + from a layer3 encoder's perspective the bit stream is primarily + a series of main_data() blocks, with header and side information + inserted at the proper locations to maintain framing. (See Figure A.7 + in the IS). + */ +int +format_bitstream(lame_internal_flags * gfc) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncStateVar_t *const esv = &gfc->sv_enc; + int bits, nbytes; + III_side_info_t *l3_side; + int bitsPerFrame; + l3_side = &gfc->l3_side; + + bitsPerFrame = getframebits(gfc); + drain_into_ancillary(gfc, l3_side->resvDrain_pre); + + encodeSideInfo2(gfc, bitsPerFrame); + bits = 8 * cfg->sideinfo_len; + bits += writeMainData(gfc); + drain_into_ancillary(gfc, l3_side->resvDrain_post); + bits += l3_side->resvDrain_post; + + l3_side->main_data_begin += (bitsPerFrame - bits) / 8; + + /* compare number of bits needed to clear all buffered mp3 frames + * with what we think the resvsize is: */ + if (compute_flushbits(gfc, &nbytes) != esv->ResvSize) { + ERRORF(gfc, "Internal buffer inconsistency. flushbits <> ResvSize"); + } + + + /* compare main_data_begin for the next frame with what we + * think the resvsize is: */ + if ((l3_side->main_data_begin * 8) != esv->ResvSize) { + ERRORF(gfc, "bit reservoir error: \n" + "l3_side->main_data_begin: %i \n" + "Resvoir size: %i \n" + "resv drain (post) %i \n" + "resv drain (pre) %i \n" + "header and sideinfo: %i \n" + "data bits: %i \n" + "total bits: %i (remainder: %i) \n" + "bitsperframe: %i \n", + 8 * l3_side->main_data_begin, + esv->ResvSize, + l3_side->resvDrain_post, + l3_side->resvDrain_pre, + 8 * cfg->sideinfo_len, + bits - l3_side->resvDrain_post - 8 * cfg->sideinfo_len, + bits, bits % 8, bitsPerFrame); + + ERRORF(gfc, "This is a fatal error. It has several possible causes:"); + ERRORF(gfc, "90%% LAME compiled with buggy version of gcc using advanced optimizations"); + ERRORF(gfc, " 9%% Your system is overclocked"); + ERRORF(gfc, " 1%% bug in LAME encoding library"); + + esv->ResvSize = l3_side->main_data_begin * 8; + }; + assert(gfc->bs.totbit % 8 == 0); + + if (gfc->bs.totbit > 1000000000) { + /* to avoid totbit overflow, (at 8h encoding at 128kbs) lets reset bit counter */ + int i; + for (i = 0; i < MAX_HEADER_BUF; ++i) + esv->header[i].write_timing -= gfc->bs.totbit; + gfc->bs.totbit = 0; + } + + + return 0; +} + + +static int +do_gain_analysis(lame_internal_flags * gfc, unsigned char* buffer, int minimum) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + RpgStateVar_t const *const rsv = &gfc->sv_rpg; + RpgResult_t *const rov = &gfc->ov_rpg; +#ifdef DECODE_ON_THE_FLY + if (cfg->decode_on_the_fly) { /* decode the frame */ + sample_t pcm_buf[2][1152]; + int mp3_in = minimum; + int samples_out = -1; + + /* re-synthesis to pcm. Repeat until we get a samples_out=0 */ + while (samples_out != 0) { + + samples_out = hip_decode1_unclipped(gfc->hip, buffer, mp3_in, pcm_buf[0], pcm_buf[1]); + /* samples_out = 0: need more data to decode + * samples_out = -1: error. Lets assume 0 pcm output + * samples_out = number of samples output */ + + /* set the lenght of the mp3 input buffer to zero, so that in the + * next iteration of the loop we will be querying mpglib about + * buffered data */ + mp3_in = 0; + + if (samples_out == -1) { + /* error decoding. Not fatal, but might screw up + * the ReplayGain tag. What should we do? Ignore for now */ + samples_out = 0; + } + if (samples_out > 0) { + /* process the PCM data */ + + /* this should not be possible, and indicates we have + * overflown the pcm_buf buffer */ + assert(samples_out <= 1152); + + if (cfg->findPeakSample) { + int i; + /* FIXME: is this correct? maybe Max(fabs(pcm),PeakSample) */ + for (i = 0; i < samples_out; i++) { + if (pcm_buf[0][i] > rov->PeakSample) + rov->PeakSample = pcm_buf[0][i]; + else if (-pcm_buf[0][i] > rov->PeakSample) + rov->PeakSample = -pcm_buf[0][i]; + } + if (cfg->channels_out > 1) + for (i = 0; i < samples_out; i++) { + if (pcm_buf[1][i] > rov->PeakSample) + rov->PeakSample = pcm_buf[1][i]; + else if (-pcm_buf[1][i] > rov->PeakSample) + rov->PeakSample = -pcm_buf[1][i]; + } + } + + if (cfg->findReplayGain) + if (AnalyzeSamples + (rsv->rgdata, pcm_buf[0], pcm_buf[1], samples_out, + cfg->channels_out) == GAIN_ANALYSIS_ERROR) + return -6; + + } /* if (samples_out>0) */ + } /* while (samples_out!=0) */ + } /* if (gfc->decode_on_the_fly) */ +#endif + return minimum; +} + +static int +do_copy_buffer(lame_internal_flags * gfc, unsigned char *buffer, int size) +{ + Bit_stream_struc *const bs = &gfc->bs; + int const minimum = bs->buf_byte_idx + 1; + if (minimum <= 0) + return 0; + if (minimum > size) + return -1; /* buffer is too small */ + memcpy(buffer, bs->buf, minimum); + bs->buf_byte_idx = -1; + bs->buf_bit_idx = 0; + return minimum; +} + +/* copy data out of the internal MP3 bit buffer into a user supplied + unsigned char buffer. + + mp3data=0 indicates data in buffer is an id3tags and VBR tags + mp3data=1 data is real mp3 frame data. + + +*/ +int +copy_buffer(lame_internal_flags * gfc, unsigned char *buffer, int size, int mp3data) +{ + int const minimum = do_copy_buffer(gfc, buffer, size); + if (minimum > 0 && mp3data) { + UpdateMusicCRC(&gfc->nMusicCRC, buffer, minimum); + + /** sum number of bytes belonging to the mp3 stream + * this info will be written into the Xing/LAME header for seeking + */ + gfc->VBR_seek_table.nBytesWritten += minimum; + + return do_gain_analysis(gfc, buffer, minimum); + } /* if (mp3data) */ + return minimum; +} + + +void +init_bit_stream_w(lame_internal_flags * gfc) +{ + EncStateVar_t *const esv = &gfc->sv_enc; + + esv->h_ptr = esv->w_ptr = 0; + esv->header[esv->h_ptr].write_timing = 0; + + gfc->bs.buf = lame_calloc(unsigned char, BUFFER_SIZE); + gfc->bs.buf_size = BUFFER_SIZE; + gfc->bs.buf_byte_idx = -1; + gfc->bs.buf_bit_idx = 0; + gfc->bs.totbit = 0; +} + +/* end of bitstream.c */ diff --git a/pkg/lame/clame/bitstream.h b/pkg/lame/clame/bitstream.h new file mode 100644 index 0000000..3ae48d0 --- /dev/null +++ b/pkg/lame/clame/bitstream.h @@ -0,0 +1,40 @@ +/* + * MP3 bitstream Output interface for LAME + * + * Copyright (c) 1999 Takehiro TOMINAGA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef LAME_BITSTREAM_H +#define LAME_BITSTREAM_H + +int getframebits(const lame_internal_flags * gfc); + +int format_bitstream(lame_internal_flags * gfc); + +void flush_bitstream(lame_internal_flags * gfc); +void add_dummy_byte(lame_internal_flags * gfc, unsigned char val, unsigned int n); + +int copy_buffer(lame_internal_flags * gfc, unsigned char *buffer, int buffer_size, + int update_crc); +void init_bit_stream_w(lame_internal_flags * gfc); +void CRC_writeheader(lame_internal_flags const *gfc, char *buffer); +int compute_flushbits(const lame_internal_flags * gfp, int *nbytes); + +int get_max_frame_buffer_size_by_constraint(SessionConfig_t const * cfg, int constraint); + +#endif diff --git a/pkg/lame/clame/config.h b/pkg/lame/clame/config.h new file mode 100644 index 0000000..4df73ee --- /dev/null +++ b/pkg/lame/clame/config.h @@ -0,0 +1,30 @@ +#ifndef LAME_CONFIG_H +#define LAME_CONFIG_H + +#define STDC_HEADERS + +/* +#define __int8_t_defined +#define uint8_t unsigned char +#define uint16_t unsigned short +#define uint32_t unsigned int +#define uint64_t unsigned long long + +#define int8_t signed char +#define int16_t signed short +#define int32_t signed int +#define int64_t signed long long +*/ +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; + +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; + +typedef long double ieee854_float80_t; +typedef double ieee754_float64_t; +typedef float ieee754_float32_t; +#endif /* LAME_CONFIG_H */ diff --git a/pkg/lame/clame/encoder.c b/pkg/lame/clame/encoder.c new file mode 100644 index 0000000..48f46c7 --- /dev/null +++ b/pkg/lame/clame/encoder.c @@ -0,0 +1,574 @@ +/* + * LAME MP3 encoding engine + * + * Copyright (c) 1999 Mark Taylor + * Copyright (c) 2000-2002 Takehiro Tominaga + * Copyright (c) 2000-2011 Robert Hegemann + * Copyright (c) 2001 Gabriel Bouvigne + * Copyright (c) 2001 John Dahlstrom + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* $Id: encoder.c,v 1.114 2017/08/26 10:54:57 robert Exp $ */ + +#ifdef HAVE_CONFIG_H +#include +#endif + + +#include "lame.h" +#include "machine.h" +#include "encoder.h" +#include "util.h" +#include "lame_global_flags.h" +#include "newmdct.h" +#include "psymodel.h" +#include "lame-analysis.h" +#include "bitstream.h" +#include "VbrTag.h" +#include "quantize.h" +#include "quantize_pvt.h" + + + +/* + * auto-adjust of ATH, useful for low volume + * Gabriel Bouvigne 3 feb 2001 + * + * modifies some values in + * gfp->internal_flags->ATH + * (gfc->ATH) + */ +static void +adjust_ATH(lame_internal_flags const *const gfc) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + FLOAT gr2_max, max_pow; + + if (gfc->ATH->use_adjust == 0) { + gfc->ATH->adjust_factor = 1.0; /* no adjustment */ + return; + } + + /* jd - 2001 mar 12, 27, jun 30 */ + /* loudness based on equal loudness curve; */ + /* use granule with maximum combined loudness */ + max_pow = gfc->ov_psy.loudness_sq[0][0]; + gr2_max = gfc->ov_psy.loudness_sq[1][0]; + if (cfg->channels_out == 2) { + max_pow += gfc->ov_psy.loudness_sq[0][1]; + gr2_max += gfc->ov_psy.loudness_sq[1][1]; + } + else { + max_pow += max_pow; + gr2_max += gr2_max; + } + if (cfg->mode_gr == 2) { + max_pow = Max(max_pow, gr2_max); + } + max_pow *= 0.5; /* max_pow approaches 1.0 for full band noise */ + + /* jd - 2001 mar 31, jun 30 */ + /* user tuning of ATH adjustment region */ + max_pow *= gfc->ATH->aa_sensitivity_p; + + /* adjust ATH depending on range of maximum value + */ + + /* jd - 2001 feb27, mar12,20, jun30, jul22 */ + /* continuous curves based on approximation */ + /* to GB's original values. */ + /* For an increase in approximate loudness, */ + /* set ATH adjust to adjust_limit immediately */ + /* after a delay of one frame. */ + /* For a loudness decrease, reduce ATH adjust */ + /* towards adjust_limit gradually. */ + /* max_pow is a loudness squared or a power. */ + if (max_pow > 0.03125) { /* ((1 - 0.000625)/ 31.98) from curve below */ + if (gfc->ATH->adjust_factor >= 1.0) { + gfc->ATH->adjust_factor = 1.0; + } + else { + /* preceding frame has lower ATH adjust; */ + /* ascend only to the preceding adjust_limit */ + /* in case there is leading low volume */ + if (gfc->ATH->adjust_factor < gfc->ATH->adjust_limit) { + gfc->ATH->adjust_factor = gfc->ATH->adjust_limit; + } + } + gfc->ATH->adjust_limit = 1.0; + } + else { /* adjustment curve */ + /* about 32 dB maximum adjust (0.000625) */ + FLOAT const adj_lim_new = 31.98 * max_pow + 0.000625; + if (gfc->ATH->adjust_factor >= adj_lim_new) { /* descend gradually */ + gfc->ATH->adjust_factor *= adj_lim_new * 0.075 + 0.925; + if (gfc->ATH->adjust_factor < adj_lim_new) { /* stop descent */ + gfc->ATH->adjust_factor = adj_lim_new; + } + } + else { /* ascend */ + if (gfc->ATH->adjust_limit >= adj_lim_new) { + gfc->ATH->adjust_factor = adj_lim_new; + } + else { /* preceding frame has lower ATH adjust; */ + /* ascend only to the preceding adjust_limit */ + if (gfc->ATH->adjust_factor < gfc->ATH->adjust_limit) { + gfc->ATH->adjust_factor = gfc->ATH->adjust_limit; + } + } + } + gfc->ATH->adjust_limit = adj_lim_new; + } +} + +/*********************************************************************** + * + * some simple statistics + * + * bitrate index 0: free bitrate -> not allowed in VBR mode + * : bitrates, kbps depending on MPEG version + * bitrate index 15: forbidden + * + * mode_ext: + * 0: LR + * 1: LR-i + * 2: MS + * 3: MS-i + * + ***********************************************************************/ + +static void +updateStats(lame_internal_flags * const gfc) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncResult_t *eov = &gfc->ov_enc; + int gr, ch; + assert(0 <= eov->bitrate_index && eov->bitrate_index < 16); + assert(0 <= eov->mode_ext && eov->mode_ext < 4); + + /* count bitrate indices */ + eov->bitrate_channelmode_hist[eov->bitrate_index][4]++; + eov->bitrate_channelmode_hist[15][4]++; + + /* count 'em for every mode extension in case of 2 channel encoding */ + if (cfg->channels_out == 2) { + eov->bitrate_channelmode_hist[eov->bitrate_index][eov->mode_ext]++; + eov->bitrate_channelmode_hist[15][eov->mode_ext]++; + } + for (gr = 0; gr < cfg->mode_gr; ++gr) { + for (ch = 0; ch < cfg->channels_out; ++ch) { + int bt = gfc->l3_side.tt[gr][ch].block_type; + if (gfc->l3_side.tt[gr][ch].mixed_block_flag) + bt = 4; + eov->bitrate_blocktype_hist[eov->bitrate_index][bt]++; + eov->bitrate_blocktype_hist[eov->bitrate_index][5]++; + eov->bitrate_blocktype_hist[15][bt]++; + eov->bitrate_blocktype_hist[15][5]++; + } + } +} + + + + +static void +lame_encode_frame_init(lame_internal_flags * gfc, const sample_t *const inbuf[2]) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + + int ch, gr; + + if (gfc->lame_encode_frame_init == 0) { + sample_t primebuff0[286 + 1152 + 576]; + sample_t primebuff1[286 + 1152 + 576]; + int const framesize = 576 * cfg->mode_gr; + /* prime the MDCT/polyphase filterbank with a short block */ + int i, j; + gfc->lame_encode_frame_init = 1; + memset(primebuff0, 0, sizeof(primebuff0)); + memset(primebuff1, 0, sizeof(primebuff1)); + for (i = 0, j = 0; i < 286 + 576 * (1 + cfg->mode_gr); ++i) { + if (i < framesize) { + primebuff0[i] = 0; + if (cfg->channels_out == 2) + primebuff1[i] = 0; + } + else { + primebuff0[i] = inbuf[0][j]; + if (cfg->channels_out == 2) + primebuff1[i] = inbuf[1][j]; + ++j; + } + } + /* polyphase filtering / mdct */ + for (gr = 0; gr < cfg->mode_gr; gr++) { + for (ch = 0; ch < cfg->channels_out; ch++) { + gfc->l3_side.tt[gr][ch].block_type = SHORT_TYPE; + } + } + mdct_sub48(gfc, primebuff0, primebuff1); + + /* check FFT will not use a negative starting offset */ +#if 576 < FFTOFFSET +# error FFTOFFSET greater than 576: FFT uses a negative offset +#endif + /* check if we have enough data for FFT */ + assert(gfc->sv_enc.mf_size >= (BLKSIZE + framesize - FFTOFFSET)); + /* check if we have enough data for polyphase filterbank */ + assert(gfc->sv_enc.mf_size >= (512 + framesize - 32)); + } + +} + + + + + + + +/************************************************************************ +* +* encodeframe() Layer 3 +* +* encode a single frame +* +************************************************************************ +lame_encode_frame() + + + gr 0 gr 1 +inbuf: |--------------|--------------|--------------| + + +Polyphase (18 windows, each shifted 32) +gr 0: +window1 <----512----> +window18 <----512----> + +gr 1: +window1 <----512----> +window18 <----512----> + + + +MDCT output: |--------------|--------------|--------------| + +FFT's <---------1024----------> + <---------1024--------> + + + + inbuf = buffer of PCM data size=MP3 framesize + encoder acts on inbuf[ch][0], but output is delayed by MDCTDELAY + so the MDCT coefficints are from inbuf[ch][-MDCTDELAY] + + psy-model FFT has a 1 granule delay, so we feed it data for the + next granule. + FFT is centered over granule: 224+576+224 + So FFT starts at: 576-224-MDCTDELAY + + MPEG2: FFT ends at: BLKSIZE+576-224-MDCTDELAY (1328) + MPEG1: FFT ends at: BLKSIZE+2*576-224-MDCTDELAY (1904) + + MPEG2: polyphase first window: [0..511] + 18th window: [544..1055] (1056) + MPEG1: 36th window: [1120..1631] (1632) + data needed: 512+framesize-32 + + A close look newmdct.c shows that the polyphase filterbank + only uses data from [0..510] for each window. Perhaps because the window + used by the filterbank is zero for the last point, so Takehiro's + code doesn't bother to compute with it. + + FFT starts at 576-224-MDCTDELAY (304) = 576-FFTOFFSET + +*/ + +typedef FLOAT chgrdata[2][2]; + + +int +lame_encode_mp3_frame( /* Output */ + lame_internal_flags * gfc, /* Context */ + sample_t const *inbuf_l, /* Input */ + sample_t const *inbuf_r, /* Input */ + unsigned char *mp3buf, /* Output */ + int mp3buf_size) +{ /* Output */ + SessionConfig_t const *const cfg = &gfc->cfg; + int mp3count; + III_psy_ratio masking_LR[2][2]; /*LR masking & energy */ + III_psy_ratio masking_MS[2][2]; /*MS masking & energy */ + const III_psy_ratio (*masking)[2]; /*pointer to selected maskings */ + const sample_t *inbuf[2]; + + FLOAT tot_ener[2][4]; + FLOAT ms_ener_ratio[2] = { .5, .5 }; + FLOAT pe[2][2] = { {0., 0.}, {0., 0.} }, pe_MS[2][2] = { { + 0., 0.}, { + 0., 0.}}; + FLOAT (*pe_use)[2]; + + int ch, gr; + + inbuf[0] = inbuf_l; + inbuf[1] = inbuf_r; + + if (gfc->lame_encode_frame_init == 0) { + /*first run? */ + lame_encode_frame_init(gfc, inbuf); + + } + + + /********************** padding *****************************/ + /* padding method as described in + * "MPEG-Layer3 / Bitstream Syntax and Decoding" + * by Martin Sieler, Ralph Sperschneider + * + * note: there is no padding for the very first frame + * + * Robert Hegemann 2000-06-22 + */ + gfc->ov_enc.padding = FALSE; + if ((gfc->sv_enc.slot_lag -= gfc->sv_enc.frac_SpF) < 0) { + gfc->sv_enc.slot_lag += cfg->samplerate_out; + gfc->ov_enc.padding = TRUE; + } + + + + /**************************************** + * Stage 1: psychoacoustic model * + ****************************************/ + + { + /* psychoacoustic model + * psy model has a 1 granule (576) delay that we must compensate for + * (mt 6/99). + */ + int ret; + const sample_t *bufp[2] = {0, 0}; /* address of beginning of left & right granule */ + int blocktype[2]; + + for (gr = 0; gr < cfg->mode_gr; gr++) { + + for (ch = 0; ch < cfg->channels_out; ch++) { + bufp[ch] = &inbuf[ch][576 + gr * 576 - FFTOFFSET]; + } + ret = L3psycho_anal_vbr(gfc, bufp, gr, + masking_LR, masking_MS, + pe[gr], pe_MS[gr], tot_ener[gr], blocktype); + if (ret != 0) + return -4; + + if (cfg->mode == JOINT_STEREO) { + ms_ener_ratio[gr] = tot_ener[gr][2] + tot_ener[gr][3]; + if (ms_ener_ratio[gr] > 0) + ms_ener_ratio[gr] = tot_ener[gr][3] / ms_ener_ratio[gr]; + } + + /* block type flags */ + for (ch = 0; ch < cfg->channels_out; ch++) { + gr_info *const cod_info = &gfc->l3_side.tt[gr][ch]; + cod_info->block_type = blocktype[ch]; + cod_info->mixed_block_flag = 0; + } + } + } + + + /* auto-adjust of ATH, useful for low volume */ + adjust_ATH(gfc); + + + /**************************************** + * Stage 2: MDCT * + ****************************************/ + + /* polyphase filtering / mdct */ + mdct_sub48(gfc, inbuf[0], inbuf[1]); + + + /**************************************** + * Stage 3: MS/LR decision * + ****************************************/ + + /* Here will be selected MS or LR coding of the 2 stereo channels */ + gfc->ov_enc.mode_ext = MPG_MD_LR_LR; + + if (cfg->force_ms) { + gfc->ov_enc.mode_ext = MPG_MD_MS_LR; + } + else if (cfg->mode == JOINT_STEREO) { + /* ms_ratio = is scaled, for historical reasons, to look like + a ratio of side_channel / total. + 0 = signal is 100% mono + .5 = L & R uncorrelated + */ + + /* [0] and [1] are the results for the two granules in MPEG-1, + * in MPEG-2 it's only a faked averaging of the same value + * _prev is the value of the last granule of the previous frame + * _next is the value of the first granule of the next frame + */ + + FLOAT sum_pe_MS = 0; + FLOAT sum_pe_LR = 0; + for (gr = 0; gr < cfg->mode_gr; gr++) { + for (ch = 0; ch < cfg->channels_out; ch++) { + sum_pe_MS += pe_MS[gr][ch]; + sum_pe_LR += pe[gr][ch]; + } + } + + /* based on PE: M/S coding would not use much more bits than L/R */ + if (sum_pe_MS <= 1.00 * sum_pe_LR) { + + gr_info const *const gi0 = &gfc->l3_side.tt[0][0]; + gr_info const *const gi1 = &gfc->l3_side.tt[cfg->mode_gr - 1][0]; + + if (gi0[0].block_type == gi0[1].block_type && gi1[0].block_type == gi1[1].block_type) { + + gfc->ov_enc.mode_ext = MPG_MD_MS_LR; + } + } + } + + /* bit and noise allocation */ + if (gfc->ov_enc.mode_ext == MPG_MD_MS_LR) { + masking = (const III_psy_ratio (*)[2])masking_MS; /* use MS masking */ + pe_use = pe_MS; + } + else { + masking = (const III_psy_ratio (*)[2])masking_LR; /* use LR masking */ + pe_use = pe; + } + + + /* copy data for MP3 frame analyzer */ + if (cfg->analysis && gfc->pinfo != NULL) { + for (gr = 0; gr < cfg->mode_gr; gr++) { + for (ch = 0; ch < cfg->channels_out; ch++) { + gfc->pinfo->ms_ratio[gr] = 0; + gfc->pinfo->ms_ener_ratio[gr] = ms_ener_ratio[gr]; + gfc->pinfo->blocktype[gr][ch] = gfc->l3_side.tt[gr][ch].block_type; + gfc->pinfo->pe[gr][ch] = pe_use[gr][ch]; + memcpy(gfc->pinfo->xr[gr][ch], &gfc->l3_side.tt[gr][ch].xr[0], sizeof(FLOAT) * 576); + /* in psymodel, LR and MS data was stored in pinfo. + switch to MS data: */ + if (gfc->ov_enc.mode_ext == MPG_MD_MS_LR) { + gfc->pinfo->ers[gr][ch] = gfc->pinfo->ers[gr][ch + 2]; + memcpy(gfc->pinfo->energy[gr][ch], gfc->pinfo->energy[gr][ch + 2], + sizeof(gfc->pinfo->energy[gr][ch])); + } + } + } + } + + + /**************************************** + * Stage 4: quantization loop * + ****************************************/ + + if (cfg->vbr == vbr_off || cfg->vbr == vbr_abr) { + static FLOAT const fircoef[9] = { + -0.0207887 * 5, -0.0378413 * 5, -0.0432472 * 5, -0.031183 * 5, + 7.79609e-18 * 5, 0.0467745 * 5, 0.10091 * 5, 0.151365 * 5, + 0.187098 * 5 + }; + + int i; + FLOAT f; + + for (i = 0; i < 18; i++) + gfc->sv_enc.pefirbuf[i] = gfc->sv_enc.pefirbuf[i + 1]; + + f = 0.0; + for (gr = 0; gr < cfg->mode_gr; gr++) + for (ch = 0; ch < cfg->channels_out; ch++) + f += pe_use[gr][ch]; + gfc->sv_enc.pefirbuf[18] = f; + + f = gfc->sv_enc.pefirbuf[9]; + for (i = 0; i < 9; i++) + f += (gfc->sv_enc.pefirbuf[i] + gfc->sv_enc.pefirbuf[18 - i]) * fircoef[i]; + + f = (670 * 5 * cfg->mode_gr * cfg->channels_out) / f; + for (gr = 0; gr < cfg->mode_gr; gr++) { + for (ch = 0; ch < cfg->channels_out; ch++) { + pe_use[gr][ch] *= f; + } + } + } + switch (cfg->vbr) + { + default: + case vbr_off: + CBR_iteration_loop(gfc, (const FLOAT (*)[2])pe_use, ms_ener_ratio, masking); + break; + case vbr_abr: + ABR_iteration_loop(gfc, (const FLOAT (*)[2])pe_use, ms_ener_ratio, masking); + break; + case vbr_rh: + VBR_old_iteration_loop(gfc, (const FLOAT (*)[2])pe_use, ms_ener_ratio, masking); + break; + case vbr_mt: + case vbr_mtrh: + VBR_new_iteration_loop(gfc, (const FLOAT (*)[2])pe_use, ms_ener_ratio, masking); + break; + } + + + /**************************************** + * Stage 5: bitstream formatting * + ****************************************/ + + + /* write the frame to the bitstream */ + (void) format_bitstream(gfc); + + /* copy mp3 bit buffer into array */ + mp3count = copy_buffer(gfc, mp3buf, mp3buf_size, 1); + + + if (cfg->write_lame_tag) { + AddVbrFrame(gfc); + } + + if (cfg->analysis && gfc->pinfo != NULL) { + int framesize = 576 * cfg->mode_gr; + for (ch = 0; ch < cfg->channels_out; ch++) { + int j; + for (j = 0; j < FFTOFFSET; j++) + gfc->pinfo->pcmdata[ch][j] = gfc->pinfo->pcmdata[ch][j + framesize]; + for (j = FFTOFFSET; j < 1600; j++) { + gfc->pinfo->pcmdata[ch][j] = inbuf[ch][j - FFTOFFSET]; + } + } + gfc->sv_qnt.masking_lower = 1.0; + + set_frame_pinfo(gfc, masking); + } + + ++gfc->ov_enc.frame_number; + + updateStats(gfc); + + return mp3count; +} diff --git a/pkg/lame/clame/encoder.h b/pkg/lame/clame/encoder.h new file mode 100644 index 0000000..b06a7c6 --- /dev/null +++ b/pkg/lame/clame/encoder.h @@ -0,0 +1,156 @@ +/* + * encoder.h include file + * + * Copyright (c) 2000 Mark Taylor + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#ifndef LAME_ENCODER_H +#define LAME_ENCODER_H + +/*********************************************************************** +* +* encoder and decoder delays +* +***********************************************************************/ + +/* + * layer III enc->dec delay: 1056 (1057?) (observed) + * layer II enc->dec delay: 480 (481?) (observed) + * + * polyphase 256-16 (dec or enc) = 240 + * mdct 256+32 (9*32) (dec or enc) = 288 + * total: 512+16 + * + * My guess is that delay of polyphase filterbank is actualy 240.5 + * (there are technical reasons for this, see postings in mp3encoder). + * So total Encode+Decode delay = ENCDELAY + 528 + 1 + */ + +/* + * ENCDELAY The encoder delay. + * + * Minimum allowed is MDCTDELAY (see below) + * + * The first 96 samples will be attenuated, so using a value less than 96 + * will result in corrupt data for the first 96-ENCDELAY samples. + * + * suggested: 576 + * set to 1160 to sync with FhG. + */ + +#define ENCDELAY 576 + + + +/* + * make sure there is at least one complete frame after the + * last frame containing real data + * + * Using a value of 288 would be sufficient for a + * a very sophisticated decoder that can decode granule-by-granule instead + * of frame by frame. But lets not assume this, and assume the decoder + * will not decode frame N unless it also has data for frame N+1 + * + */ +/*#define POSTDELAY 288*/ +#define POSTDELAY 1152 + + + +/* + * delay of the MDCT used in mdct.c + * original ISO routines had a delay of 528! + * Takehiro's routines: + */ + +#define MDCTDELAY 48 +#define FFTOFFSET (224+MDCTDELAY) + +/* + * Most decoders, including the one we use, have a delay of 528 samples. + */ + +#define DECDELAY 528 + + +/* number of subbands */ +#define SBLIMIT 32 + +/* parition bands bands */ +#define CBANDS 64 + +/* number of critical bands/scale factor bands where masking is computed*/ +#define SBPSY_l 21 +#define SBPSY_s 12 + +/* total number of scalefactor bands encoded */ +#define SBMAX_l 22 +#define SBMAX_s 13 +#define PSFB21 6 +#define PSFB12 6 + + + +/* FFT sizes */ +#define BLKSIZE 1024 +#define HBLKSIZE (BLKSIZE/2 + 1) +#define BLKSIZE_s 256 +#define HBLKSIZE_s (BLKSIZE_s/2 + 1) + + +/* #define switch_pe 1800 */ +#define NORM_TYPE 0 +#define START_TYPE 1 +#define SHORT_TYPE 2 +#define STOP_TYPE 3 + +/* + * Mode Extention: + * When we are in stereo mode, there are 4 possible methods to store these + * two channels. The stereo modes -m? are using a subset of them. + * + * -ms: MPG_MD_LR_LR + * -mj: MPG_MD_LR_LR and MPG_MD_MS_LR + * -mf: MPG_MD_MS_LR + * -mi: all + */ +#if 0 +#define MPG_MD_LR_LR 0 +#define MPG_MD_LR_I 1 +#define MPG_MD_MS_LR 2 +#define MPG_MD_MS_I 3 +#endif +enum MPEGChannelMode +{ MPG_MD_LR_LR = 0 +, MPG_MD_LR_I = 1 +, MPG_MD_MS_LR = 2 +, MPG_MD_MS_I = 3 +}; + +#ifndef lame_internal_flags_defined +#define lame_internal_flags_defined +struct lame_internal_flags; +typedef struct lame_internal_flags lame_internal_flags; +#endif + +int lame_encode_mp3_frame(lame_internal_flags * gfc, + sample_t const *inbuf_l, + sample_t const *inbuf_r, unsigned char *mp3buf, int mp3buf_size); + +#endif /* LAME_ENCODER_H */ diff --git a/pkg/lame/clame/fft.c b/pkg/lame/clame/fft.c new file mode 100644 index 0000000..163e155 --- /dev/null +++ b/pkg/lame/clame/fft.c @@ -0,0 +1,339 @@ +/* +** FFT and FHT routines +** Copyright 1988, 1993; Ron Mayer +** Copyright (c) 1999-2000 Takehiro Tominaga +** +** fht(fz,n); +** Does a hartley transform of "n" points in the array "fz". +** +** NOTE: This routine uses at least 2 patented algorithms, and may be +** under the restrictions of a bunch of different organizations. +** Although I wrote it completely myself; it is kind of a derivative +** of a routine I once authored and released under the GPL, so it +** may fall under the free software foundation's restrictions; +** it was worked on as a Stanford Univ project, so they claim +** some rights to it; it was further optimized at work here, so +** I think this company claims parts of it. The patents are +** held by R. Bracewell (the FHT algorithm) and O. Buneman (the +** trig generator), both at Stanford Univ. +** If it were up to me, I'd say go do whatever you want with it; +** but it would be polite to give credit to the following people +** if you use this anywhere: +** Euler - probable inventor of the fourier transform. +** Gauss - probable inventor of the FFT. +** Hartley - probable inventor of the hartley transform. +** Buneman - for a really cool trig generator +** Mayer(me) - for authoring this particular version and +** including all the optimizations in one package. +** Thanks, +** Ron Mayer; mayer@acuson.com +** and added some optimization by +** Mather - idea of using lookup table +** Takehiro - some dirty hack for speed up +*/ + +/* $Id: fft.c,v 1.39 2017/09/06 15:07:29 robert Exp $ */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "lame.h" +#include "machine.h" +#include "encoder.h" +#include "util.h" +#include "fft.h" + +#include "lame_intrin.h" + + + +#define TRI_SIZE (5-1) /* 1024 = 4**5 */ + +/* fft.c */ + +static const FLOAT costab[TRI_SIZE * 2] = { + 9.238795325112867e-01, 3.826834323650898e-01, + 9.951847266721969e-01, 9.801714032956060e-02, + 9.996988186962042e-01, 2.454122852291229e-02, + 9.999811752826011e-01, 6.135884649154475e-03 +}; + +static void +fht(FLOAT * fz, int n) +{ + const FLOAT *tri = costab; + int k4; + FLOAT *fi, *gi; + FLOAT const *fn; + + n <<= 1; /* to get BLKSIZE, because of 3DNow! ASM routine */ + fn = fz + n; + k4 = 4; + do { + FLOAT s1, c1; + int i, k1, k2, k3, kx; + kx = k4 >> 1; + k1 = k4; + k2 = k4 << 1; + k3 = k2 + k1; + k4 = k2 << 1; + fi = fz; + gi = fi + kx; + do { + FLOAT f0, f1, f2, f3; + f1 = fi[0] - fi[k1]; + f0 = fi[0] + fi[k1]; + f3 = fi[k2] - fi[k3]; + f2 = fi[k2] + fi[k3]; + fi[k2] = f0 - f2; + fi[0] = f0 + f2; + fi[k3] = f1 - f3; + fi[k1] = f1 + f3; + f1 = gi[0] - gi[k1]; + f0 = gi[0] + gi[k1]; + f3 = SQRT2 * gi[k3]; + f2 = SQRT2 * gi[k2]; + gi[k2] = f0 - f2; + gi[0] = f0 + f2; + gi[k3] = f1 - f3; + gi[k1] = f1 + f3; + gi += k4; + fi += k4; + } while (fi < fn); + c1 = tri[0]; + s1 = tri[1]; + for (i = 1; i < kx; i++) { + FLOAT c2, s2; + c2 = 1 - (2 * s1) * s1; + s2 = (2 * s1) * c1; + fi = fz + i; + gi = fz + k1 - i; + do { + FLOAT a, b, g0, f0, f1, g1, f2, g2, f3, g3; + b = s2 * fi[k1] - c2 * gi[k1]; + a = c2 * fi[k1] + s2 * gi[k1]; + f1 = fi[0] - a; + f0 = fi[0] + a; + g1 = gi[0] - b; + g0 = gi[0] + b; + b = s2 * fi[k3] - c2 * gi[k3]; + a = c2 * fi[k3] + s2 * gi[k3]; + f3 = fi[k2] - a; + f2 = fi[k2] + a; + g3 = gi[k2] - b; + g2 = gi[k2] + b; + b = s1 * f2 - c1 * g3; + a = c1 * f2 + s1 * g3; + fi[k2] = f0 - a; + fi[0] = f0 + a; + gi[k3] = g1 - b; + gi[k1] = g1 + b; + b = c1 * g2 - s1 * f3; + a = s1 * g2 + c1 * f3; + gi[k2] = g0 - a; + gi[0] = g0 + a; + fi[k3] = f1 - b; + fi[k1] = f1 + b; + gi += k4; + fi += k4; + } while (fi < fn); + c2 = c1; + c1 = c2 * tri[0] - s1 * tri[1]; + s1 = c2 * tri[1] + s1 * tri[0]; + } + tri += 2; + } while (k4 < n); +} + + +static const unsigned char rv_tbl[] = { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe +}; + +#define ch01(index) (buffer[chn][index]) + +#define ml00(f) (window[i ] * f(i)) +#define ml10(f) (window[i + 0x200] * f(i + 0x200)) +#define ml20(f) (window[i + 0x100] * f(i + 0x100)) +#define ml30(f) (window[i + 0x300] * f(i + 0x300)) + +#define ml01(f) (window[i + 0x001] * f(i + 0x001)) +#define ml11(f) (window[i + 0x201] * f(i + 0x201)) +#define ml21(f) (window[i + 0x101] * f(i + 0x101)) +#define ml31(f) (window[i + 0x301] * f(i + 0x301)) + +#define ms00(f) (window_s[i ] * f(i + k)) +#define ms10(f) (window_s[0x7f - i] * f(i + k + 0x80)) +#define ms20(f) (window_s[i + 0x40] * f(i + k + 0x40)) +#define ms30(f) (window_s[0x3f - i] * f(i + k + 0xc0)) + +#define ms01(f) (window_s[i + 0x01] * f(i + k + 0x01)) +#define ms11(f) (window_s[0x7e - i] * f(i + k + 0x81)) +#define ms21(f) (window_s[i + 0x41] * f(i + k + 0x41)) +#define ms31(f) (window_s[0x3e - i] * f(i + k + 0xc1)) + +void +fft_short(lame_internal_flags const *const gfc, + FLOAT x_real[3][BLKSIZE_s], int chn, const sample_t *const buffer[2]) +{ + int i; + int j; + int b; + +#define window_s gfc->cd_psy->window_s +#define window gfc->cd_psy->window + + for (b = 0; b < 3; b++) { + FLOAT *x = &x_real[b][BLKSIZE_s / 2]; + short const k = (576 / 3) * (b + 1); + j = BLKSIZE_s / 8 - 1; + do { + FLOAT f0, f1, f2, f3, w; + + i = rv_tbl[j << 2]; + + f0 = ms00(ch01); + w = ms10(ch01); + f1 = f0 - w; + f0 = f0 + w; + f2 = ms20(ch01); + w = ms30(ch01); + f3 = f2 - w; + f2 = f2 + w; + + x -= 4; + x[0] = f0 + f2; + x[2] = f0 - f2; + x[1] = f1 + f3; + x[3] = f1 - f3; + + f0 = ms01(ch01); + w = ms11(ch01); + f1 = f0 - w; + f0 = f0 + w; + f2 = ms21(ch01); + w = ms31(ch01); + f3 = f2 - w; + f2 = f2 + w; + + x[BLKSIZE_s / 2 + 0] = f0 + f2; + x[BLKSIZE_s / 2 + 2] = f0 - f2; + x[BLKSIZE_s / 2 + 1] = f1 + f3; + x[BLKSIZE_s / 2 + 3] = f1 - f3; + } while (--j >= 0); + +#undef window +#undef window_s + + gfc->fft_fht(x, BLKSIZE_s / 2); + /* BLKSIZE_s/2 because of 3DNow! ASM routine */ + } +} + +void +fft_long(lame_internal_flags const *const gfc, + FLOAT x[BLKSIZE], int chn, const sample_t *const buffer[2]) +{ + int i; + int jj = BLKSIZE / 8 - 1; + x += BLKSIZE / 2; + +#define window_s gfc->cd_psy->window_s +#define window gfc->cd_psy->window + + do { + FLOAT f0, f1, f2, f3, w; + + i = rv_tbl[jj]; + f0 = ml00(ch01); + w = ml10(ch01); + f1 = f0 - w; + f0 = f0 + w; + f2 = ml20(ch01); + w = ml30(ch01); + f3 = f2 - w; + f2 = f2 + w; + + x -= 4; + x[0] = f0 + f2; + x[2] = f0 - f2; + x[1] = f1 + f3; + x[3] = f1 - f3; + + f0 = ml01(ch01); + w = ml11(ch01); + f1 = f0 - w; + f0 = f0 + w; + f2 = ml21(ch01); + w = ml31(ch01); + f3 = f2 - w; + f2 = f2 + w; + + x[BLKSIZE / 2 + 0] = f0 + f2; + x[BLKSIZE / 2 + 2] = f0 - f2; + x[BLKSIZE / 2 + 1] = f1 + f3; + x[BLKSIZE / 2 + 3] = f1 - f3; + } while (--jj >= 0); + +#undef window +#undef window_s + + gfc->fft_fht(x, BLKSIZE / 2); + /* BLKSIZE/2 because of 3DNow! ASM routine */ +} + +#ifdef HAVE_NASM +extern void fht_3DN(FLOAT * fz, int n); +extern void fht_SSE(FLOAT * fz, int n); +#endif + +void +init_fft(lame_internal_flags * const gfc) +{ + int i; + + /* The type of window used here will make no real difference, but */ + /* in the interest of merging nspsytune stuff - switch to blackman window */ + for (i = 0; i < BLKSIZE; i++) + /* blackman window */ + gfc->cd_psy->window[i] = 0.42 - 0.5 * cos(2 * PI * (i + .5) / BLKSIZE) + + 0.08 * cos(4 * PI * (i + .5) / BLKSIZE); + + for (i = 0; i < BLKSIZE_s / 2; i++) + gfc->cd_psy->window_s[i] = 0.5 * (1.0 - cos(2.0 * PI * (i + 0.5) / BLKSIZE_s)); + + gfc->fft_fht = fht; +#ifdef HAVE_NASM + if (gfc->CPU_features.AMD_3DNow) { + gfc->fft_fht = fht_3DN; + } + else if (gfc->CPU_features.SSE) { + gfc->fft_fht = fht_SSE; + } + else { + gfc->fft_fht = fht; + } +#else +#ifdef HAVE_XMMINTRIN_H +#ifdef MIN_ARCH_SSE + gfc->fft_fht = fht_SSE2; +#endif +#endif +#endif +} diff --git a/pkg/lame/clame/fft.h b/pkg/lame/clame/fft.h new file mode 100644 index 0000000..258df88 --- /dev/null +++ b/pkg/lame/clame/fft.h @@ -0,0 +1,35 @@ +/* + * Fast Fourier Transform include file + * + * Copyright (c) 2000 Mark Taylor + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef LAME_FFT_H +#define LAME_FFT_H + +void fft_long(lame_internal_flags const *const gfc, FLOAT x_real[BLKSIZE], + int chn, const sample_t *const data[2]); + +void fft_short(lame_internal_flags const *const gfc, FLOAT x_real[3][BLKSIZE_s], + int chn, const sample_t *const data[2]); + +void init_fft(lame_internal_flags * const gfc); + +#endif + +/* End of fft.h */ diff --git a/pkg/lame/clame/gain_analysis.c b/pkg/lame/clame/gain_analysis.c new file mode 100644 index 0000000..c94db78 --- /dev/null +++ b/pkg/lame/clame/gain_analysis.c @@ -0,0 +1,476 @@ +/* + * ReplayGainAnalysis - analyzes input samples and give the recommended dB change + * Copyright (C) 2001 David Robinson and Glen Sawyer + * Improvements and optimizations added by Frank Klemm, and by Marcel Muller + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * concept and filter values by David Robinson (David@Robinson.org) + * -- blame him if you think the idea is flawed + * original coding by Glen Sawyer (mp3gain@hotmail.com) + * -- blame him if you think this runs too slowly, or the coding is otherwise flawed + * + * lots of code improvements by Frank Klemm ( http://www.uni-jena.de/~pfk/mpp/ ) + * -- credit him for all the _good_ programming ;) + * + * + * For an explanation of the concepts and the basic algorithms involved, go to: + * http://www.replaygain.org/ + */ + +/* + * Here's the deal. Call + * + * InitGainAnalysis ( long samplefreq ); + * + * to initialize everything. Call + * + * AnalyzeSamples ( const Float_t* left_samples, + * const Float_t* right_samples, + * size_t num_samples, + * int num_channels ); + * + * as many times as you want, with as many or as few samples as you want. + * If mono, pass the sample buffer in through left_samples, leave + * right_samples NULL, and make sure num_channels = 1. + * + * GetTitleGain() + * + * will return the recommended dB level change for all samples analyzed + * SINCE THE LAST TIME you called GetTitleGain() OR InitGainAnalysis(). + * + * GetAlbumGain() + * + * will return the recommended dB level change for all samples analyzed + * since InitGainAnalysis() was called and finalized with GetTitleGain(). + * + * Pseudo-code to process an album: + * + * Float_t l_samples [4096]; + * Float_t r_samples [4096]; + * size_t num_samples; + * unsigned int num_songs; + * unsigned int i; + * + * InitGainAnalysis ( 44100 ); + * for ( i = 1; i <= num_songs; i++ ) { + * while ( ( num_samples = getSongSamples ( song[i], left_samples, right_samples ) ) > 0 ) + * AnalyzeSamples ( left_samples, right_samples, num_samples, 2 ); + * fprintf ("Recommended dB change for song %2d: %+6.2f dB\n", i, GetTitleGain() ); + * } + * fprintf ("Recommended dB change for whole album: %+6.2f dB\n", GetAlbumGain() ); + */ + +/* + * So here's the main source of potential code confusion: + * + * The filters applied to the incoming samples are IIR filters, + * meaning they rely on up to number of previous samples + * AND up to number of previous filtered samples. + * + * I set up the AnalyzeSamples routine to minimize memory usage and interface + * complexity. The speed isn't compromised too much (I don't think), but the + * internal complexity is higher than it should be for such a relatively + * simple routine. + * + * Optimization/clarity suggestions are welcome. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "lame.h" +#include "machine.h" +#include "gain_analysis.h" + +/* for each filter: */ +/* [0] 48 kHz, [1] 44.1 kHz, [2] 32 kHz, [3] 24 kHz, [4] 22050 Hz, [5] 16 kHz, [6] 12 kHz, [7] is 11025 Hz, [8] 8 kHz */ + +#ifdef WIN32 +#pragma warning ( disable : 4305 ) +#endif + + +/*lint -save -e736 loss of precision */ +static const Float_t ABYule[9][multiple_of(4, 2 * YULE_ORDER + 1)] = { + /* 20 18 16 14 12 10 8 6 4 2 0 19 17 15 13 11 9 7 5 3 1 */ + { 0.00288463683916, 0.00012025322027, 0.00306428023191, 0.00594298065125, -0.02074045215285, 0.02161526843274, -0.01655260341619, -0.00009291677959, -0.00123395316851, -0.02160367184185, 0.03857599435200, 0.13919314567432, -0.86984376593551, 2.75465861874613, -5.87257861775999, 9.48293806319790,-12.28759895145294, 13.05504219327545,-11.34170355132042, 7.81501653005538, -3.84664617118067}, + {-0.00187763777362, 0.00674613682247, -0.00240879051584, 0.01624864962975, -0.02596338512915, 0.02245293253339, -0.00834990904936, -0.00851165645469, -0.00848709379851, -0.02911007808948, 0.05418656406430, 0.13149317958808, -0.75104302451432, 2.19611684890774, -4.39470996079559, 6.85401540936998, -8.81498681370155, 9.47693607801280, -8.54751527471874, 6.36317777566148, -3.47845948550071}, + {-0.00881362733839, 0.00651420667831, -0.01390589421898, 0.03174092540049, 0.00222312597743, 0.04781476674921, -0.05588393329856, 0.02163541888798, -0.06247880153653, -0.09331049056315, 0.15457299681924, 0.02347897407020, -0.05032077717131, 0.16378164858596, -0.45953458054983, 1.00595954808547, -1.67148153367602, 2.23697657451713, -2.64577170229825, 2.84868151156327, -2.37898834973084}, + {-0.02950134983287, 0.00205861885564, -0.00000828086748, 0.06276101321749, -0.00584456039913, -0.02364141202522, -0.00915702933434, 0.03282930172664, -0.08587323730772, -0.22613988682123, 0.30296907319327, 0.00302439095741, 0.02005851806501, 0.04500235387352, -0.22138138954925, 0.39120800788284, -0.22638893773906, -0.16276719120440, -0.25656257754070, 1.07977492259970, -1.61273165137247}, + {-0.01760176568150, -0.01635381384540, 0.00832043980773, 0.05724228140351, -0.00589500224440, -0.00469977914380, -0.07834489609479, 0.11921148675203, -0.11828570177555, -0.25572241425570, 0.33642304856132, 0.02977207319925, -0.04237348025746, 0.08333755284107, -0.04067510197014, -0.12453458140019, 0.47854794562326, -0.80774944671438, 0.12205022308084, 0.87350271418188, -1.49858979367799}, + { 0.00541907748707, -0.03193428438915, -0.01863887810927, 0.10478503600251, 0.04097565135648, -0.12398163381748, 0.04078262797139, -0.01419140100551, -0.22784394429749, -0.14351757464547, 0.44915256608450, 0.03222754072173, 0.05784820375801, 0.06747620744683, 0.00613424350682, 0.22199650564824, -0.42029820170918, 0.00213767857124, -0.37256372942400, 0.29661783706366, -0.62820619233671}, + {-0.00588215443421, -0.03788984554840, 0.08647503780351, 0.00647310677246, -0.27562961986224, 0.30931782841830, -0.18901604199609, 0.16744243493672, 0.16242137742230, -0.75464456939302, 0.56619470757641, 0.01807364323573, 0.01639907836189, -0.04784254229033, 0.06739368333110, -0.33032403314006, 0.45054734505008, 0.00819999645858, -0.26806001042947, 0.29156311971249, -1.04800335126349}, + {-0.00749618797172, -0.03721611395801, 0.06920467763959, 0.01628462406333, -0.25344790059353, 0.15558449135573, 0.02377945217615, 0.17520704835522, -0.14289799034253, -0.53174909058578, 0.58100494960553, 0.01818801111503, 0.02442357316099, -0.02505961724053, -0.05246019024463, -0.23313271880868, 0.38952639978999, 0.14728154134330, -0.20256413484477, -0.31863563325245, -0.51035327095184}, + {-0.02217936801134, 0.04788665548180, -0.04060034127000, -0.11202315195388, -0.02459864859345, 0.14590772289388, -0.10214864179676, 0.04267842219415, -0.00275953611929, -0.42163034350696, 0.53648789255105, 0.04704409688120, 0.05477720428674, -0.18823009262115, -0.17556493366449, 0.15113130533216, 0.26408300200955, -0.04678328784242, -0.03424681017675, -0.43193942311114, -0.25049871956020} +}; + +static const Float_t ABButter[9][multiple_of(4, 2 * BUTTER_ORDER + 1)] = { + /* 5 4 3 2 1 */ + {0.98621192462708, 0.97261396931306, -1.97242384925416, -1.97223372919527, 0.98621192462708}, + {0.98500175787242, 0.97022847566350, -1.97000351574484, -1.96977855582618, 0.98500175787242}, + {0.97938932735214, 0.95920349965459, -1.95877865470428, -1.95835380975398, 0.97938932735214}, + {0.97531843204928, 0.95124613669835, -1.95063686409857, -1.95002759149878, 0.97531843204928}, + {0.97316523498161, 0.94705070426118, -1.94633046996323, -1.94561023566527, 0.97316523498161}, + {0.96454515552826, 0.93034775234268, -1.92909031105652, -1.92783286977036, 0.96454515552826}, + {0.96009142950541, 0.92177618768381, -1.92018285901082, -1.91858953033784, 0.96009142950541}, + {0.95856916599601, 0.91885558323625, -1.91713833199203, -1.91542108074780, 0.95856916599601}, + {0.94597685600279, 0.89487434461664, -1.89195371200558, -1.88903307939452, 0.94597685600279} +}; + +/*lint -restore */ + +#ifdef WIN32 +#pragma warning ( default : 4305 ) +#endif + +/* When calling this procedure, make sure that ip[-order] and op[-order] point to real data! */ + +static void +filterYule(const Float_t * input, Float_t * output, size_t nSamples, const Float_t * const kernel) +{ + while (nSamples--) { + Float_t y0 = input[-10] * kernel[ 0]; + Float_t y2 = input[ -9] * kernel[ 1]; + Float_t y4 = input[ -8] * kernel[ 2]; + Float_t y6 = input[ -7] * kernel[ 3]; + Float_t s00 = y0 + y2 + y4 + y6; + Float_t y8 = input[ -6] * kernel[ 4]; + Float_t yA = input[ -5] * kernel[ 5]; + Float_t yC = input[ -4] * kernel[ 6]; + Float_t yE = input[ -3] * kernel[ 7]; + Float_t s01 = y8 + yA + yC + yE; + Float_t yG = input[ -2] * kernel[ 8] + input[ -1] * kernel[ 9]; + Float_t yK = input[ 0] * kernel[10]; + + Float_t s1 = s00 + s01 + yG + yK; + + Float_t x1 = output[-10] * kernel[11] + output[ -9] * kernel[12]; + Float_t x5 = output[ -8] * kernel[13] + output[ -7] * kernel[14]; + Float_t x9 = output[ -6] * kernel[15] + output[ -5] * kernel[16]; + Float_t xD = output[ -4] * kernel[17] + output[ -3] * kernel[18]; + Float_t xH = output[ -2] * kernel[19] + output[ -1] * kernel[20]; + + Float_t s2 = x1 + x5 + x9 + xD + xH; + + output[0] = (Float_t)(s1 - s2); + + ++output; + ++input; + } +} + +static void +filterButter(const Float_t * input, Float_t * output, size_t nSamples, const Float_t * const kernel) +{ + while (nSamples--) { + Float_t s1 = input[-2] * kernel[0] + input[-1] * kernel[2] + input[ 0] * kernel[4]; + Float_t s2 = output[-2] * kernel[1] + output[-1] * kernel[3]; + output[0] = (Float_t)(s1 - s2); + ++output; + ++input; + } +} + + + +static int ResetSampleFrequency(replaygain_t * rgData, long samplefreq); + +/* returns a INIT_GAIN_ANALYSIS_OK if successful, INIT_GAIN_ANALYSIS_ERROR if not */ + +int +ResetSampleFrequency(replaygain_t * rgData, long samplefreq) +{ + /* zero out initial values, only first MAX_ORDER values */ + memset(rgData->linprebuf, 0, MAX_ORDER * sizeof(*rgData->linprebuf)); + memset(rgData->rinprebuf, 0, MAX_ORDER * sizeof(*rgData->rinprebuf)); + memset(rgData->lstepbuf, 0, MAX_ORDER * sizeof(*rgData->lstepbuf)); + memset(rgData->rstepbuf, 0, MAX_ORDER * sizeof(*rgData->rstepbuf)); + memset(rgData->loutbuf, 0, MAX_ORDER * sizeof(*rgData->loutbuf)); + memset(rgData->routbuf, 0, MAX_ORDER * sizeof(*rgData->routbuf)); + + switch ((int) (samplefreq)) { + case 48000: + rgData->freqindex = 0; + break; + case 44100: + rgData->freqindex = 1; + break; + case 32000: + rgData->freqindex = 2; + break; + case 24000: + rgData->freqindex = 3; + break; + case 22050: + rgData->freqindex = 4; + break; + case 16000: + rgData->freqindex = 5; + break; + case 12000: + rgData->freqindex = 6; + break; + case 11025: + rgData->freqindex = 7; + break; + case 8000: + rgData->freqindex = 8; + break; + default: + return INIT_GAIN_ANALYSIS_ERROR; + } + + rgData->sampleWindow = + (samplefreq * RMS_WINDOW_TIME_NUMERATOR + RMS_WINDOW_TIME_DENOMINATOR - + 1) / RMS_WINDOW_TIME_DENOMINATOR; + + rgData->lsum = 0.; + rgData->rsum = 0.; + rgData->totsamp = 0; + + memset(rgData->A, 0, sizeof(rgData->A)); + + return INIT_GAIN_ANALYSIS_OK; +} + +int +InitGainAnalysis(replaygain_t * rgData, long samplefreq) +{ + if (ResetSampleFrequency(rgData, samplefreq) != INIT_GAIN_ANALYSIS_OK) { + return INIT_GAIN_ANALYSIS_ERROR; + } + + rgData->linpre = rgData->linprebuf + MAX_ORDER; + rgData->rinpre = rgData->rinprebuf + MAX_ORDER; + rgData->lstep = rgData->lstepbuf + MAX_ORDER; + rgData->rstep = rgData->rstepbuf + MAX_ORDER; + rgData->lout = rgData->loutbuf + MAX_ORDER; + rgData->rout = rgData->routbuf + MAX_ORDER; + + memset(rgData->B, 0, sizeof(rgData->B)); + + return INIT_GAIN_ANALYSIS_OK; +} + +/* returns GAIN_ANALYSIS_OK if successful, GAIN_ANALYSIS_ERROR if not */ + +int +AnalyzeSamples(replaygain_t * rgData, const Float_t * left_samples, const Float_t * right_samples, + size_t num_samples, int num_channels) +{ + const Float_t *curleft; + const Float_t *curright; + long batchsamples; + long cursamples; + long cursamplepos; + int i; + Float_t sum_l, sum_r; + + if (num_samples == 0) + return GAIN_ANALYSIS_OK; + + cursamplepos = 0; + batchsamples = (long) num_samples; + + switch (num_channels) { + case 1: + right_samples = left_samples; + break; + case 2: + break; + default: + return GAIN_ANALYSIS_ERROR; + } + + if (num_samples < MAX_ORDER) { + memcpy(rgData->linprebuf + MAX_ORDER, left_samples, num_samples * sizeof(Float_t)); + memcpy(rgData->rinprebuf + MAX_ORDER, right_samples, num_samples * sizeof(Float_t)); + } + else { + memcpy(rgData->linprebuf + MAX_ORDER, left_samples, MAX_ORDER * sizeof(Float_t)); + memcpy(rgData->rinprebuf + MAX_ORDER, right_samples, MAX_ORDER * sizeof(Float_t)); + } + + while (batchsamples > 0) { + cursamples = batchsamples > rgData->sampleWindow - rgData->totsamp ? + rgData->sampleWindow - rgData->totsamp : batchsamples; + if (cursamplepos < MAX_ORDER) { + curleft = rgData->linpre + cursamplepos; + curright = rgData->rinpre + cursamplepos; + if (cursamples > MAX_ORDER - cursamplepos) + cursamples = MAX_ORDER - cursamplepos; + } + else { + curleft = left_samples + cursamplepos; + curright = right_samples + cursamplepos; + } + + YULE_FILTER(curleft, rgData->lstep + rgData->totsamp, cursamples, + ABYule[rgData->freqindex]); + YULE_FILTER(curright, rgData->rstep + rgData->totsamp, cursamples, + ABYule[rgData->freqindex]); + + BUTTER_FILTER(rgData->lstep + rgData->totsamp, rgData->lout + rgData->totsamp, cursamples, + ABButter[rgData->freqindex]); + BUTTER_FILTER(rgData->rstep + rgData->totsamp, rgData->rout + rgData->totsamp, cursamples, + ABButter[rgData->freqindex]); + + curleft = rgData->lout + rgData->totsamp; /* Get the squared values */ + curright = rgData->rout + rgData->totsamp; + + sum_l = 0; + sum_r = 0; + i = cursamples & 0x03; + while (i--) { + Float_t const l = *curleft++; + Float_t const r = *curright++; + sum_l += l * l; + sum_r += r * r; + } + i = cursamples / 4; + while (i--) { + Float_t l0 = curleft[0] * curleft[0]; + Float_t l1 = curleft[1] * curleft[1]; + Float_t l2 = curleft[2] * curleft[2]; + Float_t l3 = curleft[3] * curleft[3]; + Float_t sl = l0 + l1 + l2 + l3; + Float_t r0 = curright[0] * curright[0]; + Float_t r1 = curright[1] * curright[1]; + Float_t r2 = curright[2] * curright[2]; + Float_t r3 = curright[3] * curright[3]; + Float_t sr = r0 + r1 + r2 + r3; + sum_l += sl; + curleft += 4; + sum_r += sr; + curright += 4; + } + rgData->lsum += sum_l; + rgData->rsum += sum_r; + + batchsamples -= cursamples; + cursamplepos += cursamples; + rgData->totsamp += cursamples; + if (rgData->totsamp == rgData->sampleWindow) { /* Get the Root Mean Square (RMS) for this set of samples */ + double const val = + STEPS_per_dB * 10. * log10((rgData->lsum + rgData->rsum) / rgData->totsamp * 0.5 + + 1.e-37); + size_t ival = (val <= 0) ? 0 : (size_t) val; + if (ival >= sizeof(rgData->A) / sizeof(*(rgData->A))) + ival = sizeof(rgData->A) / sizeof(*(rgData->A)) - 1; + rgData->A[ival]++; + rgData->lsum = rgData->rsum = 0.; + memmove(rgData->loutbuf, rgData->loutbuf + rgData->totsamp, + MAX_ORDER * sizeof(Float_t)); + memmove(rgData->routbuf, rgData->routbuf + rgData->totsamp, + MAX_ORDER * sizeof(Float_t)); + memmove(rgData->lstepbuf, rgData->lstepbuf + rgData->totsamp, + MAX_ORDER * sizeof(Float_t)); + memmove(rgData->rstepbuf, rgData->rstepbuf + rgData->totsamp, + MAX_ORDER * sizeof(Float_t)); + rgData->totsamp = 0; + } + if (rgData->totsamp > rgData->sampleWindow) /* somehow I really screwed up: Error in programming! Contact author about totsamp > sampleWindow */ + return GAIN_ANALYSIS_ERROR; + } + if (num_samples < MAX_ORDER) { + memmove(rgData->linprebuf, rgData->linprebuf + num_samples, + (MAX_ORDER - num_samples) * sizeof(Float_t)); + memmove(rgData->rinprebuf, rgData->rinprebuf + num_samples, + (MAX_ORDER - num_samples) * sizeof(Float_t)); + memcpy(rgData->linprebuf + MAX_ORDER - num_samples, left_samples, + num_samples * sizeof(Float_t)); + memcpy(rgData->rinprebuf + MAX_ORDER - num_samples, right_samples, + num_samples * sizeof(Float_t)); + } + else { + memcpy(rgData->linprebuf, left_samples + num_samples - MAX_ORDER, + MAX_ORDER * sizeof(Float_t)); + memcpy(rgData->rinprebuf, right_samples + num_samples - MAX_ORDER, + MAX_ORDER * sizeof(Float_t)); + } + + return GAIN_ANALYSIS_OK; +} + + +static Float_t +analyzeResult(uint32_t const *Array, size_t len) +{ + uint32_t elems; + uint32_t upper; + uint32_t sum; + size_t i; + + elems = 0; + for (i = 0; i < len; i++) + elems += Array[i]; + if (elems == 0) + return GAIN_NOT_ENOUGH_SAMPLES; + + upper = (uint32_t) ceil(elems * (1. - RMS_PERCENTILE)); + sum = 0; + for (i = len; i-- > 0;) { + sum += Array[i]; + if (sum >= upper) { + break; + } + } + + return (Float_t) ((Float_t) PINK_REF - (Float_t) i / (Float_t) STEPS_per_dB); +} + + +Float_t +GetTitleGain(replaygain_t * rgData) +{ + Float_t retval; + unsigned int i; + + retval = analyzeResult(rgData->A, sizeof(rgData->A) / sizeof(*(rgData->A))); + + for (i = 0; i < sizeof(rgData->A) / sizeof(*(rgData->A)); i++) { + rgData->B[i] += rgData->A[i]; + rgData->A[i] = 0; + } + + for (i = 0; i < MAX_ORDER; i++) + rgData->linprebuf[i] = rgData->lstepbuf[i] + = rgData->loutbuf[i] + = rgData->rinprebuf[i] + = rgData->rstepbuf[i] + = rgData->routbuf[i] = 0.f; + + rgData->totsamp = 0; + rgData->lsum = rgData->rsum = 0.; + return retval; +} + +#if 0 +static Float_t GetAlbumGain(replaygain_t const* rgData); + +Float_t +GetAlbumGain(replaygain_t const* rgData) +{ + return analyzeResult(rgData->B, sizeof(rgData->B) / sizeof(*(rgData->B))); +} +#endif + +/* end of gain_analysis.c */ diff --git a/pkg/lame/clame/gain_analysis.h b/pkg/lame/clame/gain_analysis.h new file mode 100644 index 0000000..a6b56ab --- /dev/null +++ b/pkg/lame/clame/gain_analysis.h @@ -0,0 +1,109 @@ +/* + * ReplayGainAnalysis - analyzes input samples and give the recommended dB change + * Copyright (C) 2001 David Robinson and Glen Sawyer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * concept and filter values by David Robinson (David@Robinson.org) + * -- blame him if you think the idea is flawed + * coding by Glen Sawyer (mp3gain@hotmail.com) 735 W 255 N, Orem, UT 84057-4505 USA + * -- blame him if you think this runs too slowly, or the coding is otherwise flawed + * + * For an explanation of the concepts and the basic algorithms involved, go to: + * http://www.replaygain.org/ + */ + +#ifndef GAIN_ANALYSIS_H +#define GAIN_ANALYSIS_H + +#ifdef HAVE_INTTYPES_H +# include +#else +# ifdef HAVE_STDINT_H +# include +# endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + + typedef sample_t Float_t; /* Type used for filtering */ + + +#define PINK_REF 64.82 /* 298640883795 */ /* calibration value for 89dB */ + + +#define YULE_ORDER 10 +#define BUTTER_ORDER 2 +#define YULE_FILTER filterYule +#define BUTTER_FILTER filterButter +#define RMS_PERCENTILE 0.95 /* percentile which is louder than the proposed level */ +#define MAX_SAMP_FREQ 48000L /* maximum allowed sample frequency [Hz] */ +#define RMS_WINDOW_TIME_NUMERATOR 1L +#define RMS_WINDOW_TIME_DENOMINATOR 20L /* numerator / denominator = time slice size [s] */ +#define STEPS_per_dB 100 /* Table entries per dB */ +#define MAX_dB 120 /* Table entries for 0...MAX_dB (normal max. values are 70...80 dB) */ + + enum { GAIN_NOT_ENOUGH_SAMPLES = -24601, GAIN_ANALYSIS_ERROR = 0, GAIN_ANALYSIS_OK = + 1, INIT_GAIN_ANALYSIS_ERROR = 0, INIT_GAIN_ANALYSIS_OK = 1 + }; + + enum { MAX_ORDER = (BUTTER_ORDER > YULE_ORDER ? BUTTER_ORDER : YULE_ORDER) + , MAX_SAMPLES_PER_WINDOW = ((MAX_SAMP_FREQ * RMS_WINDOW_TIME_NUMERATOR) / RMS_WINDOW_TIME_DENOMINATOR + 1) /* max. Samples per Time slice */ + }; + + struct replaygain_data { + Float_t linprebuf[MAX_ORDER * 2]; + Float_t *linpre; /* left input samples, with pre-buffer */ + Float_t lstepbuf[MAX_SAMPLES_PER_WINDOW + MAX_ORDER]; + Float_t *lstep; /* left "first step" (i.e. post first filter) samples */ + Float_t loutbuf[MAX_SAMPLES_PER_WINDOW + MAX_ORDER]; + Float_t *lout; /* left "out" (i.e. post second filter) samples */ + Float_t rinprebuf[MAX_ORDER * 2]; + Float_t *rinpre; /* right input samples ... */ + Float_t rstepbuf[MAX_SAMPLES_PER_WINDOW + MAX_ORDER]; + Float_t *rstep; + Float_t routbuf[MAX_SAMPLES_PER_WINDOW + MAX_ORDER]; + Float_t *rout; + long sampleWindow; /* number of samples required to reach number of milliseconds required for RMS window */ + long totsamp; + double lsum; + double rsum; + int freqindex; + int first; + uint32_t A[STEPS_per_dB * MAX_dB]; + uint32_t B[STEPS_per_dB * MAX_dB]; + + }; +#ifndef replaygain_data_defined +#define replaygain_data_defined + typedef struct replaygain_data replaygain_t; +#endif + + + + + int InitGainAnalysis(replaygain_t * rgData, long samplefreq); + int AnalyzeSamples(replaygain_t * rgData, const Float_t * left_samples, + const Float_t * right_samples, size_t num_samples, int num_channels); + Float_t GetTitleGain(replaygain_t * rgData); + + +#ifdef __cplusplus +} +#endif +#endif /* GAIN_ANALYSIS_H */ diff --git a/pkg/lame/clame/id3tag.c b/pkg/lame/clame/id3tag.c new file mode 100644 index 0000000..ac48510 --- /dev/null +++ b/pkg/lame/clame/id3tag.c @@ -0,0 +1,1926 @@ +/* + * id3tag.c -- Write ID3 version 1 and 2 tags. + * + * Copyright (C) 2000 Don Melton + * Copyright (C) 2011-2017 Robert Hegemann + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + * HISTORY: This source file is part of LAME (see http://www.mp3dev.org) + * and was originally adapted by Conrad Sanderson + * from mp3info by Ricardo Cerqueira to write only ID3 version 1 + * tags. Don Melton COMPLETELY rewrote it to support version + * 2 tags and be more conformant to other standards while remaining flexible. + * + * NOTE: See http://id3.org/ for more information about ID3 tag formats. + */ + +/* $Id: id3tag.c,v 1.80 2017/08/28 15:39:51 robert Exp $ */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef STDC_HEADERS +# include +# include +# include +# include +#else +# ifndef HAVE_STRCHR +# define strchr index +# define strrchr rindex +# endif +char *strchr(), *strrchr(); +# ifndef HAVE_MEMCPY +# define memcpy(d, s, n) bcopy ((s), (d), (n)) +# endif +#endif + + +#include "lame.h" +#include "machine.h" +#include "encoder.h" +#include "id3tag.h" +#include "lame_global_flags.h" +#include "util.h" +#include "bitstream.h" + + +static const char *const genre_names[] = { + /* + * NOTE: The spelling of these genre names is identical to those found in + * Winamp and mp3info. + */ + "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge", + "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies", "Other", "Pop", "R&B", + "Rap", "Reggae", "Rock", "Techno", "Industrial", "Alternative", "Ska", + "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", + "Vocal", "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental", + "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise", "Alternative Rock", + "Bass", "Soul", "Punk", "Space", "Meditative", "Instrumental Pop", + "Instrumental Rock", "Ethnic", "Gothic", "Darkwave", "Techno-Industrial", + "Electronic", "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy", + "Cult", "Gangsta", "Top 40", "Christian Rap", "Pop/Funk", "Jungle", + "Native US", "Cabaret", "New Wave", "Psychedelic", "Rave", + "Showtunes", "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz", + "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock", "Folk", + "Folk-Rock", "National Folk", "Swing", "Fast Fusion", "Bebob", "Latin", + "Revival", "Celtic", "Bluegrass", "Avantgarde", "Gothic Rock", + "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock", + "Big Band", "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", + "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", + "Primus", "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba", + "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle", "Duet", + "Punk Rock", "Drum Solo", "A Cappella", "Euro-House", "Dance Hall", + "Goa", "Drum & Bass", "Club-House", "Hardcore", "Terror", "Indie", + "BritPop", "Negerpunk", "Polsk Punk", "Beat", "Christian Gangsta", + "Heavy Metal", "Black Metal", "Crossover", "Contemporary Christian", + "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "JPop", + "SynthPop" +}; + +#define GENRE_NAME_COUNT \ + ((int)(sizeof genre_names / sizeof (const char *const))) + +static const int genre_alpha_map[] = { + 123, 34, 74, 73, 99, 20, 40, 26, 145, 90, 116, 41, 135, 85, 96, 138, 89, 0, + 107, 132, 65, 88, 104, 102, 97, 136, 61, 141, 32, 1, 112, 128, 57, 140, 2, + 139, 58, 3, 125, 50, 22, 4, 55, 127, 122, 120, 98, 52, 48, 54, 124, 25, 84, + 80, 115, 81, 119, 5, 30, 36, 59, 126, 38, 49, 91, 6, 129, 79, 137, 7, 35, + 100, 131, 19, 33, 46, 47, 8, 29, 146, 63, 86, 71, 45, 142, 9, 77, 82, 64, + 133, 10, 66, 39, 11, 103, 12, 75, 134, 13, 53, 62, 109, 117, 23, 108, 92, + 67, 93, 43, 121, 15, 68, 14, 16, 76, 87, 118, 17, 78, 143, 114, 110, 69, 21, + 111, 95, 105, 42, 37, 24, 56, 44, 101, 83, 94, 106, 147, 113, 18, 51, 130, + 144, 60, 70, 31, 72, 27, 28 +}; + +#define GENRE_ALPHA_COUNT ((int)(sizeof genre_alpha_map / sizeof (int))) + +#define GENRE_INDEX_OTHER 12 + + +#define FRAME_ID(a, b, c, d) \ + ( ((unsigned long)(a) << 24) \ + | ((unsigned long)(b) << 16) \ + | ((unsigned long)(c) << 8) \ + | ((unsigned long)(d) << 0) ) + +typedef enum UsualStringIDs { ID_TITLE = FRAME_ID('T', 'I', 'T', '2') + , ID_ARTIST = FRAME_ID('T', 'P', 'E', '1') + , ID_ALBUM = FRAME_ID('T', 'A', 'L', 'B') + , ID_GENRE = FRAME_ID('T', 'C', 'O', 'N') + , ID_ENCODER = FRAME_ID('T', 'S', 'S', 'E') + , ID_PLAYLENGTH = FRAME_ID('T', 'L', 'E', 'N') + , ID_COMMENT = FRAME_ID('C', 'O', 'M', 'M') /* full text string */ +} UsualStringIDs; + +typedef enum NumericStringIDs { ID_DATE = FRAME_ID('T', 'D', 'A', 'T') /* "ddMM" */ + , ID_TIME = FRAME_ID('T', 'I', 'M', 'E') /* "hhmm" */ + , ID_TPOS = FRAME_ID('T', 'P', 'O', 'S') /* '0'-'9' and '/' allowed */ + , ID_TRACK = FRAME_ID('T', 'R', 'C', 'K') /* '0'-'9' and '/' allowed */ + , ID_YEAR = FRAME_ID('T', 'Y', 'E', 'R') /* "yyyy" */ +} NumericStringIDs; + +typedef enum MiscIDs { ID_TXXX = FRAME_ID('T', 'X', 'X', 'X') + , ID_WXXX = FRAME_ID('W', 'X', 'X', 'X') + , ID_SYLT = FRAME_ID('S', 'Y', 'L', 'T') + , ID_APIC = FRAME_ID('A', 'P', 'I', 'C') + , ID_GEOB = FRAME_ID('G', 'E', 'O', 'B') + , ID_PCNT = FRAME_ID('P', 'C', 'N', 'T') + , ID_AENC = FRAME_ID('A', 'E', 'N', 'C') + , ID_LINK = FRAME_ID('L', 'I', 'N', 'K') + , ID_ENCR = FRAME_ID('E', 'N', 'C', 'R') + , ID_GRID = FRAME_ID('G', 'R', 'I', 'D') + , ID_PRIV = FRAME_ID('P', 'R', 'I', 'V') + , ID_USLT = FRAME_ID('U', 'S', 'L', 'T') /* full text string */ + , ID_USER = FRAME_ID('U', 'S', 'E', 'R') /* full text string */ + , ID_PCST = FRAME_ID('P', 'C', 'S', 'T') /* iTunes Podcast indicator, only presence important */ + , ID_WFED = FRAME_ID('W', 'F', 'E', 'D') /* iTunes Podcast URL as TEXT FRAME !!! violates standard */ +} MiscIDs; + + +static int +frame_id_matches(int id, int mask) +{ + int result = 0, i, window = 0xff; + for (i = 0; i < 4; ++i, window <<= 8) { + int const mw = (mask & window); + int const iw = (id & window); + if (mw != 0 && mw != iw) { + result |= iw; + } + } + return result; +} + +static int +isFrameIdMatching(int id, int mask) +{ + return frame_id_matches(id, mask) == 0 ? 1 : 0; +} + +static int +test_tag_spec_flags(lame_internal_flags const *gfc, unsigned int tst) +{ + return (gfc->tag_spec.flags & tst) != 0u ? 1 : 0; +} + +#if 0 +static void +debug_tag_spec_flags(lame_internal_flags * gfc, const char* info) +{ + MSGF(gfc, "%s\n", info); + MSGF(gfc, "CHANGED_FLAG : %d\n", test_tag_spec_flags(gfc, CHANGED_FLAG )); + MSGF(gfc, "ADD_V2_FLAG : %d\n", test_tag_spec_flags(gfc, ADD_V2_FLAG )); + MSGF(gfc, "V1_ONLY_FLAG : %d\n", test_tag_spec_flags(gfc, V1_ONLY_FLAG )); + MSGF(gfc, "V2_ONLY_FLAG : %d\n", test_tag_spec_flags(gfc, V2_ONLY_FLAG )); + MSGF(gfc, "SPACE_V1_FLAG : %d\n", test_tag_spec_flags(gfc, SPACE_V1_FLAG)); + MSGF(gfc, "PAD_V2_FLAG : %d\n", test_tag_spec_flags(gfc, PAD_V2_FLAG )); +} +#endif + +static int +is_lame_internal_flags_null(lame_t gfp) +{ + return (gfp && gfp->internal_flags) ? 0 : 1; +} + +static int +id3v2_add_ucs2_lng(lame_t gfp, uint32_t frame_id, unsigned short const *desc, unsigned short const *text); +static int +id3v2_add_latin1_lng(lame_t gfp, uint32_t frame_id, char const *desc, char const *text); + + +static void +copyV1ToV2(lame_t gfp, int frame_id, char const *s) +{ + lame_internal_flags *gfc = gfp != 0 ? gfp->internal_flags : 0; + if (gfc != 0) { + unsigned int flags = gfc->tag_spec.flags; + id3v2_add_latin1_lng(gfp, frame_id, 0, s); + gfc->tag_spec.flags = flags; +#if 0 + debug_tag_spec_flags(gfc, "copyV1ToV2"); +#endif + } +} + + +static void +id3v2AddLameVersion(lame_t gfp) +{ + char buffer[1024]; + const char *b = get_lame_os_bitness(); + const char *v = get_lame_version(); + const char *u = get_lame_url(); + const size_t lenb = strlen(b); + + if (lenb > 0) { + sprintf(buffer, "LAME %s version %s (%s)", b, v, u); + } + else { + sprintf(buffer, "LAME version %s (%s)", v, u); + } + copyV1ToV2(gfp, ID_ENCODER, buffer); +} + +static void +id3v2AddAudioDuration(lame_t gfp, double ms) +{ + SessionConfig_t const *const cfg = &gfp->internal_flags->cfg; /* caller checked pointers */ + char buffer[1024]; + double const max_ulong = MAX_U_32_NUM; + unsigned long playlength_ms; + + ms *= 1000; + ms /= cfg->samplerate_in; + if (ms > max_ulong) { + playlength_ms = max_ulong; + } + else if (ms < 0) { + playlength_ms = 0; + } + else { + playlength_ms = ms; + } + sprintf(buffer, "%lu", playlength_ms); + copyV1ToV2(gfp, ID_PLAYLENGTH, buffer); +} + +void +id3tag_genre_list(void (*handler) (int, const char *, void *), void *cookie) +{ + if (handler) { + int i; + for (i = 0; i < GENRE_NAME_COUNT; ++i) { + if (i < GENRE_ALPHA_COUNT) { + int j = genre_alpha_map[i]; + handler(j, genre_names[j], cookie); + } + } + } +} + +#define GENRE_NUM_UNKNOWN 255 + + + +void +id3tag_init(lame_t gfp) +{ + lame_internal_flags *gfc = 0; + + if (is_lame_internal_flags_null(gfp)) { + return; + } + gfc = gfp->internal_flags; + free_id3tag(gfc); + memset(&gfc->tag_spec, 0, sizeof gfc->tag_spec); + gfc->tag_spec.genre_id3v1 = GENRE_NUM_UNKNOWN; + gfc->tag_spec.padding_size = 128; + id3v2AddLameVersion(gfp); +} + + + +void +id3tag_add_v2(lame_t gfp) +{ + lame_internal_flags *gfc = 0; + + if (is_lame_internal_flags_null(gfp)) { + return; + } + gfc = gfp->internal_flags; + gfc->tag_spec.flags &= ~V1_ONLY_FLAG; + gfc->tag_spec.flags |= ADD_V2_FLAG; +} + +void +id3tag_v1_only(lame_t gfp) +{ + lame_internal_flags *gfc = 0; + + if (is_lame_internal_flags_null(gfp)) { + return; + } + gfc = gfp->internal_flags; + gfc->tag_spec.flags &= ~(ADD_V2_FLAG | V2_ONLY_FLAG); + gfc->tag_spec.flags |= V1_ONLY_FLAG; +} + +void +id3tag_v2_only(lame_t gfp) +{ + lame_internal_flags *gfc = 0; + + if (is_lame_internal_flags_null(gfp)) { + return; + } + gfc = gfp->internal_flags; + gfc->tag_spec.flags &= ~V1_ONLY_FLAG; + gfc->tag_spec.flags |= V2_ONLY_FLAG; +} + +void +id3tag_space_v1(lame_t gfp) +{ + lame_internal_flags *gfc = 0; + + if (is_lame_internal_flags_null(gfp)) { + return; + } + gfc = gfp->internal_flags; + gfc->tag_spec.flags &= ~V2_ONLY_FLAG; + gfc->tag_spec.flags |= SPACE_V1_FLAG; +} + +void +id3tag_pad_v2(lame_t gfp) +{ + id3tag_set_pad(gfp, 128); +} + +void +id3tag_set_pad(lame_t gfp, size_t n) +{ + lame_internal_flags *gfc = 0; + + if (is_lame_internal_flags_null(gfp)) { + return; + } + gfc = gfp->internal_flags; + gfc->tag_spec.flags &= ~V1_ONLY_FLAG; + gfc->tag_spec.flags |= PAD_V2_FLAG; + gfc->tag_spec.flags |= ADD_V2_FLAG; + gfc->tag_spec.padding_size = (unsigned int)n; +} + +static int +hasUcs2ByteOrderMarker(unsigned short bom) +{ + if (bom == 0xFFFEu || bom == 0xFEFFu) { + return 1; + } + return 0; +} + + +static unsigned short +swap_bytes(unsigned short w) +{ + return (0xff00u & (w << 8)) | (0x00ffu & (w >> 8)); +} + + +static unsigned short +toLittleEndian(unsigned short bom, unsigned short c) +{ + if (bom == 0xFFFEu) { + return swap_bytes(c); + } + return c; +} + +static unsigned short +fromLatin1Char(const unsigned short* s, unsigned short c) +{ + if (s[0] == 0xFFFEu) { + return swap_bytes(c); + } + return c; +} + + +static size_t +local_strdup(char **dst, const char *src) +{ + if (dst == 0) { + return 0; + } + free(*dst); + *dst = 0; + if (src != 0) { + size_t n; + for (n = 0; src[n] != 0; ++n) { /* calc src string length */ + } + if (n > 0) { /* string length without zero termination */ + assert(sizeof(*src) == sizeof(**dst)); + *dst = lame_calloc(char, n + 1); + if (*dst != 0) { + memcpy(*dst, src, n * sizeof(**dst)); + (*dst)[n] = 0; + return n; + } + } + } + return 0; +} + +static size_t +local_ucs2_strdup(unsigned short **dst, unsigned short const *src) +{ + if (dst == 0) { + return 0; + } + free(*dst); /* free old string pointer */ + *dst = 0; + if (src != 0) { + size_t n; + for (n = 0; src[n] != 0; ++n) { /* calc src string length */ + } + if (n > 0) { /* string length without zero termination */ + assert(sizeof(*src) >= 2); + assert(sizeof(*src) == sizeof(**dst)); + *dst = lame_calloc(unsigned short, n + 1); + if (*dst != 0) { + memcpy(*dst, src, n * sizeof(**dst)); + (*dst)[n] = 0; + return n; + } + } + } + return 0; +} + + +static size_t +local_ucs2_strlen(unsigned short const *s) +{ + size_t n = 0; + if (s != 0) { + while (*s++) { + ++n; + } + } + return n; +} + + +static size_t +local_ucs2_substr(unsigned short** dst, unsigned short const* src, size_t start, size_t end) +{ + size_t const len = 1 + 1 + ((start < end) ? (end - start) : 0); + size_t n = 0; + unsigned short *ptr = lame_calloc(unsigned short, len); + *dst = ptr; + if (ptr == 0 || src == 0) { + return 0; + } + if (hasUcs2ByteOrderMarker(src[0])) { + ptr[n++] = src[0]; + if (start == 0) { + ++start; + } + } + while (start < end) { + ptr[n++] = src[start++]; + } + ptr[n] = 0; + return n; +} + +static int +local_ucs2_pos(unsigned short const* str, unsigned short c) +{ + int i; + for (i = 0; str != 0 && str[i] != 0; ++i) { + if (str[i] == c) { + return i; + } + } + return -1; +} + +static int +local_char_pos(char const* str, char c) +{ + int i; + for (i = 0; str != 0 && str[i] != 0; ++i) { + if (str[i] == c) { + return i; + } + } + return -1; +} + +static int +maybeLatin1(unsigned short const* text) +{ + if (text) { + unsigned short bom = *text++; + while (*text) { + unsigned short c = toLittleEndian(bom, *text++); + if (c > 0x00fe) return 0; + } + } + return 1; +} + +static int searchGenre(char const* genre); +static int sloppySearchGenre(char const* genre); + +static int +lookupGenre(char const* genre) +{ + char *str; + int num = strtol(genre, &str, 10); + /* is the input a string or a valid number? */ + if (*str) { + num = searchGenre(genre); + if (num == GENRE_NAME_COUNT) { + num = sloppySearchGenre(genre); + } + if (num == GENRE_NAME_COUNT) { + return -2; /* no common genre text found */ + } + } + else { + if ((num < 0) || (num >= GENRE_NAME_COUNT)) { + return -1; /* number unknown */ + } + } + return num; +} + +static unsigned char * +writeLoBytes(unsigned char *frame, unsigned short const *str, size_t n); + +static char* +local_strdup_utf16_to_latin1(unsigned short const* utf16) +{ + size_t len = local_ucs2_strlen(utf16); + unsigned char* latin1 = lame_calloc(unsigned char, len+1); + writeLoBytes(latin1, utf16, len); + return (char*)latin1; +} + + +static int +id3tag_set_genre_utf16(lame_t gfp, unsigned short const* text) +{ + lame_internal_flags* gfc = gfp->internal_flags; + int ret; + if (text == 0) { + return -3; + } + if (!hasUcs2ByteOrderMarker(text[0])) { + return -3; + } + if (maybeLatin1(text)) { + char* latin1 = local_strdup_utf16_to_latin1(text); + int num = lookupGenre(latin1); + free(latin1); + if (num == -1) return -1; /* number out of range */ + if (num >= 0) { /* common genre found */ + gfc->tag_spec.flags |= CHANGED_FLAG; + gfc->tag_spec.genre_id3v1 = num; + copyV1ToV2(gfp, ID_GENRE, genre_names[num]); + return 0; + } + } + ret = id3v2_add_ucs2_lng(gfp, ID_GENRE, 0, text); + if (ret == 0) { + gfc->tag_spec.flags |= CHANGED_FLAG; + gfc->tag_spec.genre_id3v1 = GENRE_INDEX_OTHER; + } + return ret; +} + +/* +Some existing options for ID3 tag can be specified by --tv option +as follows. +--tt , --tv TIT2=value +--ta , --tv TPE1=value +--tl , --tv TALB=value +--ty , --tv TYER=value +--tn , --tv TRCK=value +--tg , --tv TCON=value +(although some are not exactly same)*/ + +int +id3tag_set_albumart(lame_t gfp, const char *image, size_t size) +{ + int mimetype = MIMETYPE_NONE; + lame_internal_flags *gfc = 0; + + if (is_lame_internal_flags_null(gfp)) { + return 0; + } + gfc = gfp->internal_flags; + + if (image != 0) { + unsigned char const *data = (unsigned char const *) image; + /* determine MIME type from the actual image data */ + if (2 < size && data[0] == 0xFF && data[1] == 0xD8) { + mimetype = MIMETYPE_JPEG; + } + else if (4 < size && data[0] == 0x89 && strncmp((const char *) &data[1], "PNG", 3) == 0) { + mimetype = MIMETYPE_PNG; + } + else if (4 < size && strncmp((const char *) data, "GIF8", 4) == 0) { + mimetype = MIMETYPE_GIF; + } + else { + return -1; + } + } + if (gfc->tag_spec.albumart != 0) { + free(gfc->tag_spec.albumart); + gfc->tag_spec.albumart = 0; + gfc->tag_spec.albumart_size = 0; + gfc->tag_spec.albumart_mimetype = MIMETYPE_NONE; + } + if (size < 1 || mimetype == MIMETYPE_NONE) { + return 0; + } + gfc->tag_spec.albumart = lame_calloc(unsigned char, size); + if (gfc->tag_spec.albumart != 0) { + memcpy(gfc->tag_spec.albumart, image, size); + gfc->tag_spec.albumart_size = (unsigned int)size; + gfc->tag_spec.albumart_mimetype = mimetype; + gfc->tag_spec.flags |= CHANGED_FLAG; + id3tag_add_v2(gfp); + } + return 0; +} + +static unsigned char * +set_4_byte_value(unsigned char *bytes, uint32_t value) +{ + int i; + for (i = 3; i >= 0; --i) { + bytes[i] = value & 0xffUL; + value >>= 8; + } + return bytes + 4; +} + +static uint32_t +toID3v2TagId(char const *s) +{ + unsigned int i, x = 0; + if (s == 0) { + return 0; + } + for (i = 0; i < 4 && s[i] != 0; ++i) { + char const c = s[i]; + unsigned int const u = 0x0ff & c; + x <<= 8; + x |= u; + if (c < 'A' || 'Z' < c) { + if (c < '0' || '9' < c) { + return 0; + } + } + } + return x; +} + +static uint32_t +toID3v2TagId_ucs2(unsigned short const *s) +{ + unsigned int i, x = 0; + unsigned short bom = 0; + if (s == 0) { + return 0; + } + bom = s[0]; + if (hasUcs2ByteOrderMarker(bom)) { + ++s; + } + for (i = 0; i < 4 && s[i] != 0; ++i) { + unsigned short const c = toLittleEndian(bom, s[i]); + if (c < 'A' || 'Z' < c) { + if (c < '0' || '9' < c) { + return 0; + } + } + x <<= 8; + x |= c; + } + return x; +} + +#if 0 +static int +isNumericString(uint32_t frame_id) +{ + switch (frame_id) { + case ID_DATE: + case ID_TIME: + case ID_TPOS: + case ID_TRACK: + case ID_YEAR: + return 1; + } + return 0; +} +#endif + +static int +isMultiFrame(uint32_t frame_id) +{ + switch (frame_id) { + case ID_TXXX: + case ID_WXXX: + case ID_COMMENT: + case ID_SYLT: + case ID_APIC: + case ID_GEOB: + case ID_PCNT: + case ID_AENC: + case ID_LINK: + case ID_ENCR: + case ID_GRID: + case ID_PRIV: + return 1; + } + return 0; +} + +#if 0 +static int +isFullTextString(int frame_id) +{ + switch (frame_id) { + case ID_VSLT: + case ID_COMMENT: + return 1; + } + return 0; +} +#endif + +static FrameDataNode * +findNode(id3tag_spec const *tag, uint32_t frame_id, FrameDataNode const *last) +{ + FrameDataNode *node = last ? last->nxt : tag->v2_head; + while (node != 0) { + if (node->fid == frame_id) { + return node; + } + node = node->nxt; + } + return 0; +} + +static void +appendNode(id3tag_spec * tag, FrameDataNode * node) +{ + if (tag->v2_tail == 0 || tag->v2_head == 0) { + tag->v2_head = node; + tag->v2_tail = node; + } + else { + tag->v2_tail->nxt = node; + tag->v2_tail = node; + } +} + +static void +setLang(char *dst, char const *src) +{ + int i; + if (src == 0 || src[0] == 0) { + dst[0] = 'e'; + dst[1] = 'n'; + dst[2] = 'g'; + } + else { + for (i = 0; i < 3 && src && *src; ++i) { + dst[i] = src[i]; + } + for (; i < 3; ++i) { + dst[i] = ' '; + } + } +} + +static int +isSameLang(char const *l1, char const *l2) +{ + char d[3]; + int i; + setLang(d, l2); + for (i = 0; i < 3; ++i) { + char a = tolower(l1[i]); + char b = tolower(d[i]); + if (a < ' ') + a = ' '; + if (b < ' ') + b = ' '; + if (a != b) { + return 0; + } + } + return 1; +} + +static int +isSameDescriptor(FrameDataNode const *node, char const *dsc) +{ + size_t i; + if (node->dsc.enc == 1 && node->dsc.dim > 0) { + return 0; + } + for (i = 0; i < node->dsc.dim; ++i) { + if (!dsc || node->dsc.ptr.l[i] != dsc[i]) { + return 0; + } + } + return 1; +} + +static int +isSameDescriptorUcs2(FrameDataNode const *node, unsigned short const *dsc) +{ + size_t i; + if (node->dsc.enc != 1 && node->dsc.dim > 0) { + return 0; + } + for (i = 0; i < node->dsc.dim; ++i) { + if (!dsc || node->dsc.ptr.u[i] != dsc[i]) { + return 0; + } + } + return 1; +} + +static int +id3v2_add_ucs2(lame_t gfp, uint32_t frame_id, char const *lng, unsigned short const *desc, unsigned short const *text) +{ + lame_internal_flags *gfc = gfp != 0 ? gfp->internal_flags : 0; + if (gfc != 0) { + FrameDataNode *node = findNode(&gfc->tag_spec, frame_id, 0); + char lang[4]; + setLang(lang, lng); + if (isMultiFrame(frame_id)) { + while (node) { + if (isSameLang(node->lng, lang)) { + if (isSameDescriptorUcs2(node, desc)) { + break; + } + } + node = findNode(&gfc->tag_spec, frame_id, node); + } + } + if (node == 0) { + node = lame_calloc(FrameDataNode, 1); + if (node == 0) { + return -254; /* memory problem */ + } + appendNode(&gfc->tag_spec, node); + } + node->fid = frame_id; + setLang(node->lng, lang); + node->dsc.dim = local_ucs2_strdup(&node->dsc.ptr.u, desc); + node->dsc.enc = 1; + node->txt.dim = local_ucs2_strdup(&node->txt.ptr.u, text); + node->txt.enc = 1; + gfc->tag_spec.flags |= (CHANGED_FLAG | ADD_V2_FLAG); + return 0; + } + return -255; +} + +static int +id3v2_add_latin1(lame_t gfp, uint32_t frame_id, char const *lng, char const *desc, char const *text) +{ + lame_internal_flags *gfc = gfp != 0 ? gfp->internal_flags : 0; + if (gfc != 0) { + FrameDataNode *node = findNode(&gfc->tag_spec, frame_id, 0); + char lang[4]; + setLang(lang, lng); + if (isMultiFrame(frame_id)) { + while (node) { + if (isSameLang(node->lng, lang)) { + if (isSameDescriptor(node, desc)) { + break; + } + } + node = findNode(&gfc->tag_spec, frame_id, node); + } + } + if (node == 0) { + node = lame_calloc(FrameDataNode, 1); + if (node == 0) { + return -254; /* memory problem */ + } + appendNode(&gfc->tag_spec, node); + } + node->fid = frame_id; + setLang(node->lng, lang); + node->dsc.dim = local_strdup(&node->dsc.ptr.l, desc); + node->dsc.enc = 0; + node->txt.dim = local_strdup(&node->txt.ptr.l, text); + node->txt.enc = 0; + gfc->tag_spec.flags |= (CHANGED_FLAG | ADD_V2_FLAG); + return 0; + } + return -255; +} + +static char const* +id3v2_get_language(lame_t gfp) +{ + lame_internal_flags const* gfc = gfp ? gfp->internal_flags : 0; + if (gfc) return gfc->tag_spec.language; + return 0; +} + +static int +id3v2_add_ucs2_lng(lame_t gfp, uint32_t frame_id, unsigned short const *desc, unsigned short const *text) +{ + char const* lang = id3v2_get_language(gfp); + return id3v2_add_ucs2(gfp, frame_id, lang, desc, text); +} + +static int +id3v2_add_latin1_lng(lame_t gfp, uint32_t frame_id, char const *desc, char const *text) +{ + char const* lang = id3v2_get_language(gfp); + return id3v2_add_latin1(gfp, frame_id, lang, desc, text); +} + +static int +id3tag_set_userinfo_latin1(lame_t gfp, uint32_t id, char const *fieldvalue) +{ + char const separator = '='; + int rc = -7; + int a = local_char_pos(fieldvalue, separator); + if (a >= 0) { + char* dup = 0; + local_strdup(&dup, fieldvalue); + dup[a] = 0; + rc = id3v2_add_latin1_lng(gfp, id, dup, dup+a+1); + free(dup); + } + return rc; +} + +static int +id3tag_set_userinfo_ucs2(lame_t gfp, uint32_t id, unsigned short const *fieldvalue) +{ + unsigned short const separator = fromLatin1Char(fieldvalue,'='); + int rc = -7; + size_t b = local_ucs2_strlen(fieldvalue); + int a = local_ucs2_pos(fieldvalue, separator); + if (a >= 0) { + unsigned short* dsc = 0, *val = 0; + local_ucs2_substr(&dsc, fieldvalue, 0, a); + local_ucs2_substr(&val, fieldvalue, a+1, b); + rc = id3v2_add_ucs2_lng(gfp, id, dsc, val); + free(dsc); + free(val); + } + return rc; +} + +int +id3tag_set_textinfo_utf16(lame_t gfp, char const *id, unsigned short const *text) +{ + uint32_t const frame_id = toID3v2TagId(id); + if (frame_id == 0) { + return -1; + } + if (is_lame_internal_flags_null(gfp)) { + return 0; + } + if (text == 0) { + return 0; + } + if (!hasUcs2ByteOrderMarker(text[0])) { + return -3; /* BOM missing */ + } + if (frame_id == ID_TXXX || frame_id == ID_WXXX || frame_id == ID_COMMENT) { + return id3tag_set_userinfo_ucs2(gfp, frame_id, text); + } + if (frame_id == ID_GENRE) { + return id3tag_set_genre_utf16(gfp, text); + } + if (frame_id == ID_PCST) { + return id3v2_add_ucs2_lng(gfp, frame_id, 0, text); + } + if (frame_id == ID_USER) { + return id3v2_add_ucs2_lng(gfp, frame_id, text, 0); + } + if (frame_id == ID_WFED) { + return id3v2_add_ucs2_lng(gfp, frame_id, text, 0); /* iTunes expects WFED to be a text frame */ + } + if (isFrameIdMatching(frame_id, FRAME_ID('T', 0, 0, 0)) + ||isFrameIdMatching(frame_id, FRAME_ID('W', 0, 0, 0))) { +#if 0 + if (isNumericString(frame_id)) { + return -2; /* must be Latin-1 encoded */ + } +#endif + return id3v2_add_ucs2_lng(gfp, frame_id, 0, text); + } + return -255; /* not supported by now */ +} + +extern int +id3tag_set_textinfo_ucs2(lame_t gfp, char const *id, unsigned short const *text); + +int +id3tag_set_textinfo_ucs2(lame_t gfp, char const *id, unsigned short const *text) +{ + return id3tag_set_textinfo_utf16(gfp, id, text); +} + +int +id3tag_set_textinfo_latin1(lame_t gfp, char const *id, char const *text) +{ + uint32_t const frame_id = toID3v2TagId(id); + if (frame_id == 0) { + return -1; + } + if (is_lame_internal_flags_null(gfp)) { + return 0; + } + if (text == 0) { + return 0; + } + if (frame_id == ID_TXXX || frame_id == ID_WXXX || frame_id == ID_COMMENT) { + return id3tag_set_userinfo_latin1(gfp, frame_id, text); + } + if (frame_id == ID_GENRE) { + return id3tag_set_genre(gfp, text); + } + if (frame_id == ID_PCST) { + return id3v2_add_latin1_lng(gfp, frame_id, 0, text); + } + if (frame_id == ID_USER) { + return id3v2_add_latin1_lng(gfp, frame_id, text, 0); + } + if (frame_id == ID_WFED) { + return id3v2_add_latin1_lng(gfp, frame_id, text, 0); /* iTunes expects WFED to be a text frame */ + } + if (isFrameIdMatching(frame_id, FRAME_ID('T', 0, 0, 0)) + ||isFrameIdMatching(frame_id, FRAME_ID('W', 0, 0, 0))) { + return id3v2_add_latin1_lng(gfp, frame_id, 0, text); + } + return -255; /* not supported by now */ +} + + +int +id3tag_set_comment_latin1(lame_t gfp, char const *lang, char const *desc, char const *text) +{ + if (is_lame_internal_flags_null(gfp)) { + return 0; + } + return id3v2_add_latin1(gfp, ID_COMMENT, lang, desc, text); +} + + +int +id3tag_set_comment_utf16(lame_t gfp, char const *lang, unsigned short const *desc, unsigned short const *text) +{ + if (is_lame_internal_flags_null(gfp)) { + return 0; + } + return id3v2_add_ucs2(gfp, ID_COMMENT, lang, desc, text); +} + +extern int +id3tag_set_comment_ucs2(lame_t gfp, char const *lang, unsigned short const *desc, unsigned short const *text); + + +int +id3tag_set_comment_ucs2(lame_t gfp, char const *lang, unsigned short const *desc, unsigned short const *text) +{ + if (is_lame_internal_flags_null(gfp)) { + return 0; + } + return id3tag_set_comment_utf16(gfp, lang, desc, text); +} + + +void +id3tag_set_title(lame_t gfp, const char *title) +{ + lame_internal_flags *gfc = gfp != 0 ? gfp->internal_flags : 0; + if (gfc && title && *title) { + local_strdup(&gfc->tag_spec.title, title); + gfc->tag_spec.flags |= CHANGED_FLAG; + copyV1ToV2(gfp, ID_TITLE, title); + } +} + +void +id3tag_set_artist(lame_t gfp, const char *artist) +{ + lame_internal_flags *gfc = gfp != 0 ? gfp->internal_flags : 0; + if (gfc && artist && *artist) { + local_strdup(&gfc->tag_spec.artist, artist); + gfc->tag_spec.flags |= CHANGED_FLAG; + copyV1ToV2(gfp, ID_ARTIST, artist); + } +} + +void +id3tag_set_album(lame_t gfp, const char *album) +{ + lame_internal_flags *gfc = gfp != 0 ? gfp->internal_flags : 0; + if (gfc && album && *album) { + local_strdup(&gfc->tag_spec.album, album); + gfc->tag_spec.flags |= CHANGED_FLAG; + copyV1ToV2(gfp, ID_ALBUM, album); + } +} + +void +id3tag_set_year(lame_t gfp, const char *year) +{ + lame_internal_flags *gfc = gfp != 0 ? gfp->internal_flags : 0; + if (gfc && year && *year) { + int num = atoi(year); + if (num < 0) { + num = 0; + } + /* limit a year to 4 digits so it fits in a version 1 tag */ + if (num > 9999) { + num = 9999; + } + if (num) { + gfc->tag_spec.year = num; + gfc->tag_spec.flags |= CHANGED_FLAG; + } + copyV1ToV2(gfp, ID_YEAR, year); + } +} + +void +id3tag_set_comment(lame_t gfp, const char *comment) +{ + lame_internal_flags *gfc = gfp != 0 ? gfp->internal_flags : 0; + if (gfc && comment && *comment) { + local_strdup(&gfc->tag_spec.comment, comment); + gfc->tag_spec.flags |= CHANGED_FLAG; + { + uint32_t const flags = gfc->tag_spec.flags; + id3v2_add_latin1_lng(gfp, ID_COMMENT, "", comment); + gfc->tag_spec.flags = flags; + } + } +} + +int +id3tag_set_track(lame_t gfp, const char *track) +{ + char const *trackcount; + lame_internal_flags *gfc = gfp != 0 ? gfp->internal_flags : 0; + int ret = 0; + + if (gfc && track && *track) { + int num = atoi(track); + /* check for valid ID3v1 track number range */ + if (num < 1 || num > 255) { + num = 0; + ret = -1; /* track number out of ID3v1 range, ignored for ID3v1 */ + gfc->tag_spec.flags |= (CHANGED_FLAG | ADD_V2_FLAG); + } + if (num) { + gfc->tag_spec.track_id3v1 = num; + gfc->tag_spec.flags |= CHANGED_FLAG; + } + /* Look for the total track count after a "/", same restrictions */ + trackcount = strchr(track, '/'); + if (trackcount && *trackcount) { + gfc->tag_spec.flags |= (CHANGED_FLAG | ADD_V2_FLAG); + } + copyV1ToV2(gfp, ID_TRACK, track); + } + return ret; +} + +/* would use real "strcasecmp" but it isn't portable */ +static int +local_strcasecmp(const char *s1, const char *s2) +{ + unsigned char c1; + unsigned char c2; + do { + c1 = tolower(*s1); + c2 = tolower(*s2); + if (!c1) { + break; + } + ++s1; + ++s2; + } while (c1 == c2); + return c1 - c2; +} + + +static +const char* nextUpperAlpha(const char* p, char x) +{ + char c; + for(c = toupper(*p); *p != 0; c = toupper(*++p)) { + if ('A' <= c && c <= 'Z') { + if (c != x) { + return p; + } + } + } + return p; +} + + +static int +sloppyCompared(const char* p, const char* q) +{ + char cp, cq; + p = nextUpperAlpha(p, 0); + q = nextUpperAlpha(q, 0); + cp = toupper(*p); + cq = toupper(*q); + while (cp == cq) { + if (cp == 0) { + return 1; + } + if (p[1] == '.') { /* some abbrevation */ + while (*q && *q++ != ' ') { + } + } + p = nextUpperAlpha(p, cp); + q = nextUpperAlpha(q, cq); + cp = toupper(*p); + cq = toupper(*q); + } + return 0; +} + + +static int +sloppySearchGenre(const char *genre) +{ + int i; + for (i = 0; i < GENRE_NAME_COUNT; ++i) { + if (sloppyCompared(genre, genre_names[i])) { + return i; + } + } + return GENRE_NAME_COUNT; +} + + +static int +searchGenre(const char* genre) +{ + int i; + for (i = 0; i < GENRE_NAME_COUNT; ++i) { + if (!local_strcasecmp(genre, genre_names[i])) { + return i; + } + } + return GENRE_NAME_COUNT; +} + + +int +id3tag_set_genre(lame_t gfp, const char *genre) +{ + lame_internal_flags *gfc = gfp != 0 ? gfp->internal_flags : 0; + int ret = 0; + if (gfc && genre && *genre) { + int const num = lookupGenre(genre); + if (num == -1) return num; + gfc->tag_spec.flags |= CHANGED_FLAG; + if (num >= 0) { + gfc->tag_spec.genre_id3v1 = num; + genre = genre_names[num]; + } + else { + gfc->tag_spec.genre_id3v1 = GENRE_INDEX_OTHER; + gfc->tag_spec.flags |= ADD_V2_FLAG; + } + copyV1ToV2(gfp, ID_GENRE, genre); + } + return ret; +} + + +static size_t +sizeOfNode(FrameDataNode const *node) +{ + size_t n = 0; + if (node) { + n = 10; /* header size */ + n += 1; /* text encoding flag */ + switch (node->txt.enc) { + default: + case 0: + if (node->dsc.dim > 0) { + n += node->dsc.dim + 1; + } + n += node->txt.dim; + break; + case 1: + if (node->dsc.dim > 0) { + n += (node->dsc.dim+1) * 2; + } + n += node->txt.dim * 2; + break; + } + } + return n; +} + +static size_t +sizeOfCommentNode(FrameDataNode const *node) +{ + size_t n = 0; + if (node) { + n = 10; /* header size */ + n += 1; /* text encoding flag */ + n += 3; /* language */ + switch (node->dsc.enc) { + default: + case 0: + n += 1 + node->dsc.dim; + break; + case 1: + n += 2 + node->dsc.dim * 2; + break; + } + switch (node->txt.enc) { + default: + case 0: + n += node->txt.dim; + break; + case 1: + n += node->txt.dim * 2; + break; + } + } + return n; +} + +static size_t +sizeOfWxxxNode(FrameDataNode const *node) +{ + size_t n = 0; + if (node) { + n = 10; /* header size */ + if (node->dsc.dim > 0) { + n += 1; /* text encoding flag */ + switch (node->dsc.enc) { + default: + case 0: + n += 1 + node->dsc.dim; + break; + case 1: + n += 2 + node->dsc.dim * 2; + break; + } + } + if (node->txt.dim > 0) { + switch (node->txt.enc) { + default: + case 0: + n += node->txt.dim; + break; + case 1: + n += node->txt.dim - 1; /* UCS2 -> Latin1, skip BOM */ + break; + } + } + } + return n; +} + +static unsigned char * +writeChars(unsigned char *frame, char const *str, size_t n) +{ + while (n--) { + *frame++ = *str++; + } + return frame; +} + +static unsigned char * +writeUcs2s(unsigned char *frame, unsigned short const *str, size_t n) +{ + if (n > 0) { + unsigned short const bom = *str; + while (n--) { + unsigned short const c = toLittleEndian(bom, *str++); + *frame++ = 0x00ffu & c; + *frame++ = 0x00ffu & (c >> 8); + } + } + return frame; +} + +static unsigned char * +writeLoBytes(unsigned char *frame, unsigned short const *str, size_t n) +{ + if (n > 0) { + unsigned short const bom = *str; + if (hasUcs2ByteOrderMarker(bom)) { + str++; n--; /* skip BOM */ + } + while (n--) { + unsigned short const c = toLittleEndian(bom, *str++); + if (c < 0x0020u || 0x00ffu < c) { + *frame++ = 0x0020; /* blank */ + } + else { + *frame++ = c; + } + } + } + return frame; +} + +static unsigned char * +set_frame_comment(unsigned char *frame, FrameDataNode const *node) +{ + size_t const n = sizeOfCommentNode(node); + if (n > 10) { + frame = set_4_byte_value(frame, node->fid); + frame = set_4_byte_value(frame, (uint32_t) (n - 10)); + /* clear 2-byte header flags */ + *frame++ = 0; + *frame++ = 0; + /* encoding descriptor byte */ + *frame++ = node->txt.enc == 1 ? 1 : 0; + /* 3 bytes language */ + *frame++ = node->lng[0]; + *frame++ = node->lng[1]; + *frame++ = node->lng[2]; + /* descriptor with zero byte(s) separator */ + if (node->dsc.enc != 1) { + frame = writeChars(frame, node->dsc.ptr.l, node->dsc.dim); + *frame++ = 0; + } + else { + frame = writeUcs2s(frame, node->dsc.ptr.u, node->dsc.dim); + *frame++ = 0; + *frame++ = 0; + } + /* comment full text */ + if (node->txt.enc != 1) { + frame = writeChars(frame, node->txt.ptr.l, node->txt.dim); + } + else { + frame = writeUcs2s(frame, node->txt.ptr.u, node->txt.dim); + } + } + return frame; +} + +static unsigned char * +set_frame_custom2(unsigned char *frame, FrameDataNode const *node) +{ + size_t const n = sizeOfNode(node); + if (n > 10) { + frame = set_4_byte_value(frame, node->fid); + frame = set_4_byte_value(frame, (unsigned long) (n - 10)); + /* clear 2-byte header flags */ + *frame++ = 0; + *frame++ = 0; + /* clear 1 encoding descriptor byte to indicate ISO-8859-1 format */ + *frame++ = node->txt.enc == 1 ? 1 : 0; + if (node->dsc.dim > 0) { + if (node->dsc.enc != 1) { + frame = writeChars(frame, node->dsc.ptr.l, node->dsc.dim); + *frame++ = 0; + } + else { + frame = writeUcs2s(frame, node->dsc.ptr.u, node->dsc.dim); + *frame++ = 0; + *frame++ = 0; + } + } + if (node->txt.enc != 1) { + frame = writeChars(frame, node->txt.ptr.l, node->txt.dim); + } + else { + frame = writeUcs2s(frame, node->txt.ptr.u, node->txt.dim); + } + } + return frame; +} + +static unsigned char * +set_frame_wxxx(unsigned char *frame, FrameDataNode const *node) +{ + size_t const n = sizeOfWxxxNode(node); + if (n > 10) { + frame = set_4_byte_value(frame, node->fid); + frame = set_4_byte_value(frame, (unsigned long) (n - 10)); + /* clear 2-byte header flags */ + *frame++ = 0; + *frame++ = 0; + if (node->dsc.dim > 0) { + /* clear 1 encoding descriptor byte to indicate ISO-8859-1 format */ + *frame++ = node->dsc.enc == 1 ? 1 : 0; + if (node->dsc.enc != 1) { + frame = writeChars(frame, node->dsc.ptr.l, node->dsc.dim); + *frame++ = 0; + } + else { + frame = writeUcs2s(frame, node->dsc.ptr.u, node->dsc.dim); + *frame++ = 0; + *frame++ = 0; + } + } + if (node->txt.enc != 1) { + frame = writeChars(frame, node->txt.ptr.l, node->txt.dim); + } + else { + frame = writeLoBytes(frame, node->txt.ptr.u, node->txt.dim); + } + } + return frame; +} + +static unsigned char * +set_frame_apic(unsigned char *frame, const char *mimetype, const unsigned char *data, size_t size) +{ + /* ID3v2.3 standard APIC frame: + *
+ * Text encoding $xx + * MIME type $00 + * Picture type $xx + * Description $00 (00) + * Picture data + */ + if (mimetype && data && size) { + frame = set_4_byte_value(frame, FRAME_ID('A', 'P', 'I', 'C')); + frame = set_4_byte_value(frame, (unsigned long) (4 + strlen(mimetype) + size)); + /* clear 2-byte header flags */ + *frame++ = 0; + *frame++ = 0; + /* clear 1 encoding descriptor byte to indicate ISO-8859-1 format */ + *frame++ = 0; + /* copy mime_type */ + while (*mimetype) { + *frame++ = *mimetype++; + } + *frame++ = 0; + /* set picture type to 0 */ + *frame++ = 0; + /* empty description field */ + *frame++ = 0; + /* copy the image data */ + while (size--) { + *frame++ = *data++; + } + } + return frame; +} + +int +id3tag_set_fieldvalue(lame_t gfp, const char *fieldvalue) +{ + if (is_lame_internal_flags_null(gfp)) { + return 0; + } + if (fieldvalue && *fieldvalue) { + if (strlen(fieldvalue) < 5 || fieldvalue[4] != '=') { + return -1; + } + return id3tag_set_textinfo_latin1(gfp, fieldvalue, &fieldvalue[5]); + } + return 0; +} + +int +id3tag_set_fieldvalue_utf16(lame_t gfp, const unsigned short *fieldvalue) +{ + if (is_lame_internal_flags_null(gfp)) { + return 0; + } + if (fieldvalue && *fieldvalue) { + size_t dx = hasUcs2ByteOrderMarker(fieldvalue[0]); + unsigned short const separator = fromLatin1Char(fieldvalue, '='); + char fid[5] = {0,0,0,0,0}; + uint32_t const frame_id = toID3v2TagId_ucs2(fieldvalue); + if (local_ucs2_strlen(fieldvalue) < (5+dx) || fieldvalue[4+dx] != separator) { + return -1; + } + fid[0] = (frame_id >> 24) & 0x0ff; + fid[1] = (frame_id >> 16) & 0x0ff; + fid[2] = (frame_id >> 8) & 0x0ff; + fid[3] = frame_id & 0x0ff; + if (frame_id != 0) { + unsigned short* txt = 0; + int rc; + local_ucs2_substr(&txt, fieldvalue, dx+5, local_ucs2_strlen(fieldvalue)); + rc = id3tag_set_textinfo_utf16(gfp, fid, txt); + free(txt); + return rc; + } + } + return -1; +} + +extern int +id3tag_set_fieldvalue_ucs2(lame_t gfp, const unsigned short *fieldvalue); + +int +id3tag_set_fieldvalue_ucs2(lame_t gfp, const unsigned short *fieldvalue) +{ + if (is_lame_internal_flags_null(gfp)) { + return 0; + } + return id3tag_set_fieldvalue_utf16(gfp, fieldvalue); +} + +size_t +lame_get_id3v2_tag(lame_t gfp, unsigned char *buffer, size_t size) +{ + lame_internal_flags *gfc = 0; + + if (is_lame_internal_flags_null(gfp)) { + return 0; + } + gfc = gfp->internal_flags; + if (test_tag_spec_flags(gfc, V1_ONLY_FLAG)) { + return 0; + } +#if 0 + debug_tag_spec_flags(gfc, "lame_get_id3v2_tag"); +#endif + { + int usev2 = test_tag_spec_flags(gfc, ADD_V2_FLAG | V2_ONLY_FLAG); + /* calculate length of four fields which may not fit in verion 1 tag */ + size_t title_length = gfc->tag_spec.title ? strlen(gfc->tag_spec.title) : 0; + size_t artist_length = gfc->tag_spec.artist ? strlen(gfc->tag_spec.artist) : 0; + size_t album_length = gfc->tag_spec.album ? strlen(gfc->tag_spec.album) : 0; + size_t comment_length = gfc->tag_spec.comment ? strlen(gfc->tag_spec.comment) : 0; + /* write tag if explicitly requested or if fields overflow */ + if ((title_length > 30) + || (artist_length > 30) + || (album_length > 30) + || (comment_length > 30) + || (gfc->tag_spec.track_id3v1 && (comment_length > 28))) { + usev2 = 1; + } + if (usev2) { + size_t tag_size; + unsigned char *p; + size_t adjusted_tag_size; + const char *albumart_mime = NULL; + static const char *mime_jpeg = "image/jpeg"; + static const char *mime_png = "image/png"; + static const char *mime_gif = "image/gif"; + + if (gfp->num_samples != MAX_U_32_NUM) { + id3v2AddAudioDuration(gfp, gfp->num_samples); + } + + /* calulate size of tag starting with 10-byte tag header */ + tag_size = 10; + if (gfc->tag_spec.albumart && gfc->tag_spec.albumart_size) { + switch (gfc->tag_spec.albumart_mimetype) { + case MIMETYPE_JPEG: + albumart_mime = mime_jpeg; + break; + case MIMETYPE_PNG: + albumart_mime = mime_png; + break; + case MIMETYPE_GIF: + albumart_mime = mime_gif; + break; + } + if (albumart_mime) { + tag_size += 10 + 4 + strlen(albumart_mime) + gfc->tag_spec.albumart_size; + } + } + { + id3tag_spec *tag = &gfc->tag_spec; + if (tag->v2_head != 0) { + FrameDataNode *node; + for (node = tag->v2_head; node != 0; node = node->nxt) { + if (node->fid == ID_COMMENT || node->fid == ID_USER) { + tag_size += sizeOfCommentNode(node); + } + else if (isFrameIdMatching(node->fid, FRAME_ID('W',0,0,0))) { + tag_size += sizeOfWxxxNode(node); + } + else { + tag_size += sizeOfNode(node); + } + } + } + } + if (test_tag_spec_flags(gfc, PAD_V2_FLAG)) { + /* add some bytes of padding */ + tag_size += gfc->tag_spec.padding_size; + } + if (size < tag_size) { + return tag_size; + } + if (buffer == 0) { + return 0; + } + p = buffer; + /* set tag header starting with file identifier */ + *p++ = 'I'; + *p++ = 'D'; + *p++ = '3'; + /* set version number word */ + *p++ = 3; + *p++ = 0; + /* clear flags byte */ + *p++ = 0; + /* calculate and set tag size = total size - header size */ + adjusted_tag_size = tag_size - 10; + /* encode adjusted size into four bytes where most significant + * bit is clear in each byte, for 28-bit total */ + *p++ = (unsigned char) ((adjusted_tag_size >> 21) & 0x7fu); + *p++ = (unsigned char) ((adjusted_tag_size >> 14) & 0x7fu); + *p++ = (unsigned char) ((adjusted_tag_size >> 7) & 0x7fu); + *p++ = (unsigned char) (adjusted_tag_size & 0x7fu); + + /* + * NOTE: The remainder of the tag (frames and padding, if any) + * are not "unsynchronized" to prevent false MPEG audio headers + * from appearing in the bitstream. Why? Well, most players + * and utilities know how to skip the ID3 version 2 tag by now + * even if they don't read its contents, and it's actually + * very unlikely that such a false "sync" pattern would occur + * in just the simple text frames added here. + */ + + /* set each frame in tag */ + { + id3tag_spec *tag = &gfc->tag_spec; + if (tag->v2_head != 0) { + FrameDataNode *node; + for (node = tag->v2_head; node != 0; node = node->nxt) { + if (node->fid == ID_COMMENT || node->fid == ID_USER) { + p = set_frame_comment(p, node); + } + else if (isFrameIdMatching(node->fid,FRAME_ID('W',0,0,0))) { + p = set_frame_wxxx(p, node); + } + else { + p = set_frame_custom2(p, node); + } + } + } + } + if (albumart_mime) { + p = set_frame_apic(p, albumart_mime, gfc->tag_spec.albumart, + gfc->tag_spec.albumart_size); + } + /* clear any padding bytes */ + memset(p, 0, tag_size - (p - buffer)); + return tag_size; + } + } + return 0; +} + +int +id3tag_write_v2(lame_t gfp) +{ + lame_internal_flags *gfc = 0; + + if (is_lame_internal_flags_null(gfp)) { + return 0; + } + gfc = gfp->internal_flags; +#if 0 + debug_tag_spec_flags(gfc, "write v2"); +#endif + if (test_tag_spec_flags(gfc, V1_ONLY_FLAG)) { + return 0; + } + if (test_tag_spec_flags(gfc, CHANGED_FLAG)) { + unsigned char *tag = 0; + size_t tag_size, n; + + n = lame_get_id3v2_tag(gfp, 0, 0); + tag = lame_calloc(unsigned char, n); + if (tag == 0) { + return -1; + } + tag_size = lame_get_id3v2_tag(gfp, tag, n); + if (tag_size > n) { + free(tag); + return -1; + } + else { + size_t i; + /* write tag directly into bitstream at current position */ + for (i = 0; i < tag_size; ++i) { + add_dummy_byte(gfc, tag[i], 1); + } + } + free(tag); + return (int) tag_size; /* ok, tag should not exceed 2GB */ + } + return 0; +} + +static unsigned char * +set_text_field(unsigned char *field, const char *text, size_t size, int pad) +{ + while (size--) { + if (text && *text) { + *field++ = *text++; + } + else { + *field++ = pad; + } + } + return field; +} + +size_t +lame_get_id3v1_tag(lame_t gfp, unsigned char *buffer, size_t size) +{ + size_t const tag_size = 128; + lame_internal_flags *gfc; + + if (gfp == 0) { + return 0; + } + if (size < tag_size) { + return tag_size; + } + gfc = gfp->internal_flags; + if (gfc == 0) { + return 0; + } + if (buffer == 0) { + return 0; + } + if (test_tag_spec_flags(gfc, V2_ONLY_FLAG)) { + return 0; + } + if (test_tag_spec_flags(gfc, CHANGED_FLAG)) { + unsigned char *p = buffer; + int pad = test_tag_spec_flags(gfc, SPACE_V1_FLAG) ? ' ' : 0; + char year[5]; + + /* set tag identifier */ + *p++ = 'T'; + *p++ = 'A'; + *p++ = 'G'; + /* set each field in tag */ + p = set_text_field(p, gfc->tag_spec.title, 30, pad); + p = set_text_field(p, gfc->tag_spec.artist, 30, pad); + p = set_text_field(p, gfc->tag_spec.album, 30, pad); + sprintf(year, "%d", gfc->tag_spec.year); + p = set_text_field(p, gfc->tag_spec.year ? year : NULL, 4, pad); + /* limit comment field to 28 bytes if a track is specified */ + p = set_text_field(p, gfc->tag_spec.comment, gfc->tag_spec.track_id3v1 ? 28 : 30, pad); + if (gfc->tag_spec.track_id3v1) { + /* clear the next byte to indicate a version 1.1 tag */ + *p++ = 0; + *p++ = gfc->tag_spec.track_id3v1; + } + *p++ = gfc->tag_spec.genre_id3v1; + return tag_size; + } + return 0; +} + +int +id3tag_write_v1(lame_t gfp) +{ + lame_internal_flags* gfc = 0; + size_t i, n, m; + unsigned char tag[128]; + + if (is_lame_internal_flags_null(gfp)) { + return 0; + } + gfc = gfp->internal_flags; + + m = sizeof(tag); + n = lame_get_id3v1_tag(gfp, tag, m); + if (n > m) { + return 0; + } + /* write tag directly into bitstream at current position */ + for (i = 0; i < n; ++i) { + add_dummy_byte(gfc, tag[i], 1); + } + return (int) n; /* ok, tag has fixed size of 128 bytes, well below 2GB */ +} diff --git a/pkg/lame/clame/id3tag.h b/pkg/lame/clame/id3tag.h new file mode 100644 index 0000000..9cd9ad9 --- /dev/null +++ b/pkg/lame/clame/id3tag.h @@ -0,0 +1,64 @@ + +#ifndef LAME_ID3_H +#define LAME_ID3_H + + +#define CHANGED_FLAG (1U << 0) +#define ADD_V2_FLAG (1U << 1) +#define V1_ONLY_FLAG (1U << 2) +#define V2_ONLY_FLAG (1U << 3) +#define SPACE_V1_FLAG (1U << 4) +#define PAD_V2_FLAG (1U << 5) + +enum { + MIMETYPE_NONE = 0, + MIMETYPE_JPEG, + MIMETYPE_PNG, + MIMETYPE_GIF +}; + +typedef struct FrameDataNode { + struct FrameDataNode *nxt; + uint32_t fid; /* Frame Identifier */ + char lng[4]; /* 3-character language descriptor */ + struct { + union { + char *l; /* ptr to Latin-1 chars */ + unsigned short *u; /* ptr to UCS-2 text */ + unsigned char *b; /* ptr to raw bytes */ + } ptr; + size_t dim; + int enc; /* 0:Latin-1, 1:UCS-2, 2:RAW */ + } dsc , txt; +} FrameDataNode; + + +typedef struct id3tag_spec { + /* private data members */ + unsigned int flags; + int year; + char *title; + char *artist; + char *album; + char *comment; + int track_id3v1; + int genre_id3v1; + unsigned char *albumart; + unsigned int albumart_size; + unsigned int padding_size; + int albumart_mimetype; + char language[4]; /* the language of the frame's content, according to ISO-639-2 */ + FrameDataNode *v2_head, *v2_tail; +} id3tag_spec; + + +/* write tag into stream at current position */ +extern int id3tag_write_v2(lame_global_flags * gfp); +extern int id3tag_write_v1(lame_global_flags * gfp); +/* + * NOTE: A version 2 tag will NOT be added unless one of the text fields won't + * fit in a version 1 tag (e.g. the title string is longer than 30 characters), + * or the "id3tag_add_v2" or "id3tag_v2_only" functions are used. + */ + +#endif diff --git a/pkg/lame/clame/l3side.h b/pkg/lame/clame/l3side.h new file mode 100644 index 0000000..f65bbed --- /dev/null +++ b/pkg/lame/clame/l3side.h @@ -0,0 +1,95 @@ +/* + * Layer 3 side include file + * + * Copyright (c) 1999 Mark Taylor + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef LAME_L3SIDE_H +#define LAME_L3SIDE_H + +/* max scalefactor band, max(SBMAX_l, SBMAX_s*3, (SBMAX_s-3)*3+8) */ +#define SFBMAX (SBMAX_s*3) + +/* Layer III side information. */ +typedef struct { + int l[1 + SBMAX_l]; + int s[1 + SBMAX_s]; + int psfb21[1 + PSFB21]; + int psfb12[1 + PSFB12]; +} scalefac_struct; + + +typedef struct { + FLOAT l[SBMAX_l]; + FLOAT s[SBMAX_s][3]; +} III_psy_xmin; + +typedef struct { + III_psy_xmin thm; + III_psy_xmin en; +} III_psy_ratio; + +typedef struct { + FLOAT xr[576]; + int l3_enc[576]; + int scalefac[SFBMAX]; + FLOAT xrpow_max; + + int part2_3_length; + int big_values; + int count1; + int global_gain; + int scalefac_compress; + int block_type; + int mixed_block_flag; + int table_select[3]; + int subblock_gain[3 + 1]; + int region0_count; + int region1_count; + int preflag; + int scalefac_scale; + int count1table_select; + + int part2_length; + int sfb_lmax; + int sfb_smin; + int psy_lmax; + int sfbmax; + int psymax; + int sfbdivide; + int width[SFBMAX]; + int window[SFBMAX]; + int count1bits; + /* added for LSF */ + const int *sfb_partition_table; + int slen[4]; + + int max_nonzero_coeff; + char energy_above_cutoff[SFBMAX]; +} gr_info; + +typedef struct { + gr_info tt[2][2]; + int main_data_begin; + int private_bits; + int resvDrain_pre; + int resvDrain_post; + int scfsi[2][4]; +} III_side_info_t; + +#endif diff --git a/pkg/lame/clame/lame-analysis.h b/pkg/lame/clame/lame-analysis.h new file mode 100644 index 0000000..5055a60 --- /dev/null +++ b/pkg/lame/clame/lame-analysis.h @@ -0,0 +1,96 @@ +/* + * GTK plotting routines source file + * + * Copyright (c) 1999 Mark Taylor + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef LAME_GTKANAL_H +#define LAME_GTKANAL_H + + +#define READ_AHEAD 40 /* number of frames to read ahead */ +#define MAXMPGLAG READ_AHEAD /* if the mpg123 lag becomes bigger than this + we have to stop */ +#define NUMBACK 6 /* number of frames we can back up */ +#define NUMPINFO (NUMBACK+READ_AHEAD+1) + + + +struct plotting_data { + int frameNum; /* current frame number */ + int frameNum123; + int num_samples; /* number of pcm samples read for this frame */ + double frametime; /* starting time of frame, in seconds */ + double pcmdata[2][1600]; + double pcmdata2[2][1152 + 1152 - DECDELAY]; + double xr[2][2][576]; + double mpg123xr[2][2][576]; + double ms_ratio[2]; + double ms_ener_ratio[2]; + + /* L,R, M and S values */ + double energy_save[4][BLKSIZE]; /* psymodel is one ahead */ + double energy[2][4][BLKSIZE]; + double pe[2][4]; + double thr[2][4][SBMAX_l]; + double en[2][4][SBMAX_l]; + double thr_s[2][4][3 * SBMAX_s]; + double en_s[2][4][3 * SBMAX_s]; + double ers_save[4]; /* psymodel is one ahead */ + double ers[2][4]; + + double sfb[2][2][SBMAX_l]; + double sfb_s[2][2][3 * SBMAX_s]; + double LAMEsfb[2][2][SBMAX_l]; + double LAMEsfb_s[2][2][3 * SBMAX_s]; + + int LAMEqss[2][2]; + int qss[2][2]; + int big_values[2][2]; + int sub_gain[2][2][3]; + + double xfsf[2][2][SBMAX_l]; + double xfsf_s[2][2][3 * SBMAX_s]; + + int over[2][2]; + double tot_noise[2][2]; + double max_noise[2][2]; + double over_noise[2][2]; + int over_SSD[2][2]; + int blocktype[2][2]; + int scalefac_scale[2][2]; + int preflag[2][2]; + int mpg123blocktype[2][2]; + int mixed[2][2]; + int mainbits[2][2]; + int sfbits[2][2]; + int LAMEmainbits[2][2]; + int LAMEsfbits[2][2]; + int framesize, stereo, js, ms_stereo, i_stereo, emph, bitrate, sampfreq, maindata; + int crc, padding; + int scfsi[2], mean_bits, resvsize; + int totbits; +}; +#ifndef plotting_data_defined +#define plotting_data_defined +typedef struct plotting_data plotting_data; +#endif +#if 0 +extern plotting_data *pinfo; +#endif +#endif diff --git a/pkg/lame/clame/lame.c b/pkg/lame/clame/lame.c new file mode 100644 index 0000000..cb82225 --- /dev/null +++ b/pkg/lame/clame/lame.c @@ -0,0 +1,2665 @@ +/* -*- mode: C; mode: fold -*- */ +/* + * LAME MP3 encoding engine + * + * Copyright (c) 1999-2000 Mark Taylor + * Copyright (c) 2000-2005 Takehiro Tominaga + * Copyright (c) 2000-2017 Robert Hegemann + * Copyright (c) 2000-2005 Gabriel Bouvigne + * Copyright (c) 2000-2004 Alexander Leidinger + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* $Id: lame.c,v 1.377 2017/09/26 12:14:02 robert Exp $ */ + +#ifdef HAVE_CONFIG_H +# include +#endif + + +#include "lame.h" +#include "machine.h" + +#include "encoder.h" +#include "util.h" +#include "lame_global_flags.h" +#include "gain_analysis.h" +#include "bitstream.h" +#include "quantize_pvt.h" +#include "set_get.h" +#include "quantize.h" +#include "psymodel.h" +#include "version.h" +#include "VbrTag.h" +#include "tables.h" + + +#if defined(__FreeBSD__) && !defined(__alpha__) +#include +#endif +#ifdef __riscos__ +#include "asmstuff.h" +#endif + +#ifdef __sun__ +/* woraround for SunOS 4.x, it has SEEK_* defined here */ +#include +#endif + + +#define LAME_DEFAULT_QUALITY 3 + + + +int +is_lame_global_flags_valid(const lame_global_flags * gfp) +{ + if (gfp == NULL) + return 0; + if (gfp->class_id != LAME_ID) + return 0; + return 1; +} + + +int +is_lame_internal_flags_valid(const lame_internal_flags * gfc) +{ + if (gfc == NULL) + return 0; + if (gfc->class_id != LAME_ID) + return 0; + if (gfc->lame_init_params_successful <=0) + return 0; + return 1; +} + + + +static FLOAT +filter_coef(FLOAT x) +{ + if (x > 1.0) + return 0.0; + if (x <= 0.0) + return 1.0; + + return cos(PI / 2 * x); +} + +static void +lame_init_params_ppflt(lame_internal_flags * gfc) +{ + SessionConfig_t *const cfg = &gfc->cfg; + + /***************************************************************/ + /* compute info needed for polyphase filter (filter type==0, default) */ + /***************************************************************/ + + int band, maxband, minband; + FLOAT freq; + int lowpass_band = 32; + int highpass_band = -1; + + if (cfg->lowpass1 > 0) { + minband = 999; + for (band = 0; band <= 31; band++) { + freq = band / 31.0; + /* this band and above will be zeroed: */ + if (freq >= cfg->lowpass2) { + lowpass_band = Min(lowpass_band, band); + } + if (cfg->lowpass1 < freq && freq < cfg->lowpass2) { + minband = Min(minband, band); + } + } + + /* compute the *actual* transition band implemented by + * the polyphase filter */ + if (minband == 999) { + cfg->lowpass1 = (lowpass_band - .75) / 31.0; + } + else { + cfg->lowpass1 = (minband - .75) / 31.0; + } + cfg->lowpass2 = lowpass_band / 31.0; + } + + /* make sure highpass filter is within 90% of what the effective + * highpass frequency will be */ + if (cfg->highpass2 > 0) { + if (cfg->highpass2 < .9 * (.75 / 31.0)) { + cfg->highpass1 = 0; + cfg->highpass2 = 0; + MSGF(gfc, "Warning: highpass filter disabled. " "highpass frequency too small\n"); + } + } + + if (cfg->highpass2 > 0) { + maxband = -1; + for (band = 0; band <= 31; band++) { + freq = band / 31.0; + /* this band and below will be zereod */ + if (freq <= cfg->highpass1) { + highpass_band = Max(highpass_band, band); + } + if (cfg->highpass1 < freq && freq < cfg->highpass2) { + maxband = Max(maxband, band); + } + } + /* compute the *actual* transition band implemented by + * the polyphase filter */ + cfg->highpass1 = highpass_band / 31.0; + if (maxband == -1) { + cfg->highpass2 = (highpass_band + .75) / 31.0; + } + else { + cfg->highpass2 = (maxband + .75) / 31.0; + } + } + + for (band = 0; band < 32; band++) { + FLOAT fc1, fc2; + freq = band / 31.0f; + if (cfg->highpass2 > cfg->highpass1) { + fc1 = filter_coef((cfg->highpass2 - freq) / (cfg->highpass2 - cfg->highpass1 + 1e-20)); + } + else { + fc1 = 1.0f; + } + if (cfg->lowpass2 > cfg->lowpass1) { + fc2 = filter_coef((freq - cfg->lowpass1) / (cfg->lowpass2 - cfg->lowpass1 + 1e-20)); + } + else { + fc2 = 1.0f; + } + gfc->sv_enc.amp_filter[band] = fc1 * fc2; + } +} + + +static void +optimum_bandwidth(double *const lowerlimit, double *const upperlimit, const unsigned bitrate) +{ +/* + * Input: + * bitrate total bitrate in kbps + * + * Output: + * lowerlimit: best lowpass frequency limit for input filter in Hz + * upperlimit: best highpass frequency limit for input filter in Hz + */ + int table_index; + + typedef struct { + int bitrate; /* only indicative value */ + int lowpass; + } band_pass_t; + + const band_pass_t freq_map[] = { + {8, 2000}, + {16, 3700}, + {24, 3900}, + {32, 5500}, + {40, 7000}, + {48, 7500}, + {56, 10000}, + {64, 11000}, + {80, 13500}, + {96, 15100}, + {112, 15600}, + {128, 17000}, + {160, 17500}, + {192, 18600}, + {224, 19400}, + {256, 19700}, + {320, 20500} + }; + + + table_index = nearestBitrateFullIndex(bitrate); + + (void) freq_map[table_index].bitrate; + *lowerlimit = freq_map[table_index].lowpass; + + +/* + * Now we try to choose a good high pass filtering frequency. + * This value is currently not used. + * For fu < 16 kHz: sqrt(fu*fl) = 560 Hz + * For fu = 18 kHz: no high pass filtering + * This gives: + * + * 2 kHz => 160 Hz + * 3 kHz => 107 Hz + * 4 kHz => 80 Hz + * 8 kHz => 40 Hz + * 16 kHz => 20 Hz + * 17 kHz => 10 Hz + * 18 kHz => 0 Hz + * + * These are ad hoc values and these can be optimized if a high pass is available. + */ +/* if (f_low <= 16000) + f_high = 16000. * 20. / f_low; + else if (f_low <= 18000) + f_high = 180. - 0.01 * f_low; + else + f_high = 0.;*/ + + /* + * When we sometimes have a good highpass filter, we can add the highpass + * frequency to the lowpass frequency + */ + + /*if (upperlimit != NULL) + *upperlimit = f_high;*/ + (void) upperlimit; +} + + +static int +optimum_samplefreq(int lowpassfreq, int input_samplefreq) +{ +/* + * Rules: + * - if possible, sfb21 should NOT be used + * + */ + int suggested_samplefreq = 44100; + + if (input_samplefreq >= 48000) + suggested_samplefreq = 48000; + else if (input_samplefreq >= 44100) + suggested_samplefreq = 44100; + else if (input_samplefreq >= 32000) + suggested_samplefreq = 32000; + else if (input_samplefreq >= 24000) + suggested_samplefreq = 24000; + else if (input_samplefreq >= 22050) + suggested_samplefreq = 22050; + else if (input_samplefreq >= 16000) + suggested_samplefreq = 16000; + else if (input_samplefreq >= 12000) + suggested_samplefreq = 12000; + else if (input_samplefreq >= 11025) + suggested_samplefreq = 11025; + else if (input_samplefreq >= 8000) + suggested_samplefreq = 8000; + + if (lowpassfreq == -1) + return suggested_samplefreq; + + if (lowpassfreq <= 15960) + suggested_samplefreq = 44100; + if (lowpassfreq <= 15250) + suggested_samplefreq = 32000; + if (lowpassfreq <= 11220) + suggested_samplefreq = 24000; + if (lowpassfreq <= 9970) + suggested_samplefreq = 22050; + if (lowpassfreq <= 7230) + suggested_samplefreq = 16000; + if (lowpassfreq <= 5420) + suggested_samplefreq = 12000; + if (lowpassfreq <= 4510) + suggested_samplefreq = 11025; + if (lowpassfreq <= 3970) + suggested_samplefreq = 8000; + + if (input_samplefreq < suggested_samplefreq) { + /* choose a valid MPEG sample frequency above the input sample frequency + to avoid SFB21/12 bitrate bloat + rh 061115 + */ + if (input_samplefreq > 44100) { + return 48000; + } + if (input_samplefreq > 32000) { + return 44100; + } + if (input_samplefreq > 24000) { + return 32000; + } + if (input_samplefreq > 22050) { + return 24000; + } + if (input_samplefreq > 16000) { + return 22050; + } + if (input_samplefreq > 12000) { + return 16000; + } + if (input_samplefreq > 11025) { + return 12000; + } + if (input_samplefreq > 8000) { + return 11025; + } + return 8000; + } + return suggested_samplefreq; +} + + + + + +/* set internal feature flags. USER should not access these since + * some combinations will produce strange results */ +static void +lame_init_qval(lame_global_flags * gfp) +{ + lame_internal_flags *const gfc = gfp->internal_flags; + SessionConfig_t *const cfg = &gfc->cfg; + + switch (gfp->quality) { + default: + case 9: /* no psymodel, no noise shaping */ + cfg->noise_shaping = 0; + cfg->noise_shaping_amp = 0; + cfg->noise_shaping_stop = 0; + cfg->use_best_huffman = 0; + cfg->full_outer_loop = 0; + break; + + case 8: + gfp->quality = 7; + /*lint --fallthrough */ + case 7: /* use psymodel (for short block and m/s switching), but no noise shapping */ + cfg->noise_shaping = 0; + cfg->noise_shaping_amp = 0; + cfg->noise_shaping_stop = 0; + cfg->use_best_huffman = 0; + cfg->full_outer_loop = 0; + if (cfg->vbr == vbr_mt || cfg->vbr == vbr_mtrh) { + cfg->full_outer_loop = -1; + } + break; + + case 6: + if (cfg->noise_shaping == 0) + cfg->noise_shaping = 1; + cfg->noise_shaping_amp = 0; + cfg->noise_shaping_stop = 0; + if (cfg->subblock_gain == -1) + cfg->subblock_gain = 1; + cfg->use_best_huffman = 0; + cfg->full_outer_loop = 0; + break; + + case 5: + if (cfg->noise_shaping == 0) + cfg->noise_shaping = 1; + cfg->noise_shaping_amp = 0; + cfg->noise_shaping_stop = 0; + if (cfg->subblock_gain == -1) + cfg->subblock_gain = 1; + cfg->use_best_huffman = 0; + cfg->full_outer_loop = 0; + break; + + case 4: + if (cfg->noise_shaping == 0) + cfg->noise_shaping = 1; + cfg->noise_shaping_amp = 0; + cfg->noise_shaping_stop = 0; + if (cfg->subblock_gain == -1) + cfg->subblock_gain = 1; + cfg->use_best_huffman = 1; + cfg->full_outer_loop = 0; + break; + + case 3: + if (cfg->noise_shaping == 0) + cfg->noise_shaping = 1; + cfg->noise_shaping_amp = 1; + cfg->noise_shaping_stop = 1; + if (cfg->subblock_gain == -1) + cfg->subblock_gain = 1; + cfg->use_best_huffman = 1; + cfg->full_outer_loop = 0; + break; + + case 2: + if (cfg->noise_shaping == 0) + cfg->noise_shaping = 1; + if (gfc->sv_qnt.substep_shaping == 0) + gfc->sv_qnt.substep_shaping = 2; + cfg->noise_shaping_amp = 1; + cfg->noise_shaping_stop = 1; + if (cfg->subblock_gain == -1) + cfg->subblock_gain = 1; + cfg->use_best_huffman = 1; /* inner loop */ + cfg->full_outer_loop = 0; + break; + + case 1: + if (cfg->noise_shaping == 0) + cfg->noise_shaping = 1; + if (gfc->sv_qnt.substep_shaping == 0) + gfc->sv_qnt.substep_shaping = 2; + cfg->noise_shaping_amp = 2; + cfg->noise_shaping_stop = 1; + if (cfg->subblock_gain == -1) + cfg->subblock_gain = 1; + cfg->use_best_huffman = 1; + cfg->full_outer_loop = 0; + break; + + case 0: + if (cfg->noise_shaping == 0) + cfg->noise_shaping = 1; + if (gfc->sv_qnt.substep_shaping == 0) + gfc->sv_qnt.substep_shaping = 2; + cfg->noise_shaping_amp = 2; + cfg->noise_shaping_stop = 1; + if (cfg->subblock_gain == -1) + cfg->subblock_gain = 1; + cfg->use_best_huffman = 1; /*type 2 disabled because of it slowness, + in favor of full outer loop search */ + cfg->full_outer_loop = 1; + break; + } + +} + + + +static double +linear_int(double a, double b, double m) +{ + return a + m * (b - a); +} + + + +/******************************************************************** + * initialize internal params based on data in gf + * (globalflags struct filled in by calling program) + * + * OUTLINE: + * + * We first have some complex code to determine bitrate, + * output samplerate and mode. It is complicated by the fact + * that we allow the user to set some or all of these parameters, + * and need to determine best possible values for the rest of them: + * + * 1. set some CPU related flags + * 2. check if we are mono->mono, stereo->mono or stereo->stereo + * 3. compute bitrate and output samplerate: + * user may have set compression ratio + * user may have set a bitrate + * user may have set a output samplerate + * 4. set some options which depend on output samplerate + * 5. compute the actual compression ratio + * 6. set mode based on compression ratio + * + * The remaining code is much simpler - it just sets options + * based on the mode & compression ratio: + * + * set allow_diff_short based on mode + * select lowpass filter based on compression ratio & mode + * set the bitrate index, and min/max bitrates for VBR modes + * disable VBR tag if it is not appropriate + * initialize the bitstream + * initialize scalefac_band data + * set sideinfo_len (based on channels, CRC, out_samplerate) + * write an id3v2 tag into the bitstream + * write VBR tag into the bitstream + * set mpeg1/2 flag + * estimate the number of frames (based on a lot of data) + * + * now we set more flags: + * nspsytune: + * see code + * VBR modes + * see code + * CBR/ABR + * see code + * + * Finally, we set the algorithm flags based on the gfp->quality value + * lame_init_qval(gfp); + * + ********************************************************************/ +int +lame_init_params(lame_global_flags * gfp) +{ + + int i; + int j; + lame_internal_flags *gfc; + SessionConfig_t *cfg; + + if (!is_lame_global_flags_valid(gfp)) + return -1; + + gfc = gfp->internal_flags; + if (gfc == 0) + return -1; + + if (is_lame_internal_flags_valid(gfc)) + return -1; /* already initialized */ + + /* start updating lame internal flags */ + gfc->class_id = LAME_ID; + gfc->lame_init_params_successful = 0; /* will be set to one, when we get through until the end */ + + if (gfp->samplerate_in < 1) + return -1; /* input sample rate makes no sense */ + if (gfp->num_channels < 1 || 2 < gfp->num_channels) + return -1; /* number of input channels makes no sense */ + if (gfp->samplerate_out != 0) { + int v=0; + if (SmpFrqIndex(gfp->samplerate_out, &v) < 0) + return -1; /* output sample rate makes no sense */ + } + + cfg = &gfc->cfg; + + cfg->enforce_min_bitrate = gfp->VBR_hard_min; + cfg->analysis = gfp->analysis; + if (cfg->analysis) + gfp->write_lame_tag = 0; + + /* some file options not allowed if output is: not specified or stdout */ + if (gfc->pinfo != NULL) + gfp->write_lame_tag = 0; /* disable Xing VBR tag */ + + /* report functions */ + gfc->report_msg = gfp->report.msgf; + gfc->report_dbg = gfp->report.debugf; + gfc->report_err = gfp->report.errorf; + + if (gfp->asm_optimizations.amd3dnow) + gfc->CPU_features.AMD_3DNow = has_3DNow(); + else + gfc->CPU_features.AMD_3DNow = 0; + + if (gfp->asm_optimizations.mmx) + gfc->CPU_features.MMX = has_MMX(); + else + gfc->CPU_features.MMX = 0; + + if (gfp->asm_optimizations.sse) { + gfc->CPU_features.SSE = has_SSE(); + gfc->CPU_features.SSE2 = has_SSE2(); + } + else { + gfc->CPU_features.SSE = 0; + gfc->CPU_features.SSE2 = 0; + } + + + cfg->vbr = gfp->VBR; + cfg->error_protection = gfp->error_protection; + cfg->copyright = gfp->copyright; + cfg->original = gfp->original; + cfg->extension = gfp->extension; + cfg->emphasis = gfp->emphasis; + + cfg->channels_in = gfp->num_channels; + if (cfg->channels_in == 1) + gfp->mode = MONO; + cfg->channels_out = (gfp->mode == MONO) ? 1 : 2; + if (gfp->mode != JOINT_STEREO) + gfp->force_ms = 0; /* forced mid/side stereo for j-stereo only */ + cfg->force_ms = gfp->force_ms; + + if (cfg->vbr == vbr_off && gfp->VBR_mean_bitrate_kbps != 128 && gfp->brate == 0) + gfp->brate = gfp->VBR_mean_bitrate_kbps; + + switch (cfg->vbr) { + case vbr_off: + case vbr_mtrh: + case vbr_mt: + /* these modes can handle free format condition */ + break; + default: + gfp->free_format = 0; /* mode can't be mixed with free format */ + break; + } + + cfg->free_format = gfp->free_format; + + if (cfg->vbr == vbr_off && gfp->brate == 0) { + /* no bitrate or compression ratio specified, use 11.025 */ + if (EQ(gfp->compression_ratio, 0)) + gfp->compression_ratio = 11.025; /* rate to compress a CD down to exactly 128000 bps */ + } + + /* find bitrate if user specify a compression ratio */ + if (cfg->vbr == vbr_off && gfp->compression_ratio > 0) { + + if (gfp->samplerate_out == 0) + gfp->samplerate_out = map2MP3Frequency((int) (0.97 * gfp->samplerate_in)); /* round up with a margin of 3% */ + + /* choose a bitrate for the output samplerate which achieves + * specified compression ratio + */ + gfp->brate = gfp->samplerate_out * 16 * cfg->channels_out / (1.e3 * gfp->compression_ratio); + + /* we need the version for the bitrate table look up */ + cfg->samplerate_index = SmpFrqIndex(gfp->samplerate_out, &cfg->version); + assert(cfg->samplerate_index >=0); + + if (!cfg->free_format) /* for non Free Format find the nearest allowed bitrate */ + gfp->brate = FindNearestBitrate(gfp->brate, cfg->version, gfp->samplerate_out); + } + if (gfp->samplerate_out) { + if (gfp->samplerate_out < 16000) { + gfp->VBR_mean_bitrate_kbps = Max(gfp->VBR_mean_bitrate_kbps, 8); + gfp->VBR_mean_bitrate_kbps = Min(gfp->VBR_mean_bitrate_kbps, 64); + } + else if (gfp->samplerate_out < 32000) { + gfp->VBR_mean_bitrate_kbps = Max(gfp->VBR_mean_bitrate_kbps, 8); + gfp->VBR_mean_bitrate_kbps = Min(gfp->VBR_mean_bitrate_kbps, 160); + } + else { + gfp->VBR_mean_bitrate_kbps = Max(gfp->VBR_mean_bitrate_kbps, 32); + gfp->VBR_mean_bitrate_kbps = Min(gfp->VBR_mean_bitrate_kbps, 320); + } + } + /* WORK IN PROGRESS */ + /* mapping VBR scale to internal VBR quality settings */ + if (gfp->samplerate_out == 0 && (cfg->vbr == vbr_mt || cfg->vbr == vbr_mtrh)) { + float const qval = gfp->VBR_q + gfp->VBR_q_frac; + struct q_map { int sr_a; float qa, qb, ta, tb; int lp; }; + struct q_map const m[9] + = { {48000, 0.0,6.5, 0.0,6.5, 23700} + , {44100, 0.0,6.5, 0.0,6.5, 21780} + , {32000, 6.5,8.0, 5.2,6.5, 15800} + , {24000, 8.0,8.5, 5.2,6.0, 11850} + , {22050, 8.5,9.01, 5.2,6.5, 10892} + , {16000, 9.01,9.4, 4.9,6.5, 7903} + , {12000, 9.4,9.6, 4.5,6.0, 5928} + , {11025, 9.6,9.9, 5.1,6.5, 5446} + , { 8000, 9.9,10., 4.9,6.5, 3952} + }; + for (i = 2; i < 9; ++i) { + if (gfp->samplerate_in == m[i].sr_a) { + if (qval < m[i].qa) { + double d = qval / m[i].qa; + d = d * m[i].ta; + gfp->VBR_q = (int)d; + gfp->VBR_q_frac = d - gfp->VBR_q; + } + } + if (gfp->samplerate_in >= m[i].sr_a) { + if (m[i].qa <= qval && qval < m[i].qb) { + float const q_ = m[i].qb-m[i].qa; + float const t_ = m[i].tb-m[i].ta; + double d = m[i].ta + t_ * (qval-m[i].qa) / q_; + gfp->VBR_q = (int)d; + gfp->VBR_q_frac = d - gfp->VBR_q; + gfp->samplerate_out = m[i].sr_a; + if (gfp->lowpassfreq == 0) { + gfp->lowpassfreq = -1; + } + break; + } + } + } + } + + /****************************************************************/ + /* if a filter has not been enabled, see if we should add one: */ + /****************************************************************/ + if (gfp->lowpassfreq == 0) { + double lowpass = 16000; + double highpass; + + switch (cfg->vbr) { + case vbr_off:{ + optimum_bandwidth(&lowpass, &highpass, gfp->brate); + break; + } + case vbr_abr:{ + optimum_bandwidth(&lowpass, &highpass, gfp->VBR_mean_bitrate_kbps); + break; + } + case vbr_rh:{ + int const x[11] = { + 19500, 19000, 18600, 18000, 17500, 16000, 15600, 14900, 12500, 10000, 3950 + }; + if (0 <= gfp->VBR_q && gfp->VBR_q <= 9) { + double a = x[gfp->VBR_q], b = x[gfp->VBR_q + 1], m = gfp->VBR_q_frac; + lowpass = linear_int(a, b, m); + } + else { + lowpass = 19500; + } + break; + } + case vbr_mtrh: + case vbr_mt:{ + int const x[11] = { + 24000, 19500, 18500, 18000, 17500, 17000, 16500, 15600, 15200, 7230, 3950 + }; + if (0 <= gfp->VBR_q && gfp->VBR_q <= 9) { + double a = x[gfp->VBR_q], b = x[gfp->VBR_q + 1], m = gfp->VBR_q_frac; + lowpass = linear_int(a, b, m); + } + else { + lowpass = 21500; + } + break; + } + default:{ + int const x[11] = { + 19500, 19000, 18500, 18000, 17500, 16500, 15500, 14500, 12500, 9500, 3950 + }; + if (0 <= gfp->VBR_q && gfp->VBR_q <= 9) { + double a = x[gfp->VBR_q], b = x[gfp->VBR_q + 1], m = gfp->VBR_q_frac; + lowpass = linear_int(a, b, m); + } + else { + lowpass = 19500; + } + } + } + + if (gfp->mode == MONO && (cfg->vbr == vbr_off || cfg->vbr == vbr_abr)) + lowpass *= 1.5; + + gfp->lowpassfreq = lowpass; + } + + if (gfp->samplerate_out == 0) { + if (2 * gfp->lowpassfreq > gfp->samplerate_in) { + gfp->lowpassfreq = gfp->samplerate_in / 2; + } + gfp->samplerate_out = optimum_samplefreq((int) gfp->lowpassfreq, gfp->samplerate_in); + } + if (cfg->vbr == vbr_mt || cfg->vbr == vbr_mtrh) { + gfp->lowpassfreq = Min(24000, gfp->lowpassfreq); + } + else { + gfp->lowpassfreq = Min(20500, gfp->lowpassfreq); + } + gfp->lowpassfreq = Min(gfp->samplerate_out / 2, gfp->lowpassfreq); + + if (cfg->vbr == vbr_off) { + gfp->compression_ratio = gfp->samplerate_out * 16 * cfg->channels_out / (1.e3 * gfp->brate); + } + if (cfg->vbr == vbr_abr) { + gfp->compression_ratio = + gfp->samplerate_out * 16 * cfg->channels_out / (1.e3 * gfp->VBR_mean_bitrate_kbps); + } + + cfg->disable_reservoir = gfp->disable_reservoir; + cfg->lowpassfreq = gfp->lowpassfreq; + cfg->highpassfreq = gfp->highpassfreq; + cfg->samplerate_in = gfp->samplerate_in; + cfg->samplerate_out = gfp->samplerate_out; + cfg->mode_gr = cfg->samplerate_out <= 24000 ? 1 : 2; /* Number of granules per frame */ + + + /* + * sample freq bitrate compression ratio + * [kHz] [kbps/channel] for 16 bit input + * 44.1 56 12.6 + * 44.1 64 11.025 + * 44.1 80 8.82 + * 22.05 24 14.7 + * 22.05 32 11.025 + * 22.05 40 8.82 + * 16 16 16.0 + * 16 24 10.667 + * + */ + /* + * For VBR, take a guess at the compression_ratio. + * For example: + * + * VBR_q compression like + * - 4.4 320 kbps/44 kHz + * 0...1 5.5 256 kbps/44 kHz + * 2 7.3 192 kbps/44 kHz + * 4 8.8 160 kbps/44 kHz + * 6 11 128 kbps/44 kHz + * 9 14.7 96 kbps + * + * for lower bitrates, downsample with --resample + */ + + switch (cfg->vbr) { + case vbr_mt: + case vbr_rh: + case vbr_mtrh: + { + /*numbers are a bit strange, but they determine the lowpass value */ + FLOAT const cmp[] = { 5.7, 6.5, 7.3, 8.2, 10, 11.9, 13, 14, 15, 16.5 }; + gfp->compression_ratio = cmp[gfp->VBR_q]; + } + break; + case vbr_abr: + gfp->compression_ratio = + cfg->samplerate_out * 16 * cfg->channels_out / (1.e3 * gfp->VBR_mean_bitrate_kbps); + break; + default: + gfp->compression_ratio = cfg->samplerate_out * 16 * cfg->channels_out / (1.e3 * gfp->brate); + break; + } + + + /* mode = -1 (not set by user) or + * mode = MONO (because of only 1 input channel). + * If mode has not been set, then select J-STEREO + */ + if (gfp->mode == NOT_SET) { + gfp->mode = JOINT_STEREO; + } + + cfg->mode = gfp->mode; + + + /* apply user driven high pass filter */ + if (cfg->highpassfreq > 0) { + cfg->highpass1 = 2. * cfg->highpassfreq; + + if (gfp->highpasswidth >= 0) + cfg->highpass2 = 2. * (cfg->highpassfreq + gfp->highpasswidth); + else /* 0% above on default */ + cfg->highpass2 = (1 + 0.00) * 2. * cfg->highpassfreq; + + cfg->highpass1 /= cfg->samplerate_out; + cfg->highpass2 /= cfg->samplerate_out; + } + else { + cfg->highpass1 = 0; + cfg->highpass2 = 0; + } + /* apply user driven low pass filter */ + cfg->lowpass1 = 0; + cfg->lowpass2 = 0; + if (cfg->lowpassfreq > 0 && cfg->lowpassfreq < (cfg->samplerate_out / 2) ) { + cfg->lowpass2 = 2. * cfg->lowpassfreq; + if (gfp->lowpasswidth >= 0) { + cfg->lowpass1 = 2. * (cfg->lowpassfreq - gfp->lowpasswidth); + if (cfg->lowpass1 < 0) /* has to be >= 0 */ + cfg->lowpass1 = 0; + } + else { /* 0% below on default */ + cfg->lowpass1 = (1 - 0.00) * 2. * cfg->lowpassfreq; + } + cfg->lowpass1 /= cfg->samplerate_out; + cfg->lowpass2 /= cfg->samplerate_out; + } + + + + + /**********************************************************************/ + /* compute info needed for polyphase filter (filter type==0, default) */ + /**********************************************************************/ + lame_init_params_ppflt(gfc); + + + /******************************************************* + * samplerate and bitrate index + *******************************************************/ + cfg->samplerate_index = SmpFrqIndex(cfg->samplerate_out, &cfg->version); + assert(cfg->samplerate_index >= 0); + + if (cfg->vbr == vbr_off) { + if (cfg->free_format) { + gfc->ov_enc.bitrate_index = 0; + } + else { + gfp->brate = FindNearestBitrate(gfp->brate, cfg->version, cfg->samplerate_out); + gfc->ov_enc.bitrate_index = BitrateIndex(gfp->brate, cfg->version, cfg->samplerate_out); + if (gfc->ov_enc.bitrate_index <= 0) { + /* This never happens, because of preceding FindNearestBitrate! + * But, set a sane value, just in case + */ + assert(0); + gfc->ov_enc.bitrate_index = 8; + } + } + } + else { + gfc->ov_enc.bitrate_index = 1; + } + + init_bit_stream_w(gfc); + + j = cfg->samplerate_index + (3 * cfg->version) + 6 * (cfg->samplerate_out < 16000); + for (i = 0; i < SBMAX_l + 1; i++) + gfc->scalefac_band.l[i] = sfBandIndex[j].l[i]; + + for (i = 0; i < PSFB21 + 1; i++) { + int const size = (gfc->scalefac_band.l[22] - gfc->scalefac_band.l[21]) / PSFB21; + int const start = gfc->scalefac_band.l[21] + i * size; + gfc->scalefac_band.psfb21[i] = start; + } + gfc->scalefac_band.psfb21[PSFB21] = 576; + + for (i = 0; i < SBMAX_s + 1; i++) + gfc->scalefac_band.s[i] = sfBandIndex[j].s[i]; + + for (i = 0; i < PSFB12 + 1; i++) { + int const size = (gfc->scalefac_band.s[13] - gfc->scalefac_band.s[12]) / PSFB12; + int const start = gfc->scalefac_band.s[12] + i * size; + gfc->scalefac_band.psfb12[i] = start; + } + gfc->scalefac_band.psfb12[PSFB12] = 192; + + /* determine the mean bitrate for main data */ + if (cfg->mode_gr == 2) /* MPEG 1 */ + cfg->sideinfo_len = (cfg->channels_out == 1) ? 4 + 17 : 4 + 32; + else /* MPEG 2 */ + cfg->sideinfo_len = (cfg->channels_out == 1) ? 4 + 9 : 4 + 17; + + if (cfg->error_protection) + cfg->sideinfo_len += 2; + + { + int k; + + for (k = 0; k < 19; k++) + gfc->sv_enc.pefirbuf[k] = 700 * cfg->mode_gr * cfg->channels_out; + + if (gfp->ATHtype == -1) + gfp->ATHtype = 4; + } + + assert(gfp->VBR_q <= 9); + assert(gfp->VBR_q >= 0); + + switch (cfg->vbr) { + + case vbr_mt: + case vbr_mtrh:{ + if (gfp->strict_ISO < 0) { + gfp->strict_ISO = MDB_MAXIMUM; + } + if (gfp->useTemporal < 0) { + gfp->useTemporal = 0; /* off by default for this VBR mode */ + } + + (void) apply_preset(gfp, 500 - (gfp->VBR_q * 10), 0); + /* The newer VBR code supports only a limited + subset of quality levels: + 9-5=5 are the same, uses x^3/4 quantization + 4-0=0 are the same 5 plus best huffman divide code + */ + if (gfp->quality < 0) + gfp->quality = LAME_DEFAULT_QUALITY; + if (gfp->quality < 5) + gfp->quality = 0; + if (gfp->quality > 7) + gfp->quality = 7; + + /* sfb21 extra only with MPEG-1 at higher sampling rates + */ + if (gfp->experimentalY) + gfc->sv_qnt.sfb21_extra = 0; + else + gfc->sv_qnt.sfb21_extra = (cfg->samplerate_out > 44000); + + break; + + } + case vbr_rh:{ + + (void) apply_preset(gfp, 500 - (gfp->VBR_q * 10), 0); + + /* sfb21 extra only with MPEG-1 at higher sampling rates + */ + if (gfp->experimentalY) + gfc->sv_qnt.sfb21_extra = 0; + else + gfc->sv_qnt.sfb21_extra = (cfg->samplerate_out > 44000); + + /* VBR needs at least the output of GPSYCHO, + * so we have to garantee that by setting a minimum + * quality level, actually level 6 does it. + * down to level 6 + */ + if (gfp->quality > 6) + gfp->quality = 6; + + + if (gfp->quality < 0) + gfp->quality = LAME_DEFAULT_QUALITY; + + break; + } + + default: /* cbr/abr */ { + + /* no sfb21 extra with CBR code + */ + gfc->sv_qnt.sfb21_extra = 0; + + if (gfp->quality < 0) + gfp->quality = LAME_DEFAULT_QUALITY; + + + if (cfg->vbr == vbr_off) + (void) lame_set_VBR_mean_bitrate_kbps(gfp, gfp->brate); + /* second, set parameters depending on bitrate */ + (void) apply_preset(gfp, gfp->VBR_mean_bitrate_kbps, 0); + gfp->VBR = cfg->vbr; + + break; + } + } + + /*initialize default values common for all modes */ + + gfc->sv_qnt.mask_adjust = gfp->maskingadjust; + gfc->sv_qnt.mask_adjust_short = gfp->maskingadjust_short; + + /* just another daily changing developer switch */ + if (gfp->tune) { + gfc->sv_qnt.mask_adjust += gfp->tune_value_a; + gfc->sv_qnt.mask_adjust_short += gfp->tune_value_a; + } + + + if (cfg->vbr != vbr_off) { /* choose a min/max bitrate for VBR */ + /* if the user didn't specify VBR_max_bitrate: */ + cfg->vbr_min_bitrate_index = 1; /* default: allow 8 kbps (MPEG-2) or 32 kbps (MPEG-1) */ + cfg->vbr_max_bitrate_index = 14; /* default: allow 160 kbps (MPEG-2) or 320 kbps (MPEG-1) */ + if (cfg->samplerate_out < 16000) + cfg->vbr_max_bitrate_index = 8; /* default: allow 64 kbps (MPEG-2.5) */ + if (gfp->VBR_min_bitrate_kbps) { + gfp->VBR_min_bitrate_kbps = + FindNearestBitrate(gfp->VBR_min_bitrate_kbps, cfg->version, cfg->samplerate_out); + cfg->vbr_min_bitrate_index = + BitrateIndex(gfp->VBR_min_bitrate_kbps, cfg->version, cfg->samplerate_out); + if (cfg->vbr_min_bitrate_index < 0) { + /* This never happens, because of preceding FindNearestBitrate! + * But, set a sane value, just in case + */ + assert(0); + cfg->vbr_min_bitrate_index = 1; + } + } + if (gfp->VBR_max_bitrate_kbps) { + gfp->VBR_max_bitrate_kbps = + FindNearestBitrate(gfp->VBR_max_bitrate_kbps, cfg->version, cfg->samplerate_out); + cfg->vbr_max_bitrate_index = + BitrateIndex(gfp->VBR_max_bitrate_kbps, cfg->version, cfg->samplerate_out); + if (cfg->vbr_max_bitrate_index < 0) { + /* This never happens, because of preceding FindNearestBitrate! + * But, set a sane value, just in case + */ + assert(0); + cfg->vbr_max_bitrate_index = cfg->samplerate_out < 16000 ? 8 : 14; + } + } + gfp->VBR_min_bitrate_kbps = bitrate_table[cfg->version][cfg->vbr_min_bitrate_index]; + gfp->VBR_max_bitrate_kbps = bitrate_table[cfg->version][cfg->vbr_max_bitrate_index]; + gfp->VBR_mean_bitrate_kbps = + Min(bitrate_table[cfg->version][cfg->vbr_max_bitrate_index], + gfp->VBR_mean_bitrate_kbps); + gfp->VBR_mean_bitrate_kbps = + Max(bitrate_table[cfg->version][cfg->vbr_min_bitrate_index], + gfp->VBR_mean_bitrate_kbps); + } + + cfg->preset = gfp->preset; + cfg->write_lame_tag = gfp->write_lame_tag; + gfc->sv_qnt.substep_shaping = gfp->substep_shaping; + cfg->noise_shaping = gfp->noise_shaping; + cfg->subblock_gain = gfp->subblock_gain; + cfg->use_best_huffman = gfp->use_best_huffman; + cfg->avg_bitrate = gfp->brate; + cfg->vbr_avg_bitrate_kbps = gfp->VBR_mean_bitrate_kbps; + cfg->compression_ratio = gfp->compression_ratio; + + /* initialize internal qval settings */ + lame_init_qval(gfp); + + + /* automatic ATH adjustment on + */ + if (gfp->athaa_type < 0) + gfc->ATH->use_adjust = 3; + else + gfc->ATH->use_adjust = gfp->athaa_type; + + + /* initialize internal adaptive ATH settings -jd */ + gfc->ATH->aa_sensitivity_p = pow(10.0, gfp->athaa_sensitivity / -10.0); + + + if (gfp->short_blocks == short_block_not_set) { + gfp->short_blocks = short_block_allowed; + } + + /*Note Jan/2003: Many hardware decoders cannot handle short blocks in regular + stereo mode unless they are coupled (same type in both channels) + it is a rare event (1 frame per min. or so) that LAME would use + uncoupled short blocks, so lets turn them off until we decide + how to handle this. No other encoders allow uncoupled short blocks, + even though it is in the standard. */ + /* rh 20040217: coupling makes no sense for mono and dual-mono streams + */ + if (gfp->short_blocks == short_block_allowed + && (cfg->mode == JOINT_STEREO || cfg->mode == STEREO)) { + gfp->short_blocks = short_block_coupled; + } + + cfg->short_blocks = gfp->short_blocks; + + + if (lame_get_quant_comp(gfp) < 0) + (void) lame_set_quant_comp(gfp, 1); + if (lame_get_quant_comp_short(gfp) < 0) + (void) lame_set_quant_comp_short(gfp, 0); + + if (lame_get_msfix(gfp) < 0) + lame_set_msfix(gfp, 0); + + /* select psychoacoustic model */ + (void) lame_set_exp_nspsytune(gfp, lame_get_exp_nspsytune(gfp) | 1); + + if (gfp->ATHtype < 0) + gfp->ATHtype = 4; + + if (gfp->ATHcurve < 0) + gfp->ATHcurve = 4; + + if (gfp->interChRatio < 0) + gfp->interChRatio = 0; + + if (gfp->useTemporal < 0) + gfp->useTemporal = 1; /* on by default */ + + + cfg->interChRatio = gfp->interChRatio; + cfg->msfix = gfp->msfix; + cfg->ATH_offset_db = 0-gfp->ATH_lower_db; + cfg->ATH_offset_factor = powf(10.f, cfg->ATH_offset_db * 0.1f); + cfg->ATHcurve = gfp->ATHcurve; + cfg->ATHtype = gfp->ATHtype; + cfg->ATHonly = gfp->ATHonly; + cfg->ATHshort = gfp->ATHshort; + cfg->noATH = gfp->noATH; + + cfg->quant_comp = gfp->quant_comp; + cfg->quant_comp_short = gfp->quant_comp_short; + + cfg->use_temporal_masking_effect = gfp->useTemporal; + if (cfg->mode == JOINT_STEREO) { + cfg->use_safe_joint_stereo = gfp->exp_nspsytune & 2; + } + else { + cfg->use_safe_joint_stereo = 0; + } + { + cfg->adjust_bass_db = (gfp->exp_nspsytune >> 2) & 63; + if (cfg->adjust_bass_db >= 32.f) + cfg->adjust_bass_db -= 64.f; + cfg->adjust_bass_db *= 0.25f; + + cfg->adjust_alto_db = (gfp->exp_nspsytune >> 8) & 63; + if (cfg->adjust_alto_db >= 32.f) + cfg->adjust_alto_db -= 64.f; + cfg->adjust_alto_db *= 0.25f; + + cfg->adjust_treble_db = (gfp->exp_nspsytune >> 14) & 63; + if (cfg->adjust_treble_db >= 32.f) + cfg->adjust_treble_db -= 64.f; + cfg->adjust_treble_db *= 0.25f; + + /* to be compatible with Naoki's original code, the next 6 bits + * define only the amount of changing treble for sfb21 */ + cfg->adjust_sfb21_db = (gfp->exp_nspsytune >> 20) & 63; + if (cfg->adjust_sfb21_db >= 32.f) + cfg->adjust_sfb21_db -= 64.f; + cfg->adjust_sfb21_db *= 0.25f; + cfg->adjust_sfb21_db += cfg->adjust_treble_db; + } + + /* Setting up the PCM input data transform matrix, to apply + * user defined re-scaling, and or two-to-one channel downmix. + */ + { + FLOAT m[2][2] = { {1.0f, 0.0f}, {0.0f, 1.0f} }; + + /* user selected scaling of the samples */ + m[0][0] *= gfp->scale; + m[0][1] *= gfp->scale; + m[1][0] *= gfp->scale; + m[1][1] *= gfp->scale; + /* user selected scaling of the channel 0 (left) samples */ + m[0][0] *= gfp->scale_left; + m[0][1] *= gfp->scale_left; + /* user selected scaling of the channel 1 (right) samples */ + m[1][0] *= gfp->scale_right; + m[1][1] *= gfp->scale_right; + /* Downsample to Mono if 2 channels in and 1 channel out */ + if (cfg->channels_in == 2 && cfg->channels_out == 1) { + m[0][0] = 0.5f * (m[0][0] + m[1][0]); + m[0][1] = 0.5f * (m[0][1] + m[1][1]); + m[1][0] = 0; + m[1][1] = 0; + } + cfg->pcm_transform[0][0] = m[0][0]; + cfg->pcm_transform[0][1] = m[0][1]; + cfg->pcm_transform[1][0] = m[1][0]; + cfg->pcm_transform[1][1] = m[1][1]; + } + + /* padding method as described in + * "MPEG-Layer3 / Bitstream Syntax and Decoding" + * by Martin Sieler, Ralph Sperschneider + * + * note: there is no padding for the very first frame + * + * Robert Hegemann 2000-06-22 + */ + gfc->sv_enc.slot_lag = gfc->sv_enc.frac_SpF = 0; + if (cfg->vbr == vbr_off) + gfc->sv_enc.slot_lag = gfc->sv_enc.frac_SpF + = ((cfg->version + 1) * 72000L * cfg->avg_bitrate) % cfg->samplerate_out; + + (void) lame_init_bitstream(gfp); + + iteration_init(gfc); + (void) psymodel_init(gfp); + + cfg->buffer_constraint = get_max_frame_buffer_size_by_constraint(cfg, gfp->strict_ISO); + + + cfg->findReplayGain = gfp->findReplayGain; + cfg->decode_on_the_fly = gfp->decode_on_the_fly; + + if (cfg->decode_on_the_fly) + cfg->findPeakSample = 1; + + if (cfg->findReplayGain) { + if (InitGainAnalysis(gfc->sv_rpg.rgdata, cfg->samplerate_out) == INIT_GAIN_ANALYSIS_ERROR) { + /* Actually this never happens, our samplerates are the ones RG accepts! + * But just in case, turn RG off + */ + assert(0); + cfg->findReplayGain = 0; + } + } + +#ifdef DECODE_ON_THE_FLY + if (cfg->decode_on_the_fly && !gfp->decode_only) { + if (gfc->hip) { + hip_decode_exit(gfc->hip); + } + gfc->hip = hip_decode_init(); + /* report functions */ + hip_set_errorf(gfc->hip, gfp->report.errorf); + hip_set_debugf(gfc->hip, gfp->report.debugf); + hip_set_msgf(gfc->hip, gfp->report.msgf); + } +#endif + /* updating lame internal flags finished successful */ + gfc->lame_init_params_successful = 1; + return 0; +} + +static void +concatSep(char* dest, char const* sep, char const* str) +{ + if (*dest != 0) strcat(dest, sep); + strcat(dest, str); +} + +/* + * print_config + * + * Prints some selected information about the coding parameters via + * the macro command MSGF(), which is currently mapped to lame_errorf + * (reports via a error function?), which is a printf-like function + * for . + */ + +void +lame_print_config(const lame_global_flags * gfp) +{ + lame_internal_flags const *const gfc = gfp->internal_flags; + SessionConfig_t const *const cfg = &gfc->cfg; + double const out_samplerate = cfg->samplerate_out; + double const in_samplerate = cfg->samplerate_in; + + MSGF(gfc, "LAME %s %s (%s)\n", get_lame_version(), get_lame_os_bitness(), get_lame_url()); + +#if (LAME_ALPHA_VERSION) + MSGF(gfc, "warning: alpha versions should be used for testing only\n"); +#endif + if (gfc->CPU_features.MMX + || gfc->CPU_features.AMD_3DNow || gfc->CPU_features.SSE || gfc->CPU_features.SSE2) { + char text[256] = { 0 }; + int fft_asm_used = 0; +#ifdef HAVE_NASM + if (gfc->CPU_features.AMD_3DNow) { + fft_asm_used = 1; + } + else if (gfc->CPU_features.SSE) { + fft_asm_used = 2; + } +#else +# if defined( HAVE_XMMINTRIN_H ) && defined( MIN_ARCH_SSE ) + { + fft_asm_used = 3; + } +# endif +#endif + if (gfc->CPU_features.MMX) { +#ifdef MMX_choose_table + concatSep(text, ", ", "MMX (ASM used)"); +#else + concatSep(text, ", ", "MMX"); +#endif + } + if (gfc->CPU_features.AMD_3DNow) { + concatSep(text, ", ", (fft_asm_used == 1) ? "3DNow! (ASM used)" : "3DNow!"); + } + if (gfc->CPU_features.SSE) { +#if defined(HAVE_XMMINTRIN_H) + concatSep(text, ", ", "SSE (ASM used)"); +#else + concatSep(text, ", ", (fft_asm_used == 2) ? "SSE (ASM used)" : "SSE"); +#endif + } + if (gfc->CPU_features.SSE2) { + concatSep(text, ", ", (fft_asm_used == 3) ? "SSE2 (ASM used)" : "SSE2"); + } + MSGF(gfc, "CPU features: %s\n", text); + } + + if (cfg->channels_in == 2 && cfg->channels_out == 1 /* mono */ ) { + MSGF(gfc, "Autoconverting from stereo to mono. Setting encoding to mono mode.\n"); + } + + if (isResamplingNecessary(cfg)) { + MSGF(gfc, "Resampling: input %g kHz output %g kHz\n", + 1.e-3 * in_samplerate, 1.e-3 * out_samplerate); + } + + if (cfg->highpass2 > 0.) + MSGF(gfc, + "Using polyphase highpass filter, transition band: %5.0f Hz - %5.0f Hz\n", + 0.5 * cfg->highpass1 * out_samplerate, 0.5 * cfg->highpass2 * out_samplerate); + if (0. < cfg->lowpass1 || 0. < cfg->lowpass2) { + MSGF(gfc, + "Using polyphase lowpass filter, transition band: %5.0f Hz - %5.0f Hz\n", + 0.5 * cfg->lowpass1 * out_samplerate, 0.5 * cfg->lowpass2 * out_samplerate); + } + else { + MSGF(gfc, "polyphase lowpass filter disabled\n"); + } + + if (cfg->free_format) { + MSGF(gfc, "Warning: many decoders cannot handle free format bitstreams\n"); + if (cfg->avg_bitrate > 320) { + MSGF(gfc, + "Warning: many decoders cannot handle free format bitrates >320 kbps (see documentation)\n"); + } + } +} + + +/** rh: + * some pretty printing is very welcome at this point! + * so, if someone is willing to do so, please do it! + * add more, if you see more... + */ +void +lame_print_internals(const lame_global_flags * gfp) +{ + lame_internal_flags const *const gfc = gfp->internal_flags; + SessionConfig_t const *const cfg = &gfc->cfg; + const char *pc = ""; + + /* compiler/processor optimizations, operational, etc. + */ + MSGF(gfc, "\nmisc:\n\n"); + + MSGF(gfc, "\tscaling: %g\n", gfp->scale); + MSGF(gfc, "\tch0 (left) scaling: %g\n", gfp->scale_left); + MSGF(gfc, "\tch1 (right) scaling: %g\n", gfp->scale_right); + switch (cfg->use_best_huffman) { + default: + pc = "normal"; + break; + case 1: + pc = "best (outside loop)"; + break; + case 2: + pc = "best (inside loop, slow)"; + break; + } + MSGF(gfc, "\thuffman search: %s\n", pc); + MSGF(gfc, "\texperimental Y=%d\n", gfp->experimentalY); + MSGF(gfc, "\t...\n"); + + /* everything controlling the stream format + */ + MSGF(gfc, "\nstream format:\n\n"); + switch (cfg->version) { + case 0: + pc = "2.5"; + break; + case 1: + pc = "1"; + break; + case 2: + pc = "2"; + break; + default: + pc = "?"; + break; + } + MSGF(gfc, "\tMPEG-%s Layer 3\n", pc); + switch (cfg->mode) { + case JOINT_STEREO: + pc = "joint stereo"; + break; + case STEREO: + pc = "stereo"; + break; + case DUAL_CHANNEL: + pc = "dual channel"; + break; + case MONO: + pc = "mono"; + break; + case NOT_SET: + pc = "not set (error)"; + break; + default: + pc = "unknown (error)"; + break; + } + MSGF(gfc, "\t%d channel - %s\n", cfg->channels_out, pc); + + switch (cfg->vbr) { + case vbr_off: + pc = "off"; + break; + default: + pc = "all"; + break; + } + MSGF(gfc, "\tpadding: %s\n", pc); + + if (vbr_default == cfg->vbr) + pc = "(default)"; + else if (cfg->free_format) + pc = "(free format)"; + else + pc = ""; + switch (cfg->vbr) { + case vbr_off: + MSGF(gfc, "\tconstant bitrate - CBR %s\n", pc); + break; + case vbr_abr: + MSGF(gfc, "\tvariable bitrate - ABR %s\n", pc); + break; + case vbr_rh: + MSGF(gfc, "\tvariable bitrate - VBR rh %s\n", pc); + break; + case vbr_mt: + MSGF(gfc, "\tvariable bitrate - VBR mt %s\n", pc); + break; + case vbr_mtrh: + MSGF(gfc, "\tvariable bitrate - VBR mtrh %s\n", pc); + break; + default: + MSGF(gfc, "\t ?? oops, some new one ?? \n"); + break; + } + if (cfg->write_lame_tag) + MSGF(gfc, "\tusing LAME Tag\n"); + MSGF(gfc, "\t...\n"); + + /* everything controlling psychoacoustic settings, like ATH, etc. + */ + MSGF(gfc, "\npsychoacoustic:\n\n"); + + switch (cfg->short_blocks) { + default: + case short_block_not_set: + pc = "?"; + break; + case short_block_allowed: + pc = "allowed"; + break; + case short_block_coupled: + pc = "channel coupled"; + break; + case short_block_dispensed: + pc = "dispensed"; + break; + case short_block_forced: + pc = "forced"; + break; + } + MSGF(gfc, "\tusing short blocks: %s\n", pc); + MSGF(gfc, "\tsubblock gain: %d\n", cfg->subblock_gain); + MSGF(gfc, "\tadjust masking: %g dB\n", gfc->sv_qnt.mask_adjust); + MSGF(gfc, "\tadjust masking short: %g dB\n", gfc->sv_qnt.mask_adjust_short); + MSGF(gfc, "\tquantization comparison: %d\n", cfg->quant_comp); + MSGF(gfc, "\t ^ comparison short blocks: %d\n", cfg->quant_comp_short); + MSGF(gfc, "\tnoise shaping: %d\n", cfg->noise_shaping); + MSGF(gfc, "\t ^ amplification: %d\n", cfg->noise_shaping_amp); + MSGF(gfc, "\t ^ stopping: %d\n", cfg->noise_shaping_stop); + + pc = "using"; + if (cfg->ATHshort) + pc = "the only masking for short blocks"; + if (cfg->ATHonly) + pc = "the only masking"; + if (cfg->noATH) + pc = "not used"; + MSGF(gfc, "\tATH: %s\n", pc); + MSGF(gfc, "\t ^ type: %d\n", cfg->ATHtype); + MSGF(gfc, "\t ^ shape: %g%s\n", cfg->ATHcurve, " (only for type 4)"); + MSGF(gfc, "\t ^ level adjustement: %g dB\n", cfg->ATH_offset_db); + MSGF(gfc, "\t ^ adjust type: %d\n", gfc->ATH->use_adjust); + MSGF(gfc, "\t ^ adjust sensitivity power: %f\n", gfc->ATH->aa_sensitivity_p); + + MSGF(gfc, "\texperimental psy tunings by Naoki Shibata\n"); + MSGF(gfc, "\t adjust masking bass=%g dB, alto=%g dB, treble=%g dB, sfb21=%g dB\n", + 10 * log10(gfc->sv_qnt.longfact[0]), + 10 * log10(gfc->sv_qnt.longfact[7]), + 10 * log10(gfc->sv_qnt.longfact[14]), 10 * log10(gfc->sv_qnt.longfact[21])); + + pc = cfg->use_temporal_masking_effect ? "yes" : "no"; + MSGF(gfc, "\tusing temporal masking effect: %s\n", pc); + MSGF(gfc, "\tinterchannel masking ratio: %g\n", cfg->interChRatio); + MSGF(gfc, "\t...\n"); + + /* that's all ? + */ + MSGF(gfc, "\n"); + return; +} + + +static void +save_gain_values(lame_internal_flags * gfc) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + RpgStateVar_t const *const rsv = &gfc->sv_rpg; + RpgResult_t *const rov = &gfc->ov_rpg; + /* save the ReplayGain value */ + if (cfg->findReplayGain) { + FLOAT const RadioGain = (FLOAT) GetTitleGain(rsv->rgdata); + if (NEQ(RadioGain, GAIN_NOT_ENOUGH_SAMPLES)) { + rov->RadioGain = (int) floor(RadioGain * 10.0 + 0.5); /* round to nearest */ + } + else { + rov->RadioGain = 0; + } + } + + /* find the gain and scale change required for no clipping */ + if (cfg->findPeakSample) { + rov->noclipGainChange = (int) ceil(log10(rov->PeakSample / 32767.0) * 20.0 * 10.0); /* round up */ + + if (rov->noclipGainChange > 0) { /* clipping occurs */ + rov->noclipScale = floor((32767.0f / rov->PeakSample) * 100.0f) / 100.0f; /* round down */ + } + else /* no clipping */ + rov->noclipScale = -1.0f; + } +} + + + +static int +update_inbuffer_size(lame_internal_flags * gfc, const int nsamples) +{ + EncStateVar_t *const esv = &gfc->sv_enc; + if (esv->in_buffer_0 == 0 || esv->in_buffer_nsamples < nsamples) { + if (esv->in_buffer_0) { + free(esv->in_buffer_0); + } + if (esv->in_buffer_1) { + free(esv->in_buffer_1); + } + esv->in_buffer_0 = lame_calloc(sample_t, nsamples); + esv->in_buffer_1 = lame_calloc(sample_t, nsamples); + esv->in_buffer_nsamples = nsamples; + } + if (esv->in_buffer_0 == NULL || esv->in_buffer_1 == NULL) { + if (esv->in_buffer_0) { + free(esv->in_buffer_0); + } + if (esv->in_buffer_1) { + free(esv->in_buffer_1); + } + esv->in_buffer_0 = 0; + esv->in_buffer_1 = 0; + esv->in_buffer_nsamples = 0; + ERRORF(gfc, "Error: can't allocate in_buffer buffer\n"); + return -2; + } + return 0; +} + + +static int +calcNeeded(SessionConfig_t const * cfg) +{ + int mf_needed; + int pcm_samples_per_frame = 576 * cfg->mode_gr; + + /* some sanity checks */ +#if ENCDELAY < MDCTDELAY +# error ENCDELAY is less than MDCTDELAY, see encoder.h +#endif +#if FFTOFFSET > BLKSIZE +# error FFTOFFSET is greater than BLKSIZE, see encoder.h +#endif + + mf_needed = BLKSIZE + pcm_samples_per_frame - FFTOFFSET; /* amount needed for FFT */ + /*mf_needed = Max(mf_needed, 286 + 576 * (1 + gfc->mode_gr)); */ + mf_needed = Max(mf_needed, 512 + pcm_samples_per_frame - 32); + + assert(MFSIZE >= mf_needed); + + return mf_needed; +} + + +/* + * THE MAIN LAME ENCODING INTERFACE + * mt 3/00 + * + * input pcm data, output (maybe) mp3 frames. + * This routine handles all buffering, resampling and filtering for you. + * The required mp3buffer_size can be computed from num_samples, + * samplerate and encoding rate, but here is a worst case estimate: + * + * mp3buffer_size in bytes = 1.25*num_samples + 7200 + * + * return code = number of bytes output in mp3buffer. can be 0 + * + * NOTE: this routine uses LAME's internal PCM data representation, + * 'sample_t'. It should not be used by any application. + * applications should use lame_encode_buffer(), + * lame_encode_buffer_float() + * lame_encode_buffer_int() + * etc... depending on what type of data they are working with. +*/ +static int +lame_encode_buffer_sample_t(lame_internal_flags * gfc, + int nsamples, unsigned char *mp3buf, const int mp3buf_size) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncStateVar_t *const esv = &gfc->sv_enc; + int pcm_samples_per_frame = 576 * cfg->mode_gr; + int mp3size = 0, ret, i, ch, mf_needed; + int mp3out; + sample_t *mfbuf[2]; + sample_t *in_buffer[2]; + + if (gfc->class_id != LAME_ID) + return -3; + + if (nsamples == 0) + return 0; + + /* copy out any tags that may have been written into bitstream */ + { /* if user specifed buffer size = 0, dont check size */ + int const buf_size = mp3buf_size == 0 ? INT_MAX : mp3buf_size; + mp3out = copy_buffer(gfc, mp3buf, buf_size, 0); + } + if (mp3out < 0) + return mp3out; /* not enough buffer space */ + mp3buf += mp3out; + mp3size += mp3out; + + in_buffer[0] = esv->in_buffer_0; + in_buffer[1] = esv->in_buffer_1; + + mf_needed = calcNeeded(cfg); + + mfbuf[0] = esv->mfbuf[0]; + mfbuf[1] = esv->mfbuf[1]; + + while (nsamples > 0) { + sample_t const *in_buffer_ptr[2]; + int n_in = 0; /* number of input samples processed with fill_buffer */ + int n_out = 0; /* number of samples output with fill_buffer */ + /* n_in <> n_out if we are resampling */ + + in_buffer_ptr[0] = in_buffer[0]; + in_buffer_ptr[1] = in_buffer[1]; + /* copy in new samples into mfbuf, with resampling */ + fill_buffer(gfc, mfbuf, &in_buffer_ptr[0], nsamples, &n_in, &n_out); + + /* compute ReplayGain of resampled input if requested */ + if (cfg->findReplayGain && !cfg->decode_on_the_fly) + if (AnalyzeSamples + (gfc->sv_rpg.rgdata, &mfbuf[0][esv->mf_size], &mfbuf[1][esv->mf_size], n_out, + cfg->channels_out) == GAIN_ANALYSIS_ERROR) + return -6; + + + + /* update in_buffer counters */ + nsamples -= n_in; + in_buffer[0] += n_in; + if (cfg->channels_out == 2) + in_buffer[1] += n_in; + + /* update mfbuf[] counters */ + esv->mf_size += n_out; + assert(esv->mf_size <= MFSIZE); + + /* lame_encode_flush may have set gfc->mf_sample_to_encode to 0 + * so we have to reinitialize it here when that happened. + */ + if (esv->mf_samples_to_encode < 1) { + esv->mf_samples_to_encode = ENCDELAY + POSTDELAY; + } + esv->mf_samples_to_encode += n_out; + + + if (esv->mf_size >= mf_needed) { + /* encode the frame. */ + /* mp3buf = pointer to current location in buffer */ + /* mp3buf_size = size of original mp3 output buffer */ + /* = 0 if we should not worry about the */ + /* buffer size because calling program is */ + /* to lazy to compute it */ + /* mp3size = size of data written to buffer so far */ + /* mp3buf_size-mp3size = amount of space avalable */ + + int buf_size = mp3buf_size - mp3size; + if (mp3buf_size == 0) + buf_size = INT_MAX; + + ret = lame_encode_mp3_frame(gfc, mfbuf[0], mfbuf[1], mp3buf, buf_size); + + if (ret < 0) + return ret; + mp3buf += ret; + mp3size += ret; + + /* shift out old samples */ + esv->mf_size -= pcm_samples_per_frame; + esv->mf_samples_to_encode -= pcm_samples_per_frame; + for (ch = 0; ch < cfg->channels_out; ch++) + for (i = 0; i < esv->mf_size; i++) + mfbuf[ch][i] = mfbuf[ch][i + pcm_samples_per_frame]; + } + } + assert(nsamples == 0); + + return mp3size; +} + +enum PCMSampleType +{ pcm_short_type +, pcm_int_type +, pcm_long_type +, pcm_float_type +, pcm_double_type +}; + +static void +lame_copy_inbuffer(lame_internal_flags* gfc, + void const* l, void const* r, int nsamples, + enum PCMSampleType pcm_type, int jump, FLOAT s) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncStateVar_t *const esv = &gfc->sv_enc; + sample_t* ib0 = esv->in_buffer_0; + sample_t* ib1 = esv->in_buffer_1; + FLOAT m[2][2]; + + /* Apply user defined re-scaling */ + m[0][0] = s * cfg->pcm_transform[0][0]; + m[0][1] = s * cfg->pcm_transform[0][1]; + m[1][0] = s * cfg->pcm_transform[1][0]; + m[1][1] = s * cfg->pcm_transform[1][1]; + + /* make a copy of input buffer, changing type to sample_t */ +#define COPY_AND_TRANSFORM(T) \ +{ \ + T const *bl = l, *br = r; \ + int i; \ + for (i = 0; i < nsamples; i++) { \ + sample_t const xl = *bl; \ + sample_t const xr = *br; \ + sample_t const u = xl * m[0][0] + xr * m[0][1]; \ + sample_t const v = xl * m[1][0] + xr * m[1][1]; \ + ib0[i] = u; \ + ib1[i] = v; \ + bl += jump; \ + br += jump; \ + } \ +} + switch ( pcm_type ) { + case pcm_short_type: + COPY_AND_TRANSFORM(short int); + break; + case pcm_int_type: + COPY_AND_TRANSFORM(int); + break; + case pcm_long_type: + COPY_AND_TRANSFORM(long int); + break; + case pcm_float_type: + COPY_AND_TRANSFORM(float); + break; + case pcm_double_type: + COPY_AND_TRANSFORM(double); + break; + } +} + + +static int +lame_encode_buffer_template(lame_global_flags * gfp, + void const* buffer_l, void const* buffer_r, const int nsamples, + unsigned char *mp3buf, const int mp3buf_size, enum PCMSampleType pcm_type, int aa, FLOAT norm) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + SessionConfig_t const *const cfg = &gfc->cfg; + + if (nsamples == 0) + return 0; + + if (update_inbuffer_size(gfc, nsamples) != 0) { + return -2; + } + /* make a copy of input buffer, changing type to sample_t */ + if (cfg->channels_in > 1) { + if (buffer_l == 0 || buffer_r == 0) { + return 0; + } + lame_copy_inbuffer(gfc, buffer_l, buffer_r, nsamples, pcm_type, aa, norm); + } + else { + if (buffer_l == 0) { + return 0; + } + lame_copy_inbuffer(gfc, buffer_l, buffer_l, nsamples, pcm_type, aa, norm); + } + + return lame_encode_buffer_sample_t(gfc, nsamples, mp3buf, mp3buf_size); + } + } + return -3; +} + +int +lame_encode_buffer(lame_global_flags * gfp, + const short int pcm_l[], const short int pcm_r[], const int nsamples, + unsigned char *mp3buf, const int mp3buf_size) +{ + return lame_encode_buffer_template(gfp, pcm_l, pcm_r, nsamples, mp3buf, mp3buf_size, pcm_short_type, 1, 1.0); +} + + +int +lame_encode_buffer_float(lame_global_flags * gfp, + const float pcm_l[], const float pcm_r[], const int nsamples, + unsigned char *mp3buf, const int mp3buf_size) +{ + /* input is assumed to be normalized to +/- 32768 for full scale */ + return lame_encode_buffer_template(gfp, pcm_l, pcm_r, nsamples, mp3buf, mp3buf_size, pcm_float_type, 1, 1.0); +} + + +int +lame_encode_buffer_ieee_float(lame_t gfp, + const float pcm_l[], const float pcm_r[], const int nsamples, + unsigned char *mp3buf, const int mp3buf_size) +{ + /* input is assumed to be normalized to +/- 1.0 for full scale */ + return lame_encode_buffer_template(gfp, pcm_l, pcm_r, nsamples, mp3buf, mp3buf_size, pcm_float_type, 1, 32767.0); +} + + +int +lame_encode_buffer_interleaved_ieee_float(lame_t gfp, + const float pcm[], const int nsamples, + unsigned char *mp3buf, const int mp3buf_size) +{ + /* input is assumed to be normalized to +/- 1.0 for full scale */ + return lame_encode_buffer_template(gfp, pcm, pcm+1, nsamples, mp3buf, mp3buf_size, pcm_float_type, 2, 32767.0); +} + + +int +lame_encode_buffer_ieee_double(lame_t gfp, + const double pcm_l[], const double pcm_r[], const int nsamples, + unsigned char *mp3buf, const int mp3buf_size) +{ + /* input is assumed to be normalized to +/- 1.0 for full scale */ + return lame_encode_buffer_template(gfp, pcm_l, pcm_r, nsamples, mp3buf, mp3buf_size, pcm_double_type, 1, 32767.0); +} + + +int +lame_encode_buffer_interleaved_ieee_double(lame_t gfp, + const double pcm[], const int nsamples, + unsigned char *mp3buf, const int mp3buf_size) +{ + /* input is assumed to be normalized to +/- 1.0 for full scale */ + return lame_encode_buffer_template(gfp, pcm, pcm+1, nsamples, mp3buf, mp3buf_size, pcm_double_type, 2, 32767.0); +} + + +int +lame_encode_buffer_int(lame_global_flags * gfp, + const int pcm_l[], const int pcm_r[], const int nsamples, + unsigned char *mp3buf, const int mp3buf_size) +{ + /* input is assumed to be normalized to +/- MAX_INT for full scale */ + FLOAT const norm = (1.0 / (1L << (8 * sizeof(int) - 16))); + return lame_encode_buffer_template(gfp, pcm_l, pcm_r, nsamples, mp3buf, mp3buf_size, pcm_int_type, 1, norm); +} + + +int +lame_encode_buffer_long2(lame_global_flags * gfp, + const long pcm_l[], const long pcm_r[], const int nsamples, + unsigned char *mp3buf, const int mp3buf_size) +{ + /* input is assumed to be normalized to +/- MAX_LONG for full scale */ + FLOAT const norm = (1.0 / (1L << (8 * sizeof(long) - 16))); + return lame_encode_buffer_template(gfp, pcm_l, pcm_r, nsamples, mp3buf, mp3buf_size, pcm_long_type, 1, norm); +} + + +int +lame_encode_buffer_long(lame_global_flags * gfp, + const long pcm_l[], const long pcm_r[], const int nsamples, + unsigned char *mp3buf, const int mp3buf_size) +{ + /* input is assumed to be normalized to +/- 32768 for full scale */ + return lame_encode_buffer_template(gfp, pcm_l, pcm_r, nsamples, mp3buf, mp3buf_size, pcm_long_type, 1, 1.0); +} + + + +int +lame_encode_buffer_interleaved(lame_global_flags * gfp, + short int pcm[], int nsamples, + unsigned char *mp3buf, int mp3buf_size) +{ + /* input is assumed to be normalized to +/- MAX_SHORT for full scale */ + return lame_encode_buffer_template(gfp, pcm, pcm+1, nsamples, mp3buf, mp3buf_size, pcm_short_type, 2, 1.0); +} + + +int +lame_encode_buffer_interleaved_int(lame_t gfp, + const int pcm[], const int nsamples, + unsigned char *mp3buf, const int mp3buf_size) +{ + /* input is assumed to be normalized to +/- MAX(int) for full scale */ + FLOAT const norm = (1.0 / (1L << (8 * sizeof(int)-16))); + return lame_encode_buffer_template(gfp, pcm, pcm + 1, nsamples, mp3buf, mp3buf_size, pcm_int_type, 2, norm); +} + + + + +/***************************************************************** + Flush mp3 buffer, pad with ancillary data so last frame is complete. + Reset reservoir size to 0 + but keep all PCM samples and MDCT data in memory + This option is used to break a large file into several mp3 files + that when concatenated together will decode with no gaps + Because we set the reservoir=0, they will also decode seperately + with no errors. +*********************************************************************/ +int +lame_encode_flush_nogap(lame_global_flags * gfp, unsigned char *mp3buffer, int mp3buffer_size) +{ + int rc = -3; + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + flush_bitstream(gfc); + /* if user specifed buffer size = 0, dont check size */ + if (mp3buffer_size == 0) + mp3buffer_size = INT_MAX; + rc = copy_buffer(gfc, mp3buffer, mp3buffer_size, 1); + save_gain_values(gfc); + } + } + return rc; +} + + +/* called by lame_init_params. You can also call this after flush_nogap + if you want to write new id3v2 and Xing VBR tags into the bitstream */ +int +lame_init_bitstream(lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags *const gfc = gfp->internal_flags; + if (gfc != 0) { + gfc->ov_enc.frame_number = 0; + + if (gfp->write_id3tag_automatic) { + (void) id3tag_write_v2(gfp); + } + /* initialize histogram data optionally used by frontend */ + memset(gfc->ov_enc.bitrate_channelmode_hist, 0, + sizeof(gfc->ov_enc.bitrate_channelmode_hist)); + memset(gfc->ov_enc.bitrate_blocktype_hist, 0, + sizeof(gfc->ov_enc.bitrate_blocktype_hist)); + + gfc->ov_rpg.PeakSample = 0.0; + + /* Write initial VBR Header to bitstream and init VBR data */ + if (gfc->cfg.write_lame_tag) + (void) InitVbrTag(gfp); + + + return 0; + } + } + return -3; +} + + +/*****************************************************************/ +/* flush internal PCM sample buffers, then mp3 buffers */ +/* then write id3 v1 tags into bitstream. */ +/*****************************************************************/ + +int +lame_encode_flush(lame_global_flags * gfp, unsigned char *mp3buffer, int mp3buffer_size) +{ + lame_internal_flags *gfc; + SessionConfig_t const *cfg; + EncStateVar_t *esv; + short int buffer[2][1152]; + int imp3 = 0, mp3count, mp3buffer_size_remaining; + + /* we always add POSTDELAY=288 padding to make sure granule with real + * data can be complety decoded (because of 50% overlap with next granule */ + int end_padding; + int frames_left; + int samples_to_encode; + int pcm_samples_per_frame; + int mf_needed; + int is_resampling_necessary; + double resample_ratio = 1; + + if (!is_lame_global_flags_valid(gfp)) { + return -3; + } + gfc = gfp->internal_flags; + if (!is_lame_internal_flags_valid(gfc)) { + return -3; + } + cfg = &gfc->cfg; + esv = &gfc->sv_enc; + + /* Was flush already called? */ + if (esv->mf_samples_to_encode < 1) { + return 0; + } + pcm_samples_per_frame = 576 * cfg->mode_gr; + mf_needed = calcNeeded(cfg); + + samples_to_encode = esv->mf_samples_to_encode - POSTDELAY; + + memset(buffer, 0, sizeof(buffer)); + mp3count = 0; + + is_resampling_necessary = isResamplingNecessary(cfg); + if (is_resampling_necessary) { + resample_ratio = (double)cfg->samplerate_in / (double)cfg->samplerate_out; + /* delay due to resampling; needs to be fixed, if resampling code gets changed */ + samples_to_encode += 16. / resample_ratio; + } + end_padding = pcm_samples_per_frame - (samples_to_encode % pcm_samples_per_frame); + if (end_padding < 576) + end_padding += pcm_samples_per_frame; + gfc->ov_enc.encoder_padding = end_padding; + + frames_left = (samples_to_encode + end_padding) / pcm_samples_per_frame; + while (frames_left > 0 && imp3 >= 0) { + int const frame_num = gfc->ov_enc.frame_number; + int bunch = mf_needed - esv->mf_size; + + bunch *= resample_ratio; + if (bunch > 1152) bunch = 1152; + if (bunch < 1) bunch = 1; + + mp3buffer_size_remaining = mp3buffer_size - mp3count; + + /* if user specifed buffer size = 0, dont check size */ + if (mp3buffer_size == 0) + mp3buffer_size_remaining = 0; + + /* send in a frame of 0 padding until all internal sample buffers + * are flushed + */ + imp3 = lame_encode_buffer(gfp, buffer[0], buffer[1], bunch, + mp3buffer, mp3buffer_size_remaining); + + mp3buffer += imp3; + mp3count += imp3; + { /* even a single pcm sample can produce several frames! + * for example: 1 Hz input file resampled to 8 kHz mpeg2.5 + */ + int const new_frames = gfc->ov_enc.frame_number - frame_num; + if (new_frames > 0) + frames_left -= new_frames; + } + } + /* Set esv->mf_samples_to_encode to 0, so we may detect + * and break loops calling it more than once in a row. + */ + esv->mf_samples_to_encode = 0; + + if (imp3 < 0) { + /* some type of fatal error */ + return imp3; + } + + mp3buffer_size_remaining = mp3buffer_size - mp3count; + /* if user specifed buffer size = 0, dont check size */ + if (mp3buffer_size == 0) + mp3buffer_size_remaining = INT_MAX; + + /* mp3 related stuff. bit buffer might still contain some mp3 data */ + flush_bitstream(gfc); + imp3 = copy_buffer(gfc, mp3buffer, mp3buffer_size_remaining, 1); + save_gain_values(gfc); + if (imp3 < 0) { + /* some type of fatal error */ + return imp3; + } + mp3buffer += imp3; + mp3count += imp3; + mp3buffer_size_remaining = mp3buffer_size - mp3count; + /* if user specifed buffer size = 0, dont check size */ + if (mp3buffer_size == 0) + mp3buffer_size_remaining = INT_MAX; + + if (gfp->write_id3tag_automatic) { + /* write a id3 tag to the bitstream */ + (void) id3tag_write_v1(gfp); + + imp3 = copy_buffer(gfc, mp3buffer, mp3buffer_size_remaining, 0); + + if (imp3 < 0) { + return imp3; + } + mp3count += imp3; + } +#if 0 + { + int const ed = gfc->ov_enc.encoder_delay; + int const ep = gfc->ov_enc.encoder_padding; + int const ns = (gfc->ov_enc.frame_number * pcm_samples_per_frame) - (ed + ep); + double duration = ns; + duration /= cfg->samplerate_out; + MSGF(gfc, "frames=%d\n", gfc->ov_enc.frame_number); + MSGF(gfc, "pcm_samples_per_frame=%d\n", pcm_samples_per_frame); + MSGF(gfc, "encoder delay=%d\n", ed); + MSGF(gfc, "encoder padding=%d\n", ep); + MSGF(gfc, "sample count=%d (%g)\n", ns, cfg->samplerate_in * duration); + MSGF(gfc, "duration=%g sec\n", duration); + } +#endif + return mp3count; +} + +/*********************************************************************** + * + * lame_close () + * + * frees internal buffers + * + ***********************************************************************/ + +int +lame_close(lame_global_flags * gfp) +{ + int ret = 0; + if (gfp && gfp->class_id == LAME_ID) { + lame_internal_flags *const gfc = gfp->internal_flags; + gfp->class_id = 0; + if (NULL == gfc || gfc->class_id != LAME_ID) { + ret = -3; + } + if (NULL != gfc) { + gfc->lame_init_params_successful = 0; + gfc->class_id = 0; + /* this routine will free all malloc'd data in gfc, and then free gfc: */ + freegfc(gfc); + gfp->internal_flags = NULL; + } + if (gfp->lame_allocated_gfp) { + gfp->lame_allocated_gfp = 0; + free(gfp); + } + } + return ret; +} + +/*****************************************************************/ +/* flush internal mp3 buffers, and free internal buffers */ +/*****************************************************************/ +#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED +int CDECL +lame_encode_finish(lame_global_flags * gfp, unsigned char *mp3buffer, int mp3buffer_size); +#else +#endif + +int +lame_encode_finish(lame_global_flags * gfp, unsigned char *mp3buffer, int mp3buffer_size) +{ + int const ret = lame_encode_flush(gfp, mp3buffer, mp3buffer_size); + + (void) lame_close(gfp); + + return ret; +} + +/*****************************************************************/ +/* write VBR Xing header, and ID3 version 1 tag, if asked for */ +/*****************************************************************/ +void lame_mp3_tags_fid(lame_global_flags * gfp, FILE * fpStream); + +void +lame_mp3_tags_fid(lame_global_flags * gfp, FILE * fpStream) +{ + lame_internal_flags *gfc; + SessionConfig_t const *cfg; + if (!is_lame_global_flags_valid(gfp)) { + return; + } + gfc = gfp->internal_flags; + if (!is_lame_internal_flags_valid(gfc)) { + return; + } + cfg = &gfc->cfg; + if (!cfg->write_lame_tag) { + return; + } + /* Write Xing header again */ + if (fpStream && !fseek(fpStream, 0, SEEK_SET)) { + int rc = PutVbrTag(gfp, fpStream); + switch (rc) { + default: + /* OK */ + break; + + case -1: + ERRORF(gfc, "Error: could not update LAME tag.\n"); + break; + + case -2: + ERRORF(gfc, "Error: could not update LAME tag, file not seekable.\n"); + break; + + case -3: + ERRORF(gfc, "Error: could not update LAME tag, file not readable.\n"); + break; + } + } +} + + +static int +lame_init_internal_flags(lame_internal_flags* gfc) +{ + if (NULL == gfc) + return -1; + + gfc->cfg.vbr_min_bitrate_index = 1; /* not 0 ????? */ + gfc->cfg.vbr_max_bitrate_index = 13; /* not 14 ????? */ + gfc->cfg.decode_on_the_fly = 0; + gfc->cfg.findReplayGain = 0; + gfc->cfg.findPeakSample = 0; + + gfc->sv_qnt.OldValue[0] = 180; + gfc->sv_qnt.OldValue[1] = 180; + gfc->sv_qnt.CurrentStep[0] = 4; + gfc->sv_qnt.CurrentStep[1] = 4; + gfc->sv_qnt.masking_lower = 1; + + /* The reason for + * int mf_samples_to_encode = ENCDELAY + POSTDELAY; + * ENCDELAY = internal encoder delay. And then we have to add POSTDELAY=288 + * because of the 50% MDCT overlap. A 576 MDCT granule decodes to + * 1152 samples. To synthesize the 576 samples centered under this granule + * we need the previous granule for the first 288 samples (no problem), and + * the next granule for the next 288 samples (not possible if this is last + * granule). So we need to pad with 288 samples to make sure we can + * encode the 576 samples we are interested in. + */ + gfc->sv_enc.mf_samples_to_encode = ENCDELAY + POSTDELAY; + gfc->sv_enc.mf_size = ENCDELAY - MDCTDELAY; /* we pad input with this many 0's */ + gfc->ov_enc.encoder_padding = 0; + gfc->ov_enc.encoder_delay = ENCDELAY; + + gfc->ov_rpg.RadioGain = 0; + gfc->ov_rpg.noclipGainChange = 0; + gfc->ov_rpg.noclipScale = -1.0; + + gfc->ATH = lame_calloc(ATH_t, 1); + if (NULL == gfc->ATH) + return -2; /* maybe error codes should be enumerated in lame.h ?? */ + + gfc->sv_rpg.rgdata = lame_calloc(replaygain_t, 1); + if (NULL == gfc->sv_rpg.rgdata) { + return -2; + } + return 0; +} + +/* initialize mp3 encoder */ +#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED +static +#else +#endif +int +lame_init_old(lame_global_flags * gfp) +{ + disable_FPE(); /* disable floating point exceptions */ + + memset(gfp, 0, sizeof(lame_global_flags)); + + gfp->class_id = LAME_ID; + + /* Global flags. set defaults here for non-zero values */ + /* see lame.h for description */ + /* set integer values to -1 to mean that LAME will compute the + * best value, UNLESS the calling program as set it + * (and the value is no longer -1) + */ + gfp->strict_ISO = MDB_MAXIMUM; + + gfp->mode = NOT_SET; + gfp->original = 1; + gfp->samplerate_in = 44100; + gfp->num_channels = 2; + gfp->num_samples = MAX_U_32_NUM; + + gfp->write_lame_tag = 1; + gfp->quality = -1; + gfp->short_blocks = short_block_not_set; + gfp->subblock_gain = -1; + + gfp->lowpassfreq = 0; + gfp->highpassfreq = 0; + gfp->lowpasswidth = -1; + gfp->highpasswidth = -1; + + gfp->VBR = vbr_off; + gfp->VBR_q = 4; + gfp->VBR_mean_bitrate_kbps = 128; + gfp->VBR_min_bitrate_kbps = 0; + gfp->VBR_max_bitrate_kbps = 0; + gfp->VBR_hard_min = 0; + + gfp->quant_comp = -1; + gfp->quant_comp_short = -1; + + gfp->msfix = -1; + + gfp->attackthre = -1; + gfp->attackthre_s = -1; + + gfp->scale = 1; + gfp->scale_left = 1; + gfp->scale_right = 1; + + gfp->ATHcurve = -1; + gfp->ATHtype = -1; /* default = -1 = set in lame_init_params */ + /* 2 = equal loudness curve */ + gfp->athaa_sensitivity = 0.0; /* no offset */ + gfp->athaa_type = -1; + gfp->useTemporal = -1; + gfp->interChRatio = -1; + + gfp->findReplayGain = 0; + gfp->decode_on_the_fly = 0; + + gfp->asm_optimizations.mmx = 1; + gfp->asm_optimizations.amd3dnow = 1; + gfp->asm_optimizations.sse = 1; + + gfp->preset = 0; + + gfp->write_id3tag_automatic = 1; + + gfp->report.debugf = &lame_report_def; + gfp->report.errorf = &lame_report_def; + gfp->report.msgf = &lame_report_def; + + gfp->internal_flags = lame_calloc(lame_internal_flags, 1); + + if (lame_init_internal_flags(gfp->internal_flags) < 0) { + freegfc(gfp->internal_flags); + gfp->internal_flags = 0; + return -1; + } + return 0; +} + + +lame_global_flags * +lame_init(void) +{ + lame_global_flags *gfp; + int ret; + + init_log_table(); + + gfp = lame_calloc(lame_global_flags, 1); + if (gfp == NULL) + return NULL; + + ret = lame_init_old(gfp); + if (ret != 0) { + free(gfp); + return NULL; + } + + gfp->lame_allocated_gfp = 1; + return gfp; +} + + +/*********************************************************************** + * + * some simple statistics + * + * Robert Hegemann 2000-10-11 + * + ***********************************************************************/ + +/* histogram of used bitrate indexes: + * One has to weight them to calculate the average bitrate in kbps + * + * bitrate indices: + * there are 14 possible bitrate indices, 0 has the special meaning + * "free format" which is not possible to mix with VBR and 15 is forbidden + * anyway. + * + * stereo modes: + * 0: LR number of left-right encoded frames + * 1: LR-I number of left-right and intensity encoded frames + * 2: MS number of mid-side encoded frames + * 3: MS-I number of mid-side and intensity encoded frames + * + * 4: number of encoded frames + * + */ + +void +lame_bitrate_kbps(const lame_global_flags * gfp, int bitrate_kbps[14]) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags const *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + SessionConfig_t const *const cfg = &gfc->cfg; + int i; + if (cfg->free_format) { + for (i = 0; i < 14; i++) + bitrate_kbps[i] = -1; + bitrate_kbps[0] = cfg->avg_bitrate; + } + else { + for (i = 0; i < 14; i++) + bitrate_kbps[i] = bitrate_table[cfg->version][i + 1]; + } + } + } +} + + +void +lame_bitrate_hist(const lame_global_flags * gfp, int bitrate_count[14]) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags const *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + SessionConfig_t const *const cfg = &gfc->cfg; + EncResult_t const *const eov = &gfc->ov_enc; + int i; + + if (cfg->free_format) { + for (i = 0; i < 14; i++) { + bitrate_count[i] = 0; + } + bitrate_count[0] = eov->bitrate_channelmode_hist[0][4]; + } + else { + for (i = 0; i < 14; i++) { + bitrate_count[i] = eov->bitrate_channelmode_hist[i + 1][4]; + } + } + } + } +} + + +void +lame_stereo_mode_hist(const lame_global_flags * gfp, int stmode_count[4]) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags const *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + EncResult_t const *const eov = &gfc->ov_enc; + int i; + + for (i = 0; i < 4; i++) { + stmode_count[i] = eov->bitrate_channelmode_hist[15][i]; + } + } + } +} + + + +void +lame_bitrate_stereo_mode_hist(const lame_global_flags * gfp, int bitrate_stmode_count[14][4]) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags const *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + SessionConfig_t const *const cfg = &gfc->cfg; + EncResult_t const *const eov = &gfc->ov_enc; + int i; + int j; + + if (cfg->free_format) { + for (j = 0; j < 14; j++) + for (i = 0; i < 4; i++) { + bitrate_stmode_count[j][i] = 0; + } + for (i = 0; i < 4; i++) { + bitrate_stmode_count[0][i] = eov->bitrate_channelmode_hist[0][i]; + } + } + else { + for (j = 0; j < 14; j++) { + for (i = 0; i < 4; i++) { + bitrate_stmode_count[j][i] = eov->bitrate_channelmode_hist[j + 1][i]; + } + } + } + } + } +} + + +void +lame_block_type_hist(const lame_global_flags * gfp, int btype_count[6]) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags const *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + EncResult_t const *const eov = &gfc->ov_enc; + int i; + + for (i = 0; i < 6; ++i) { + btype_count[i] = eov->bitrate_blocktype_hist[15][i]; + } + } + } +} + + + +void +lame_bitrate_block_type_hist(const lame_global_flags * gfp, int bitrate_btype_count[14][6]) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags const *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + SessionConfig_t const *const cfg = &gfc->cfg; + EncResult_t const *const eov = &gfc->ov_enc; + int i, j; + + if (cfg->free_format) { + for (j = 0; j < 14; ++j) { + for (i = 0; i < 6; ++i) { + bitrate_btype_count[j][i] = 0; + } + } + for (i = 0; i < 6; ++i) { + bitrate_btype_count[0][i] = eov->bitrate_blocktype_hist[0][i]; + } + } + else { + for (j = 0; j < 14; ++j) { + for (i = 0; i < 6; ++i) { + bitrate_btype_count[j][i] = eov->bitrate_blocktype_hist[j + 1][i]; + } + } + } + } + } +} + +/* end of lame.c */ diff --git a/pkg/lame/clame/lame.h b/pkg/lame/clame/lame.h new file mode 100644 index 0000000..5196690 --- /dev/null +++ b/pkg/lame/clame/lame.h @@ -0,0 +1,1342 @@ +/* + * Interface to MP3 LAME encoding engine + * + * Copyright (c) 1999 Mark Taylor + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* $Id: lame.h,v 1.192 2017/08/31 14:14:46 robert Exp $ */ + +#ifndef LAME_LAME_H +#define LAME_LAME_H + +/* for size_t typedef */ +#include +/* for va_list typedef */ +#include +/* for FILE typedef, TODO: remove when removing lame_mp3_tags_fid */ +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +typedef void (*lame_report_function)(const char *format, va_list ap); + +#if defined(WIN32) || defined(_WIN32) +#undef CDECL +#define CDECL __cdecl +#else +#define CDECL +#endif + +#define DEPRECATED_OR_OBSOLETE_CODE_REMOVED 1 + +typedef enum vbr_mode_e { + vbr_off=0, + vbr_mt, /* obsolete, same as vbr_mtrh */ + vbr_rh, + vbr_abr, + vbr_mtrh, + vbr_max_indicator, /* Don't use this! It's used for sanity checks. */ + vbr_default=vbr_mtrh /* change this to change the default VBR mode of LAME */ +} vbr_mode; + + +/* MPEG modes */ +typedef enum MPEG_mode_e { + STEREO = 0, + JOINT_STEREO, + DUAL_CHANNEL, /* LAME doesn't supports this! */ + MONO, + NOT_SET, + MAX_INDICATOR /* Don't use this! It's used for sanity checks. */ +} MPEG_mode; + +/* Padding types */ +typedef enum Padding_type_e { + PAD_NO = 0, + PAD_ALL, + PAD_ADJUST, + PAD_MAX_INDICATOR /* Don't use this! It's used for sanity checks. */ +} Padding_type; + + + +/*presets*/ +typedef enum preset_mode_e { + /*values from 8 to 320 should be reserved for abr bitrates*/ + /*for abr I'd suggest to directly use the targeted bitrate as a value*/ + ABR_8 = 8, + ABR_320 = 320, + + V9 = 410, /*Vx to match Lame and VBR_xx to match FhG*/ + VBR_10 = 410, + V8 = 420, + VBR_20 = 420, + V7 = 430, + VBR_30 = 430, + V6 = 440, + VBR_40 = 440, + V5 = 450, + VBR_50 = 450, + V4 = 460, + VBR_60 = 460, + V3 = 470, + VBR_70 = 470, + V2 = 480, + VBR_80 = 480, + V1 = 490, + VBR_90 = 490, + V0 = 500, + VBR_100 = 500, + + + + /*still there for compatibility*/ + R3MIX = 1000, + STANDARD = 1001, + EXTREME = 1002, + INSANE = 1003, + STANDARD_FAST = 1004, + EXTREME_FAST = 1005, + MEDIUM = 1006, + MEDIUM_FAST = 1007 +} preset_mode; + + +/*asm optimizations*/ +typedef enum asm_optimizations_e { + MMX = 1, + AMD_3DNOW = 2, + SSE = 3 +} asm_optimizations; + + +/* psychoacoustic model */ +typedef enum Psy_model_e { + PSY_GPSYCHO = 1, + PSY_NSPSYTUNE = 2 +} Psy_model; + + +/* buffer considerations */ +typedef enum buffer_constraint_e { + MDB_DEFAULT=0, + MDB_STRICT_ISO=1, + MDB_MAXIMUM=2 +} buffer_constraint; + + +struct lame_global_struct; +typedef struct lame_global_struct lame_global_flags; +typedef lame_global_flags *lame_t; + + + + +/*********************************************************************** + * + * The LAME API + * These functions should be called, in this order, for each + * MP3 file to be encoded. See the file "API" for more documentation + * + ***********************************************************************/ + + +/* + * REQUIRED: + * initialize the encoder. sets default for all encoder parameters, + * returns NULL if some malloc()'s failed + * otherwise returns pointer to structure needed for all future + * API calls. + */ +lame_global_flags * CDECL lame_init(void); +#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED +#else +/* obsolete version */ +int CDECL lame_init_old(lame_global_flags *); +#endif + +/* + * OPTIONAL: + * set as needed to override defaults + */ + +/******************************************************************** + * input stream description + ***********************************************************************/ +/* number of samples. default = 2^32-1 */ +int CDECL lame_set_num_samples(lame_global_flags *, unsigned long); +unsigned long CDECL lame_get_num_samples(const lame_global_flags *); + +/* input sample rate in Hz. default = 44100hz */ +int CDECL lame_set_in_samplerate(lame_global_flags *, int); +int CDECL lame_get_in_samplerate(const lame_global_flags *); + +/* number of channels in input stream. default=2 */ +int CDECL lame_set_num_channels(lame_global_flags *, int); +int CDECL lame_get_num_channels(const lame_global_flags *); + +/* + scale the input by this amount before encoding. default=1 + (not used by decoding routines) +*/ +int CDECL lame_set_scale(lame_global_flags *, float); +float CDECL lame_get_scale(const lame_global_flags *); + +/* + scale the channel 0 (left) input by this amount before encoding. default=1 + (not used by decoding routines) +*/ +int CDECL lame_set_scale_left(lame_global_flags *, float); +float CDECL lame_get_scale_left(const lame_global_flags *); + +/* + scale the channel 1 (right) input by this amount before encoding. default=1 + (not used by decoding routines) +*/ +int CDECL lame_set_scale_right(lame_global_flags *, float); +float CDECL lame_get_scale_right(const lame_global_flags *); + +/* + output sample rate in Hz. default = 0, which means LAME picks best value + based on the amount of compression. MPEG only allows: + MPEG1 32, 44.1, 48khz + MPEG2 16, 22.05, 24 + MPEG2.5 8, 11.025, 12 + (not used by decoding routines) +*/ +int CDECL lame_set_out_samplerate(lame_global_flags *, int); +int CDECL lame_get_out_samplerate(const lame_global_flags *); + + +/******************************************************************** + * general control parameters + ***********************************************************************/ +/* 1=cause LAME to collect data for an MP3 frame analyzer. default=0 */ +int CDECL lame_set_analysis(lame_global_flags *, int); +int CDECL lame_get_analysis(const lame_global_flags *); + +/* + 1 = write a Xing VBR header frame. + default = 1 + this variable must have been added by a Hungarian notation Windows programmer :-) +*/ +int CDECL lame_set_bWriteVbrTag(lame_global_flags *, int); +int CDECL lame_get_bWriteVbrTag(const lame_global_flags *); + +/* 1=decode only. use lame/mpglib to convert mp3/ogg to wav. default=0 */ +int CDECL lame_set_decode_only(lame_global_flags *, int); +int CDECL lame_get_decode_only(const lame_global_flags *); + +#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED +#else +/* 1=encode a Vorbis .ogg file. default=0 */ +/* DEPRECATED */ +int CDECL lame_set_ogg(lame_global_flags *, int); +int CDECL lame_get_ogg(const lame_global_flags *); +#endif + +/* + internal algorithm selection. True quality is determined by the bitrate + but this variable will effect quality by selecting expensive or cheap algorithms. + quality=0..9. 0=best (very slow). 9=worst. + recommended: 2 near-best quality, not too slow + 5 good quality, fast + 7 ok quality, really fast +*/ +int CDECL lame_set_quality(lame_global_flags *, int); +int CDECL lame_get_quality(const lame_global_flags *); + +/* + mode = 0,1,2,3 = stereo, jstereo, dual channel (not supported), mono + default: lame picks based on compression ration and input channels +*/ +int CDECL lame_set_mode(lame_global_flags *, MPEG_mode); +MPEG_mode CDECL lame_get_mode(const lame_global_flags *); + +#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED +#else +/* + mode_automs. Use a M/S mode with a switching threshold based on + compression ratio + DEPRECATED +*/ +int CDECL lame_set_mode_automs(lame_global_flags *, int); +int CDECL lame_get_mode_automs(const lame_global_flags *); +#endif + +/* + force_ms. Force M/S for all frames. For testing only. + default = 0 (disabled) +*/ +int CDECL lame_set_force_ms(lame_global_flags *, int); +int CDECL lame_get_force_ms(const lame_global_flags *); + +/* use free_format? default = 0 (disabled) */ +int CDECL lame_set_free_format(lame_global_flags *, int); +int CDECL lame_get_free_format(const lame_global_flags *); + +/* perform ReplayGain analysis? default = 0 (disabled) */ +int CDECL lame_set_findReplayGain(lame_global_flags *, int); +int CDECL lame_get_findReplayGain(const lame_global_flags *); + +/* decode on the fly. Search for the peak sample. If the ReplayGain + * analysis is enabled then perform the analysis on the decoded data + * stream. default = 0 (disabled) + * NOTE: if this option is set the build-in decoder should not be used */ +int CDECL lame_set_decode_on_the_fly(lame_global_flags *, int); +int CDECL lame_get_decode_on_the_fly(const lame_global_flags *); + +#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED +#else +/* DEPRECATED: now does the same as lame_set_findReplayGain() + default = 0 (disabled) */ +int CDECL lame_set_ReplayGain_input(lame_global_flags *, int); +int CDECL lame_get_ReplayGain_input(const lame_global_flags *); + +/* DEPRECATED: now does the same as + lame_set_decode_on_the_fly() && lame_set_findReplayGain() + default = 0 (disabled) */ +int CDECL lame_set_ReplayGain_decode(lame_global_flags *, int); +int CDECL lame_get_ReplayGain_decode(const lame_global_flags *); + +/* DEPRECATED: now does the same as lame_set_decode_on_the_fly() + default = 0 (disabled) */ +int CDECL lame_set_findPeakSample(lame_global_flags *, int); +int CDECL lame_get_findPeakSample(const lame_global_flags *); +#endif + +/* counters for gapless encoding */ +int CDECL lame_set_nogap_total(lame_global_flags*, int); +int CDECL lame_get_nogap_total(const lame_global_flags*); + +int CDECL lame_set_nogap_currentindex(lame_global_flags* , int); +int CDECL lame_get_nogap_currentindex(const lame_global_flags*); + + +/* + * OPTIONAL: + * Set printf like error/debug/message reporting functions. + * The second argument has to be a pointer to a function which looks like + * void my_debugf(const char *format, va_list ap) + * { + * (void) vfprintf(stdout, format, ap); + * } + * If you use NULL as the value of the pointer in the set function, the + * lame buildin function will be used (prints to stderr). + * To quiet any output you have to replace the body of the example function + * with just "return;" and use it in the set function. + */ +int CDECL lame_set_errorf(lame_global_flags *, lame_report_function); +int CDECL lame_set_debugf(lame_global_flags *, lame_report_function); +int CDECL lame_set_msgf (lame_global_flags *, lame_report_function); + + + +/* set one of brate compression ratio. default is compression ratio of 11. */ +int CDECL lame_set_brate(lame_global_flags *, int); +int CDECL lame_get_brate(const lame_global_flags *); +int CDECL lame_set_compression_ratio(lame_global_flags *, float); +float CDECL lame_get_compression_ratio(const lame_global_flags *); + + +int CDECL lame_set_preset( lame_global_flags* gfp, int ); +int CDECL lame_set_asm_optimizations( lame_global_flags* gfp, int, int ); + + + +/******************************************************************** + * frame params + ***********************************************************************/ +/* mark as copyright. default=0 */ +int CDECL lame_set_copyright(lame_global_flags *, int); +int CDECL lame_get_copyright(const lame_global_flags *); + +/* mark as original. default=1 */ +int CDECL lame_set_original(lame_global_flags *, int); +int CDECL lame_get_original(const lame_global_flags *); + +/* error_protection. Use 2 bytes from each frame for CRC checksum. default=0 */ +int CDECL lame_set_error_protection(lame_global_flags *, int); +int CDECL lame_get_error_protection(const lame_global_flags *); + +#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED +#else +/* padding_type. 0=pad no frames 1=pad all frames 2=adjust padding(default) */ +int CDECL lame_set_padding_type(lame_global_flags *, Padding_type); +Padding_type CDECL lame_get_padding_type(const lame_global_flags *); +#endif + +/* MP3 'private extension' bit Meaningless. default=0 */ +int CDECL lame_set_extension(lame_global_flags *, int); +int CDECL lame_get_extension(const lame_global_flags *); + +/* enforce strict ISO compliance. default=0 */ +int CDECL lame_set_strict_ISO(lame_global_flags *, int); +int CDECL lame_get_strict_ISO(const lame_global_flags *); + + +/******************************************************************** + * quantization/noise shaping + ***********************************************************************/ + +/* disable the bit reservoir. For testing only. default=0 */ +int CDECL lame_set_disable_reservoir(lame_global_flags *, int); +int CDECL lame_get_disable_reservoir(const lame_global_flags *); + +/* select a different "best quantization" function. default=0 */ +int CDECL lame_set_quant_comp(lame_global_flags *, int); +int CDECL lame_get_quant_comp(const lame_global_flags *); +int CDECL lame_set_quant_comp_short(lame_global_flags *, int); +int CDECL lame_get_quant_comp_short(const lame_global_flags *); + +int CDECL lame_set_experimentalX(lame_global_flags *, int); /* compatibility*/ +int CDECL lame_get_experimentalX(const lame_global_flags *); + +/* another experimental option. for testing only */ +int CDECL lame_set_experimentalY(lame_global_flags *, int); +int CDECL lame_get_experimentalY(const lame_global_flags *); + +/* another experimental option. for testing only */ +int CDECL lame_set_experimentalZ(lame_global_flags *, int); +int CDECL lame_get_experimentalZ(const lame_global_flags *); + +/* Naoki's psycho acoustic model. default=0 */ +int CDECL lame_set_exp_nspsytune(lame_global_flags *, int); +int CDECL lame_get_exp_nspsytune(const lame_global_flags *); + +void CDECL lame_set_msfix(lame_global_flags *, double); +float CDECL lame_get_msfix(const lame_global_flags *); + + +/******************************************************************** + * VBR control + ***********************************************************************/ +/* Types of VBR. default = vbr_off = CBR */ +int CDECL lame_set_VBR(lame_global_flags *, vbr_mode); +vbr_mode CDECL lame_get_VBR(const lame_global_flags *); + +/* VBR quality level. 0=highest 9=lowest */ +int CDECL lame_set_VBR_q(lame_global_flags *, int); +int CDECL lame_get_VBR_q(const lame_global_flags *); + +/* VBR quality level. 0=highest 9=lowest, Range [0,...,10[ */ +int CDECL lame_set_VBR_quality(lame_global_flags *, float); +float CDECL lame_get_VBR_quality(const lame_global_flags *); + +/* Ignored except for VBR=vbr_abr (ABR mode) */ +int CDECL lame_set_VBR_mean_bitrate_kbps(lame_global_flags *, int); +int CDECL lame_get_VBR_mean_bitrate_kbps(const lame_global_flags *); + +int CDECL lame_set_VBR_min_bitrate_kbps(lame_global_flags *, int); +int CDECL lame_get_VBR_min_bitrate_kbps(const lame_global_flags *); + +int CDECL lame_set_VBR_max_bitrate_kbps(lame_global_flags *, int); +int CDECL lame_get_VBR_max_bitrate_kbps(const lame_global_flags *); + +/* + 1=strictly enforce VBR_min_bitrate. Normally it will be violated for + analog silence +*/ +int CDECL lame_set_VBR_hard_min(lame_global_flags *, int); +int CDECL lame_get_VBR_hard_min(const lame_global_flags *); + +/* for preset */ +#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED +#else +int CDECL lame_set_preset_expopts(lame_global_flags *, int); +#endif + +/******************************************************************** + * Filtering control + ***********************************************************************/ +/* freq in Hz to apply lowpass. Default = 0 = lame chooses. -1 = disabled */ +int CDECL lame_set_lowpassfreq(lame_global_flags *, int); +int CDECL lame_get_lowpassfreq(const lame_global_flags *); +/* width of transition band, in Hz. Default = one polyphase filter band */ +int CDECL lame_set_lowpasswidth(lame_global_flags *, int); +int CDECL lame_get_lowpasswidth(const lame_global_flags *); + +/* freq in Hz to apply highpass. Default = 0 = lame chooses. -1 = disabled */ +int CDECL lame_set_highpassfreq(lame_global_flags *, int); +int CDECL lame_get_highpassfreq(const lame_global_flags *); +/* width of transition band, in Hz. Default = one polyphase filter band */ +int CDECL lame_set_highpasswidth(lame_global_flags *, int); +int CDECL lame_get_highpasswidth(const lame_global_flags *); + + +/******************************************************************** + * psycho acoustics and other arguments which you should not change + * unless you know what you are doing + ***********************************************************************/ + +/* only use ATH for masking */ +int CDECL lame_set_ATHonly(lame_global_flags *, int); +int CDECL lame_get_ATHonly(const lame_global_flags *); + +/* only use ATH for short blocks */ +int CDECL lame_set_ATHshort(lame_global_flags *, int); +int CDECL lame_get_ATHshort(const lame_global_flags *); + +/* disable ATH */ +int CDECL lame_set_noATH(lame_global_flags *, int); +int CDECL lame_get_noATH(const lame_global_flags *); + +/* select ATH formula */ +int CDECL lame_set_ATHtype(lame_global_flags *, int); +int CDECL lame_get_ATHtype(const lame_global_flags *); + +/* lower ATH by this many db */ +int CDECL lame_set_ATHlower(lame_global_flags *, float); +float CDECL lame_get_ATHlower(const lame_global_flags *); + +/* select ATH adaptive adjustment type */ +int CDECL lame_set_athaa_type( lame_global_flags *, int); +int CDECL lame_get_athaa_type( const lame_global_flags *); + +#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED +#else +/* select the loudness approximation used by the ATH adaptive auto-leveling */ +int CDECL lame_set_athaa_loudapprox( lame_global_flags *, int); +int CDECL lame_get_athaa_loudapprox( const lame_global_flags *); +#endif + +/* adjust (in dB) the point below which adaptive ATH level adjustment occurs */ +int CDECL lame_set_athaa_sensitivity( lame_global_flags *, float); +float CDECL lame_get_athaa_sensitivity( const lame_global_flags* ); + +#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED +#else +/* OBSOLETE: predictability limit (ISO tonality formula) */ +int CDECL lame_set_cwlimit(lame_global_flags *, int); +int CDECL lame_get_cwlimit(const lame_global_flags *); +#endif + +/* + allow blocktypes to differ between channels? + default: 0 for jstereo, 1 for stereo +*/ +int CDECL lame_set_allow_diff_short(lame_global_flags *, int); +int CDECL lame_get_allow_diff_short(const lame_global_flags *); + +/* use temporal masking effect (default = 1) */ +int CDECL lame_set_useTemporal(lame_global_flags *, int); +int CDECL lame_get_useTemporal(const lame_global_flags *); + +/* use temporal masking effect (default = 1) */ +int CDECL lame_set_interChRatio(lame_global_flags *, float); +float CDECL lame_get_interChRatio(const lame_global_flags *); + +/* disable short blocks */ +int CDECL lame_set_no_short_blocks(lame_global_flags *, int); +int CDECL lame_get_no_short_blocks(const lame_global_flags *); + +/* force short blocks */ +int CDECL lame_set_force_short_blocks(lame_global_flags *, int); +int CDECL lame_get_force_short_blocks(const lame_global_flags *); + +/* Input PCM is emphased PCM (for instance from one of the rarely + emphased CDs), it is STRONGLY not recommended to use this, because + psycho does not take it into account, and last but not least many decoders + ignore these bits */ +int CDECL lame_set_emphasis(lame_global_flags *, int); +int CDECL lame_get_emphasis(const lame_global_flags *); + + + +/************************************************************************/ +/* internal variables, cannot be set... */ +/* provided because they may be of use to calling application */ +/************************************************************************/ +/* version 0=MPEG-2 1=MPEG-1 (2=MPEG-2.5) */ +int CDECL lame_get_version(const lame_global_flags *); + +/* encoder delay */ +int CDECL lame_get_encoder_delay(const lame_global_flags *); + +/* + padding appended to the input to make sure decoder can fully decode + all input. Note that this value can only be calculated during the + call to lame_encoder_flush(). Before lame_encoder_flush() has + been called, the value of encoder_padding = 0. +*/ +int CDECL lame_get_encoder_padding(const lame_global_flags *); + +/* size of MPEG frame */ +int CDECL lame_get_framesize(const lame_global_flags *); + +/* number of PCM samples buffered, but not yet encoded to mp3 data. */ +int CDECL lame_get_mf_samples_to_encode( const lame_global_flags* gfp ); + +/* + size (bytes) of mp3 data buffered, but not yet encoded. + this is the number of bytes which would be output by a call to + lame_encode_flush_nogap. NOTE: lame_encode_flush() will return + more bytes than this because it will encode the reamining buffered + PCM samples before flushing the mp3 buffers. +*/ +int CDECL lame_get_size_mp3buffer( const lame_global_flags* gfp ); + +/* number of frames encoded so far */ +int CDECL lame_get_frameNum(const lame_global_flags *); + +/* + lame's estimate of the total number of frames to be encoded + only valid if calling program set num_samples +*/ +int CDECL lame_get_totalframes(const lame_global_flags *); + +/* RadioGain value. Multiplied by 10 and rounded to the nearest. */ +int CDECL lame_get_RadioGain(const lame_global_flags *); + +/* AudiophileGain value. Multipled by 10 and rounded to the nearest. */ +int CDECL lame_get_AudiophileGain(const lame_global_flags *); + +/* the peak sample */ +float CDECL lame_get_PeakSample(const lame_global_flags *); + +/* Gain change required for preventing clipping. The value is correct only if + peak sample searching was enabled. If negative then the waveform + already does not clip. The value is multiplied by 10 and rounded up. */ +int CDECL lame_get_noclipGainChange(const lame_global_flags *); + +/* user-specified scale factor required for preventing clipping. Value is + correct only if peak sample searching was enabled and no user-specified + scaling was performed. If negative then either the waveform already does + not clip or the value cannot be determined */ +float CDECL lame_get_noclipScale(const lame_global_flags *); + +/* returns the limit of PCM samples, which one can pass in an encode call + under the constrain of a provided buffer of size buffer_size */ +int CDECL lame_get_maximum_number_of_samples(lame_t gfp, size_t buffer_size); + + + + +/* + * REQUIRED: + * sets more internal configuration based on data provided above. + * returns -1 if something failed. + */ +int CDECL lame_init_params(lame_global_flags *); + + +/* + * OPTIONAL: + * get the version number, in a string. of the form: + * "3.63 (beta)" or just "3.63". + */ +const char* CDECL get_lame_version ( void ); +const char* CDECL get_lame_short_version ( void ); +const char* CDECL get_lame_very_short_version ( void ); +const char* CDECL get_psy_version ( void ); +const char* CDECL get_lame_url ( void ); +const char* CDECL get_lame_os_bitness ( void ); + +/* + * OPTIONAL: + * get the version numbers in numerical form. + */ +typedef struct { + /* generic LAME version */ + int major; + int minor; + int alpha; /* 0 if not an alpha version */ + int beta; /* 0 if not a beta version */ + + /* version of the psy model */ + int psy_major; + int psy_minor; + int psy_alpha; /* 0 if not an alpha version */ + int psy_beta; /* 0 if not a beta version */ + + /* compile time features */ + const char *features; /* Don't make assumptions about the contents! */ +} lame_version_t; +void CDECL get_lame_version_numerical(lame_version_t *); + + +/* + * OPTIONAL: + * print internal lame configuration to message handler + */ +void CDECL lame_print_config(const lame_global_flags* gfp); + +void CDECL lame_print_internals( const lame_global_flags *gfp); + + +/* + * input pcm data, output (maybe) mp3 frames. + * This routine handles all buffering, resampling and filtering for you. + * + * return code number of bytes output in mp3buf. Can be 0 + * -1: mp3buf was too small + * -2: malloc() problem + * -3: lame_init_params() not called + * -4: psycho acoustic problems + * + * The required mp3buf_size can be computed from num_samples, + * samplerate and encoding rate, but here is a worst case estimate: + * + * mp3buf_size in bytes = 1.25*num_samples + 7200 + * + * I think a tighter bound could be: (mt, March 2000) + * MPEG1: + * num_samples*(bitrate/8)/samplerate + 4*1152*(bitrate/8)/samplerate + 512 + * MPEG2: + * num_samples*(bitrate/8)/samplerate + 4*576*(bitrate/8)/samplerate + 256 + * + * but test first if you use that! + * + * set mp3buf_size = 0 and LAME will not check if mp3buf_size is + * large enough. + * + * NOTE: + * if gfp->num_channels=2, but gfp->mode = 3 (mono), the L & R channels + * will be averaged into the L channel before encoding only the L channel + * This will overwrite the data in buffer_l[] and buffer_r[]. + * +*/ +int CDECL lame_encode_buffer ( + lame_global_flags* gfp, /* global context handle */ + const short int buffer_l [], /* PCM data for left channel */ + const short int buffer_r [], /* PCM data for right channel */ + const int nsamples, /* number of samples per channel */ + unsigned char* mp3buf, /* pointer to encoded MP3 stream */ + const int mp3buf_size ); /* number of valid octets in this + stream */ + +/* + * as above, but input has L & R channel data interleaved. + * NOTE: + * num_samples = number of samples in the L (or R) + * channel, not the total number of samples in pcm[] + */ +int CDECL lame_encode_buffer_interleaved( + lame_global_flags* gfp, /* global context handlei */ + short int pcm[], /* PCM data for left and right + channel, interleaved */ + int num_samples, /* number of samples per channel, + _not_ number of samples in + pcm[] */ + unsigned char* mp3buf, /* pointer to encoded MP3 stream */ + int mp3buf_size ); /* number of valid octets in this + stream */ + + +/* as lame_encode_buffer, but for 'float's. + * !! NOTE: !! data must still be scaled to be in the same range as + * short int, +/- 32768 + */ +int CDECL lame_encode_buffer_float( + lame_global_flags* gfp, /* global context handle */ + const float pcm_l [], /* PCM data for left channel */ + const float pcm_r [], /* PCM data for right channel */ + const int nsamples, /* number of samples per channel */ + unsigned char* mp3buf, /* pointer to encoded MP3 stream */ + const int mp3buf_size ); /* number of valid octets in this + stream */ + +/* as lame_encode_buffer, but for 'float's. + * !! NOTE: !! data must be scaled to +/- 1 full scale + */ +int CDECL lame_encode_buffer_ieee_float( + lame_t gfp, + const float pcm_l [], /* PCM data for left channel */ + const float pcm_r [], /* PCM data for right channel */ + const int nsamples, + unsigned char * mp3buf, + const int mp3buf_size); +int CDECL lame_encode_buffer_interleaved_ieee_float( + lame_t gfp, + const float pcm[], /* PCM data for left and right + channel, interleaved */ + const int nsamples, + unsigned char * mp3buf, + const int mp3buf_size); + +/* as lame_encode_buffer, but for 'double's. + * !! NOTE: !! data must be scaled to +/- 1 full scale + */ +int CDECL lame_encode_buffer_ieee_double( + lame_t gfp, + const double pcm_l [], /* PCM data for left channel */ + const double pcm_r [], /* PCM data for right channel */ + const int nsamples, + unsigned char * mp3buf, + const int mp3buf_size); +int CDECL lame_encode_buffer_interleaved_ieee_double( + lame_t gfp, + const double pcm[], /* PCM data for left and right + channel, interleaved */ + const int nsamples, + unsigned char * mp3buf, + const int mp3buf_size); + +/* as lame_encode_buffer, but for long's + * !! NOTE: !! data must still be scaled to be in the same range as + * short int, +/- 32768 + * + * This scaling was a mistake (doesn't allow one to exploit full + * precision of type 'long'. Use lame_encode_buffer_long2() instead. + * + */ +int CDECL lame_encode_buffer_long( + lame_global_flags* gfp, /* global context handle */ + const long buffer_l [], /* PCM data for left channel */ + const long buffer_r [], /* PCM data for right channel */ + const int nsamples, /* number of samples per channel */ + unsigned char* mp3buf, /* pointer to encoded MP3 stream */ + const int mp3buf_size ); /* number of valid octets in this + stream */ + +/* Same as lame_encode_buffer_long(), but with correct scaling. + * !! NOTE: !! data must still be scaled to be in the same range as + * type 'long'. Data should be in the range: +/- 2^(8*size(long)-1) + * + */ +int CDECL lame_encode_buffer_long2( + lame_global_flags* gfp, /* global context handle */ + const long buffer_l [], /* PCM data for left channel */ + const long buffer_r [], /* PCM data for right channel */ + const int nsamples, /* number of samples per channel */ + unsigned char* mp3buf, /* pointer to encoded MP3 stream */ + const int mp3buf_size ); /* number of valid octets in this + stream */ + +/* as lame_encode_buffer, but for int's + * !! NOTE: !! input should be scaled to the maximum range of 'int' + * If int is 4 bytes, then the values should range from + * +/- 2147483648. + * + * This routine does not (and cannot, without loosing precision) use + * the same scaling as the rest of the lame_encode_buffer() routines. + * + */ +int CDECL lame_encode_buffer_int( + lame_global_flags* gfp, /* global context handle */ + const int buffer_l [], /* PCM data for left channel */ + const int buffer_r [], /* PCM data for right channel */ + const int nsamples, /* number of samples per channel */ + unsigned char* mp3buf, /* pointer to encoded MP3 stream */ + const int mp3buf_size ); /* number of valid octets in this + stream */ + +/* + * as above, but for interleaved data. + * !! NOTE: !! data must still be scaled to be in the same range as + * type 'int32_t'. Data should be in the range: +/- 2^(8*size(int32_t)-1) + * NOTE: + * num_samples = number of samples in the L (or R) + * channel, not the total number of samples in pcm[] + */ +int +lame_encode_buffer_interleaved_int( + lame_t gfp, + const int pcm [], /* PCM data for left and right + channel, interleaved */ + const int nsamples, /* number of samples per channel, + _not_ number of samples in + pcm[] */ + unsigned char* mp3buf, /* pointer to encoded MP3 stream */ + const int mp3buf_size ); /* number of valid octets in this + stream */ + + + +/* + * REQUIRED: + * lame_encode_flush will flush the intenal PCM buffers, padding with + * 0's to make sure the final frame is complete, and then flush + * the internal MP3 buffers, and thus may return a + * final few mp3 frames. 'mp3buf' should be at least 7200 bytes long + * to hold all possible emitted data. + * + * will also write id3v1 tags (if any) into the bitstream + * + * return code = number of bytes output to mp3buf. Can be 0 + */ +int CDECL lame_encode_flush( + lame_global_flags * gfp, /* global context handle */ + unsigned char* mp3buf, /* pointer to encoded MP3 stream */ + int size); /* number of valid octets in this stream */ + +/* + * OPTIONAL: + * lame_encode_flush_nogap will flush the internal mp3 buffers and pad + * the last frame with ancillary data so it is a complete mp3 frame. + * + * 'mp3buf' should be at least 7200 bytes long + * to hold all possible emitted data. + * + * After a call to this routine, the outputed mp3 data is complete, but + * you may continue to encode new PCM samples and write future mp3 data + * to a different file. The two mp3 files will play back with no gaps + * if they are concatenated together. + * + * This routine will NOT write id3v1 tags into the bitstream. + * + * return code = number of bytes output to mp3buf. Can be 0 + */ +int CDECL lame_encode_flush_nogap( + lame_global_flags * gfp, /* global context handle */ + unsigned char* mp3buf, /* pointer to encoded MP3 stream */ + int size); /* number of valid octets in this stream */ + +/* + * OPTIONAL: + * Normally, this is called by lame_init_params(). It writes id3v2 and + * Xing headers into the front of the bitstream, and sets frame counters + * and bitrate histogram data to 0. You can also call this after + * lame_encode_flush_nogap(). + */ +int CDECL lame_init_bitstream( + lame_global_flags * gfp); /* global context handle */ + + + +/* + * OPTIONAL: some simple statistics + * a bitrate histogram to visualize the distribution of used frame sizes + * a stereo mode histogram to visualize the distribution of used stereo + * modes, useful in joint-stereo mode only + * 0: LR left-right encoded + * 1: LR-I left-right and intensity encoded (currently not supported) + * 2: MS mid-side encoded + * 3: MS-I mid-side and intensity encoded (currently not supported) + * + * attention: don't call them after lame_encode_finish + * suggested: lame_encode_flush -> lame_*_hist -> lame_close + */ + +void CDECL lame_bitrate_hist( + const lame_global_flags * gfp, + int bitrate_count[14] ); +void CDECL lame_bitrate_kbps( + const lame_global_flags * gfp, + int bitrate_kbps [14] ); +void CDECL lame_stereo_mode_hist( + const lame_global_flags * gfp, + int stereo_mode_count[4] ); + +void CDECL lame_bitrate_stereo_mode_hist ( + const lame_global_flags * gfp, + int bitrate_stmode_count[14][4] ); + +void CDECL lame_block_type_hist ( + const lame_global_flags * gfp, + int btype_count[6] ); + +void CDECL lame_bitrate_block_type_hist ( + const lame_global_flags * gfp, + int bitrate_btype_count[14][6] ); + +#if (DEPRECATED_OR_OBSOLETE_CODE_REMOVED && 0) +#else +/* + * OPTIONAL: + * lame_mp3_tags_fid will rewrite a Xing VBR tag to the mp3 file with file + * pointer fid. These calls perform forward and backwards seeks, so make + * sure fid is a real file. Make sure lame_encode_flush has been called, + * and all mp3 data has been written to the file before calling this + * function. + * NOTE: + * if VBR tags are turned off by the user, or turned off by LAME because + * the output is not a regular file, this call does nothing + * NOTE: + * LAME wants to read from the file to skip an optional ID3v2 tag, so + * make sure you opened the file for writing and reading. + * NOTE: + * You can call lame_get_lametag_frame instead, if you want to insert + * the lametag yourself. +*/ +void CDECL lame_mp3_tags_fid(lame_global_flags *, FILE* fid); +#endif + +/* + * OPTIONAL: + * lame_get_lametag_frame copies the final LAME-tag into 'buffer'. + * The function returns the number of bytes copied into buffer, or + * the required buffer size, if the provided buffer is too small. + * Function failed, if the return value is larger than 'size'! + * Make sure lame_encode flush has been called before calling this function. + * NOTE: + * if VBR tags are turned off by the user, or turned off by LAME, + * this call does nothing and returns 0. + * NOTE: + * LAME inserted an empty frame in the beginning of mp3 audio data, + * which you have to replace by the final LAME-tag frame after encoding. + * In case there is no ID3v2 tag, usually this frame will be the very first + * data in your mp3 file. If you put some other leading data into your + * file, you'll have to do some bookkeeping about where to write this buffer. + */ +size_t CDECL lame_get_lametag_frame( + const lame_global_flags *, unsigned char* buffer, size_t size); + +/* + * REQUIRED: + * final call to free all remaining buffers + */ +int CDECL lame_close (lame_global_flags *); + +#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED +#else +/* + * OBSOLETE: + * lame_encode_finish combines lame_encode_flush() and lame_close() in + * one call. However, once this call is made, the statistics routines + * will no longer work because the data will have been cleared, and + * lame_mp3_tags_fid() cannot be called to add data to the VBR header + */ +int CDECL lame_encode_finish( + lame_global_flags* gfp, + unsigned char* mp3buf, + int size ); +#endif + + + + + + +/********************************************************************* + * + * decoding + * + * a simple interface to mpglib, part of mpg123, is also included if + * libmp3lame is compiled with HAVE_MPGLIB + * + *********************************************************************/ + +struct hip_global_struct; +typedef struct hip_global_struct hip_global_flags; +typedef hip_global_flags *hip_t; + + +typedef struct { + int header_parsed; /* 1 if header was parsed and following data was + computed */ + int stereo; /* number of channels */ + int samplerate; /* sample rate */ + int bitrate; /* bitrate */ + int mode; /* mp3 frame type */ + int mode_ext; /* mp3 frame type */ + int framesize; /* number of samples per mp3 frame */ + + /* this data is only computed if mpglib detects a Xing VBR header */ + unsigned long nsamp; /* number of samples in mp3 file. */ + int totalframes; /* total number of frames in mp3 file */ + + /* this data is not currently computed by the mpglib routines */ + int framenum; /* frames decoded counter */ +} mp3data_struct; + +/* required call to initialize decoder */ +hip_t CDECL hip_decode_init(void); + +/* cleanup call to exit decoder */ +int CDECL hip_decode_exit(hip_t gfp); + +/* HIP reporting functions */ +void CDECL hip_set_errorf(hip_t gfp, lame_report_function f); +void CDECL hip_set_debugf(hip_t gfp, lame_report_function f); +void CDECL hip_set_msgf (hip_t gfp, lame_report_function f); + +/********************************************************************* + * input 1 mp3 frame, output (maybe) pcm data. + * + * nout = hip_decode(hip, mp3buf,len,pcm_l,pcm_r); + * + * input: + * len : number of bytes of mp3 data in mp3buf + * mp3buf[len] : mp3 data to be decoded + * + * output: + * nout: -1 : decoding error + * 0 : need more data before we can complete the decode + * >0 : returned 'nout' samples worth of data in pcm_l,pcm_r + * pcm_l[nout] : left channel data + * pcm_r[nout] : right channel data + * + *********************************************************************/ +int CDECL hip_decode( hip_t gfp + , unsigned char * mp3buf + , size_t len + , short pcm_l[] + , short pcm_r[] + ); + +/* same as hip_decode, and also returns mp3 header data */ +int CDECL hip_decode_headers( hip_t gfp + , unsigned char* mp3buf + , size_t len + , short pcm_l[] + , short pcm_r[] + , mp3data_struct* mp3data + ); + +/* same as hip_decode, but returns at most one frame */ +int CDECL hip_decode1( hip_t gfp + , unsigned char* mp3buf + , size_t len + , short pcm_l[] + , short pcm_r[] + ); + +/* same as hip_decode1, but returns at most one frame and mp3 header data */ +int CDECL hip_decode1_headers( hip_t gfp + , unsigned char* mp3buf + , size_t len + , short pcm_l[] + , short pcm_r[] + , mp3data_struct* mp3data + ); + +/* same as hip_decode1_headers, but also returns enc_delay and enc_padding + from VBR Info tag, (-1 if no info tag was found) */ +int CDECL hip_decode1_headersB( hip_t gfp + , unsigned char* mp3buf + , size_t len + , short pcm_l[] + , short pcm_r[] + , mp3data_struct* mp3data + , int *enc_delay + , int *enc_padding + ); + + + +/* OBSOLETE: + * lame_decode... functions are there to keep old code working + * but it is strongly recommended to replace calls by hip_decode... + * function calls, see above. + */ +#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED +#else +int CDECL lame_decode_init(void); +int CDECL lame_decode( + unsigned char * mp3buf, + int len, + short pcm_l[], + short pcm_r[] ); +int CDECL lame_decode_headers( + unsigned char* mp3buf, + int len, + short pcm_l[], + short pcm_r[], + mp3data_struct* mp3data ); +int CDECL lame_decode1( + unsigned char* mp3buf, + int len, + short pcm_l[], + short pcm_r[] ); +int CDECL lame_decode1_headers( + unsigned char* mp3buf, + int len, + short pcm_l[], + short pcm_r[], + mp3data_struct* mp3data ); +int CDECL lame_decode1_headersB( + unsigned char* mp3buf, + int len, + short pcm_l[], + short pcm_r[], + mp3data_struct* mp3data, + int *enc_delay, + int *enc_padding ); +int CDECL lame_decode_exit(void); + +#endif /* obsolete lame_decode API calls */ + + +/********************************************************************* + * + * id3tag stuff + * + *********************************************************************/ + +/* + * id3tag.h -- Interface to write ID3 version 1 and 2 tags. + * + * Copyright (C) 2000 Don Melton. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ + +/* utility to obtain alphabetically sorted list of genre names with numbers */ +void CDECL id3tag_genre_list( + void (*handler)(int, const char *, void *), + void* cookie); + +void CDECL id3tag_init (lame_t gfp); + +/* force addition of version 2 tag */ +void CDECL id3tag_add_v2 (lame_t gfp); + +/* add only a version 1 tag */ +void CDECL id3tag_v1_only (lame_t gfp); + +/* add only a version 2 tag */ +void CDECL id3tag_v2_only (lame_t gfp); + +/* pad version 1 tag with spaces instead of nulls */ +void CDECL id3tag_space_v1 (lame_t gfp); + +/* pad version 2 tag with extra 128 bytes */ +void CDECL id3tag_pad_v2 (lame_t gfp); + +/* pad version 2 tag with extra n bytes */ +void CDECL id3tag_set_pad (lame_t gfp, size_t n); + +void CDECL id3tag_set_title(lame_t gfp, const char* title); +void CDECL id3tag_set_artist(lame_t gfp, const char* artist); +void CDECL id3tag_set_album(lame_t gfp, const char* album); +void CDECL id3tag_set_year(lame_t gfp, const char* year); +void CDECL id3tag_set_comment(lame_t gfp, const char* comment); + +/* return -1 result if track number is out of ID3v1 range + and ignored for ID3v1 */ +int CDECL id3tag_set_track(lame_t gfp, const char* track); + +/* return non-zero result if genre name or number is invalid + result 0: OK + result -1: genre number out of range + result -2: no valid ID3v1 genre name, mapped to ID3v1 'Other' + but taken as-is for ID3v2 genre tag */ +int CDECL id3tag_set_genre(lame_t gfp, const char* genre); + +/* return non-zero result if field name is invalid */ +int CDECL id3tag_set_fieldvalue(lame_t gfp, const char* fieldvalue); + +/* return non-zero result if image type is invalid */ +int CDECL id3tag_set_albumart(lame_t gfp, const char* image, size_t size); + +/* lame_get_id3v1_tag copies ID3v1 tag into buffer. + * Function returns number of bytes copied into buffer, or number + * of bytes rquired if buffer 'size' is too small. + * Function fails, if returned value is larger than 'size'. + * NOTE: + * This functions does nothing, if user/LAME disabled ID3v1 tag. + */ +size_t CDECL lame_get_id3v1_tag(lame_t gfp, unsigned char* buffer, size_t size); + +/* lame_get_id3v2_tag copies ID3v2 tag into buffer. + * Function returns number of bytes copied into buffer, or number + * of bytes rquired if buffer 'size' is too small. + * Function fails, if returned value is larger than 'size'. + * NOTE: + * This functions does nothing, if user/LAME disabled ID3v2 tag. + */ +size_t CDECL lame_get_id3v2_tag(lame_t gfp, unsigned char* buffer, size_t size); + +/* normaly lame_init_param writes ID3v2 tags into the audio stream + * Call lame_set_write_id3tag_automatic(gfp, 0) before lame_init_param + * to turn off this behaviour and get ID3v2 tag with above function + * write it yourself into your file. + */ +void CDECL lame_set_write_id3tag_automatic(lame_global_flags * gfp, int); +int CDECL lame_get_write_id3tag_automatic(lame_global_flags const* gfp); + +/* experimental */ +int CDECL id3tag_set_textinfo_latin1(lame_t gfp, char const *id, char const *text); + +/* experimental */ +int CDECL id3tag_set_comment_latin1(lame_t gfp, char const *lang, char const *desc, char const *text); + +#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED +#else +/* experimental */ +int CDECL id3tag_set_textinfo_ucs2(lame_t gfp, char const *id, unsigned short const *text); + +/* experimental */ +int CDECL id3tag_set_comment_ucs2(lame_t gfp, char const *lang, + unsigned short const *desc, unsigned short const *text); + +/* experimental */ +int CDECL id3tag_set_fieldvalue_ucs2(lame_t gfp, const unsigned short *fieldvalue); +#endif + +/* experimental */ +int CDECL id3tag_set_fieldvalue_utf16(lame_t gfp, const unsigned short *fieldvalue); + +/* experimental */ +int CDECL id3tag_set_textinfo_utf16(lame_t gfp, char const *id, unsigned short const *text); + +/* experimental */ +int CDECL id3tag_set_comment_utf16(lame_t gfp, char const *lang, unsigned short const *desc, unsigned short const *text); + + +/*********************************************************************** +* +* list of valid bitrates [kbps] & sample frequencies [Hz]. +* first index: 0: MPEG-2 values (sample frequencies 16...24 kHz) +* 1: MPEG-1 values (sample frequencies 32...48 kHz) +* 2: MPEG-2.5 values (sample frequencies 8...12 kHz) +***********************************************************************/ + +extern const int bitrate_table [3][16]; +extern const int samplerate_table [3][ 4]; + +/* access functions for use in DLL, global vars are not exported */ +int CDECL lame_get_bitrate(int mpeg_version, int table_index); +int CDECL lame_get_samplerate(int mpeg_version, int table_index); + + +/* maximum size of albumart image (128KB), which affects LAME_MAXMP3BUFFER + as well since lame_encode_buffer() also returns ID3v2 tag data */ +#define LAME_MAXALBUMART (128 * 1024) + +/* maximum size of mp3buffer needed if you encode at most 1152 samples for + each call to lame_encode_buffer. see lame_encode_buffer() below + (LAME_MAXMP3BUFFER is now obsolete) */ +#define LAME_MAXMP3BUFFER (16384 + LAME_MAXALBUMART) + + +typedef enum { + LAME_OKAY = 0, + LAME_NOERROR = 0, + LAME_GENERICERROR = -1, + LAME_NOMEM = -10, + LAME_BADBITRATE = -11, + LAME_BADSAMPFREQ = -12, + LAME_INTERNALERROR = -13, + + FRONTEND_READERROR = -80, + FRONTEND_WRITEERROR = -81, + FRONTEND_FILETOOLARGE = -82 + +} lame_errorcodes_t; + +#if defined(__cplusplus) +} +#endif +#endif /* LAME_LAME_H */ + diff --git a/pkg/lame/clame/lame_global_flags.h b/pkg/lame/clame/lame_global_flags.h new file mode 100644 index 0000000..ad9e677 --- /dev/null +++ b/pkg/lame/clame/lame_global_flags.h @@ -0,0 +1,184 @@ +#ifndef LAME_GLOBAL_FLAGS_H +#define LAME_GLOBAL_FLAGS_H + +#ifndef lame_internal_flags_defined +#define lame_internal_flags_defined +struct lame_internal_flags; +typedef struct lame_internal_flags lame_internal_flags; +#endif + + +typedef enum short_block_e { + short_block_not_set = -1, /* allow LAME to decide */ + short_block_allowed = 0, /* LAME may use them, even different block types for L/R */ + short_block_coupled, /* LAME may use them, but always same block types in L/R */ + short_block_dispensed, /* LAME will not use short blocks, long blocks only */ + short_block_forced /* LAME will not use long blocks, short blocks only */ +} short_block_t; + +/*********************************************************************** +* +* Control Parameters set by User. These parameters are here for +* backwards compatibility with the old, non-shared lib API. +* Please use the lame_set_variablename() functions below +* +* +***********************************************************************/ +struct lame_global_struct { + unsigned int class_id; + + /* input description */ + unsigned long num_samples; /* number of samples. default=2^32-1 */ + int num_channels; /* input number of channels. default=2 */ + int samplerate_in; /* input_samp_rate in Hz. default=44.1 kHz */ + int samplerate_out; /* output_samp_rate. + default: LAME picks best value + at least not used for MP3 decoding: + Remember 44.1 kHz MP3s and AC97 */ + float scale; /* scale input by this amount before encoding + at least not used for MP3 decoding */ + float scale_left; /* scale input of channel 0 (left) by this + amount before encoding */ + float scale_right; /* scale input of channel 1 (right) by this + amount before encoding */ + + /* general control params */ + int analysis; /* collect data for a MP3 frame analyzer? */ + int write_lame_tag; /* add Xing VBR tag? */ + int decode_only; /* use lame/mpglib to convert mp3 to wav */ + int quality; /* quality setting 0=best, 9=worst default=5 */ + MPEG_mode mode; /* see enum in lame.h + default = LAME picks best value */ + int force_ms; /* force M/S mode. requires mode=1 */ + int free_format; /* use free format? default=0 */ + int findReplayGain; /* find the RG value? default=0 */ + int decode_on_the_fly; /* decode on the fly? default=0 */ + int write_id3tag_automatic; /* 1 (default) writes ID3 tags, 0 not */ + + int nogap_total; + int nogap_current; + + int substep_shaping; + int noise_shaping; + int subblock_gain; /* 0 = no, 1 = yes */ + int use_best_huffman; /* 0 = no. 1=outside loop 2=inside loop(slow) */ + + /* + * set either brate>0 or compression_ratio>0, LAME will compute + * the value of the variable not set. + * Default is compression_ratio = 11.025 + */ + int brate; /* bitrate */ + float compression_ratio; /* sizeof(wav file)/sizeof(mp3 file) */ + + + /* frame params */ + int copyright; /* mark as copyright. default=0 */ + int original; /* mark as original. default=1 */ + int extension; /* the MP3 'private extension' bit. + Meaningless */ + int emphasis; /* Input PCM is emphased PCM (for + instance from one of the rarely + emphased CDs), it is STRONGLY not + recommended to use this, because + psycho does not take it into account, + and last but not least many decoders + don't care about these bits */ + int error_protection; /* use 2 bytes per frame for a CRC + checksum. default=0 */ + int strict_ISO; /* enforce ISO spec as much as possible */ + + int disable_reservoir; /* use bit reservoir? */ + + /* quantization/noise shaping */ + int quant_comp; + int quant_comp_short; + int experimentalY; + int experimentalZ; + int exp_nspsytune; + + int preset; + + /* VBR control */ + vbr_mode VBR; + float VBR_q_frac; /* Range [0,...,1[ */ + int VBR_q; /* Range [0,...,9] */ + int VBR_mean_bitrate_kbps; + int VBR_min_bitrate_kbps; + int VBR_max_bitrate_kbps; + int VBR_hard_min; /* strictly enforce VBR_min_bitrate + normaly, it will be violated for analog + silence */ + + + /* resampling and filtering */ + int lowpassfreq; /* freq in Hz. 0=lame choses. + -1=no filter */ + int highpassfreq; /* freq in Hz. 0=lame choses. + -1=no filter */ + int lowpasswidth; /* freq width of filter, in Hz + (default=15%) */ + int highpasswidth; /* freq width of filter, in Hz + (default=15%) */ + + + + /* + * psycho acoustics and other arguments which you should not change + * unless you know what you are doing + */ + float maskingadjust; + float maskingadjust_short; + int ATHonly; /* only use ATH */ + int ATHshort; /* only use ATH for short blocks */ + int noATH; /* disable ATH */ + int ATHtype; /* select ATH formula */ + float ATHcurve; /* change ATH formula 4 shape */ + float ATH_lower_db; /* lower ATH by this many db */ + int athaa_type; /* select ATH auto-adjust scheme */ + float athaa_sensitivity; /* dB, tune active region of auto-level */ + short_block_t short_blocks; + int useTemporal; /* use temporal masking effect */ + float interChRatio; + float msfix; /* Naoki's adjustment of Mid/Side maskings */ + + int tune; /* 0 off, 1 on */ + float tune_value_a; /* used to pass values for debugging and stuff */ + + float attackthre; /* attack threshold for L/R/M channel */ + float attackthre_s; /* attack threshold for S channel */ + + + struct { + void (*msgf) (const char *format, va_list ap); + void (*debugf) (const char *format, va_list ap); + void (*errorf) (const char *format, va_list ap); + } report; + + /************************************************************************/ + /* internal variables, do not set... */ + /* provided because they may be of use to calling application */ + /************************************************************************/ + + int lame_allocated_gfp; /* is this struct owned by calling + program or lame? */ + + + + /**************************************************************************/ + /* more internal variables are stored in this structure: */ + /**************************************************************************/ + lame_internal_flags *internal_flags; + + + struct { + int mmx; + int amd3dnow; + int sse; + + } asm_optimizations; +}; + +int is_lame_global_flags_valid(const lame_global_flags * gfp); + +#endif /* LAME_GLOBAL_FLAGS_H */ diff --git a/pkg/lame/clame/lame_intrin.h b/pkg/lame/clame/lame_intrin.h new file mode 100644 index 0000000..bc4c189 --- /dev/null +++ b/pkg/lame/clame/lame_intrin.h @@ -0,0 +1,33 @@ +/* + * lame_intrin.h include file + * + * Copyright (c) 2006 Gabriel Bouvigne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#ifndef LAME_INTRIN_H +#define LAME_INTRIN_H + + +void +init_xrpow_core_sse(gr_info * const cod_info, FLOAT xrpow[576], int upper, FLOAT * sum); + +void +fht_SSE2(FLOAT* , int); + +#endif diff --git a/pkg/lame/clame/machine.h b/pkg/lame/clame/machine.h new file mode 100644 index 0000000..bf6fff2 --- /dev/null +++ b/pkg/lame/clame/machine.h @@ -0,0 +1,189 @@ +/* + * Machine dependent defines/includes for LAME. + * + * Copyright (c) 1999 A.L. Faber + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef LAME_MACHINE_H +#define LAME_MACHINE_H + +#include "version.h" + +#include +#include + +#ifdef STDC_HEADERS +# include +# include +#else +# ifndef HAVE_STRCHR +# define strchr index +# define strrchr rindex +# endif +char *strchr(), *strrchr(); +# ifndef HAVE_MEMCPY +# define memcpy(d, s, n) bcopy ((s), (d), (n)) +# define memmove(d, s, n) bcopy ((s), (d), (n)) +# endif +#endif + +#if defined(__riscos__) && defined(FPA10) +# include "ymath.h" +#else +# include +#endif +#include + +#include + +#ifdef HAVE_ERRNO_H +# include +#endif +#ifdef HAVE_FCNTL_H +# include +#endif + +#if defined(macintosh) +# include +# include +#else +# include +# include +#endif + +#ifdef HAVE_INTTYPES_H +# include +#else +# ifdef HAVE_STDINT_H +# include +# endif +#endif + +#ifdef WITH_DMALLOC +#include +#endif + +/* + * 3 different types of pow() functions: + * - table lookup + * - pow() + * - exp() on some machines this is claimed to be faster than pow() + */ + +#define POW20(x) (assert(0 <= (x+Q_MAX2) && x < Q_MAX), pow20[x+Q_MAX2]) +/*#define POW20(x) pow(2.0,((double)(x)-210)*.25) */ +/*#define POW20(x) exp( ((double)(x)-210)*(.25*LOG2) ) */ + +#define IPOW20(x) (assert(0 <= x && x < Q_MAX), ipow20[x]) +/*#define IPOW20(x) exp( -((double)(x)-210)*.1875*LOG2 ) */ +/*#define IPOW20(x) pow(2.0,-((double)(x)-210)*.1875) */ + +/* in case this is used without configure */ +#ifndef inline +# define inline +#endif + +#if defined(_MSC_VER) +# undef inline +# define inline _inline +#elif defined(__SASC) || defined(__GNUC__) || defined(__ICC) || defined(__ECC) +/* if __GNUC__ we always want to inline, not only if the user requests it */ +# undef inline +# define inline __inline +#endif + +#if defined(_MSC_VER) +# pragma warning( disable : 4244 ) +/*# pragma warning( disable : 4305 ) */ +#endif + +/* + * FLOAT for variables which require at least 32 bits + * FLOAT8 for variables which require at least 64 bits + * + * On some machines, 64 bit will be faster than 32 bit. Also, some math + * routines require 64 bit float, so setting FLOAT=float will result in a + * lot of conversions. + */ + +#if ( defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__) ) +# define WIN32_LEAN_AND_MEAN +# include +# include +# define FLOAT_MAX FLT_MAX +#else +# ifndef FLOAT +typedef float FLOAT; +# ifdef FLT_MAX +# define FLOAT_MAX FLT_MAX +# else +# define FLOAT_MAX 1e37 /* approx */ +# endif +# endif +#endif + +#ifndef FLOAT8 +typedef double FLOAT8; +# ifdef DBL_MAX +# define FLOAT8_MAX DBL_MAX +# else +# define FLOAT8_MAX 1e99 /* approx */ +# endif +#else +# ifdef FLT_MAX +# define FLOAT8_MAX FLT_MAX +# else +# define FLOAT8_MAX 1e37 /* approx */ +# endif +#endif + +/* sample_t must be floating point, at least 32 bits */ +typedef FLOAT sample_t; + +#define dimension_of(array) (sizeof(array)/sizeof(array[0])) +#define beyond(array) (array+dimension_of(array)) +#define compiletime_assert(expression) enum{static_assert_##FILE##_##LINE = 1/((expression)?1:0)} +#define lame_calloc(TYPE, COUNT) ((TYPE*)calloc(COUNT, sizeof(TYPE))) +#define multiple_of(CHUNK, COUNT) (\ + ( (COUNT) < 1 || (CHUNK) < 1 || (COUNT) % (CHUNK) == 0 ) \ + ? (COUNT) \ + : ((COUNT) + (CHUNK) - (COUNT) % (CHUNK)) \ + ) + +#if 1 +#define EQ(a,b) (\ +(fabs(a) > fabs(b)) \ + ? (fabs((a)-(b)) <= (fabs(a) * 1e-6f)) \ + : (fabs((a)-(b)) <= (fabs(b) * 1e-6f))) +#else +#define EQ(a,b) (fabs((a)-(b))<1E-37) +#endif + +#define NEQ(a,b) (!EQ(a,b)) + +#ifdef _MSC_VER +# if _MSC_VER < 1400 +# define fabsf fabs +# define powf pow +# define log10f log10 +# endif +#endif + +#endif + +/* end of machine.h */ diff --git a/pkg/lame/clame/mpglib_interface.c b/pkg/lame/clame/mpglib_interface.c new file mode 100644 index 0000000..d0f0b1d --- /dev/null +++ b/pkg/lame/clame/mpglib_interface.c @@ -0,0 +1,477 @@ +/* -*- mode: C; mode: fold -*- */ +/* + * LAME MP3 encoding engine + * + * Copyright (c) 1999-2000 Mark Taylor + * Copyright (c) 2003 Olcios + * Copyright (c) 2008 Robert Hegemann + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* $Id: mpglib_interface.c,v 1.44 2012/02/18 13:09:00 robert Exp $ */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef HAVE_MPGLIB +#define hip_global_struct mpstr_tag +#include "lame.h" +#include "machine.h" +#include "encoder.h" +#include "interface.h" + +#include "util.h" + + + +#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED +/* + * OBSOLETE: + * - kept to let it link + * - forward declaration to silence compiler + */ +int CDECL lame_decode_init(void); +int CDECL lame_decode( + unsigned char * mp3buf, + int len, + short pcm_l[], + short pcm_r[] ); +int CDECL lame_decode_headers( + unsigned char* mp3buf, + int len, + short pcm_l[], + short pcm_r[], + mp3data_struct* mp3data ); +int CDECL lame_decode1( + unsigned char* mp3buf, + int len, + short pcm_l[], + short pcm_r[] ); +int CDECL lame_decode1_headers( + unsigned char* mp3buf, + int len, + short pcm_l[], + short pcm_r[], + mp3data_struct* mp3data ); +int CDECL lame_decode1_headersB( + unsigned char* mp3buf, + int len, + short pcm_l[], + short pcm_r[], + mp3data_struct* mp3data, + int *enc_delay, + int *enc_padding ); +int CDECL lame_decode_exit(void); +#endif + + +static MPSTR mp; + +int +lame_decode_exit(void) +{ + ExitMP3(&mp); + return 0; +} + + +int +lame_decode_init(void) +{ + (void) InitMP3(&mp); + return 0; +} + + + + +/* copy mono samples */ +#define COPY_MONO(DST_TYPE, SRC_TYPE) \ + DST_TYPE *pcm_l = (DST_TYPE *)pcm_l_raw; \ + SRC_TYPE const *p_samples = (SRC_TYPE const *)p; \ + for (i = 0; i < processed_samples; i++) \ + *pcm_l++ = (DST_TYPE)(*p_samples++); + +/* copy stereo samples */ +#define COPY_STEREO(DST_TYPE, SRC_TYPE) \ + DST_TYPE *pcm_l = (DST_TYPE *)pcm_l_raw, *pcm_r = (DST_TYPE *)pcm_r_raw; \ + SRC_TYPE const *p_samples = (SRC_TYPE const *)p; \ + for (i = 0; i < processed_samples; i++) { \ + *pcm_l++ = (DST_TYPE)(*p_samples++); \ + *pcm_r++ = (DST_TYPE)(*p_samples++); \ + } + + + +/* + * For lame_decode: return code + * -1 error + * 0 ok, but need more data before outputing any samples + * n number of samples output. either 576 or 1152 depending on MP3 file. + */ + +static int +decode1_headersB_clipchoice(PMPSTR pmp, unsigned char *buffer, size_t len, + char pcm_l_raw[], char pcm_r_raw[], mp3data_struct * mp3data, + int *enc_delay, int *enc_padding, + char *p, size_t psize, int decoded_sample_size, + int (*decodeMP3_ptr) (PMPSTR, unsigned char *, int, char *, int, + int *)) +{ + static const int smpls[2][4] = { + /* Layer I II III */ + {0, 384, 1152, 1152}, /* MPEG-1 */ + {0, 384, 1152, 576} /* MPEG-2(.5) */ + }; + + int processed_bytes; + int processed_samples; /* processed samples per channel */ + int ret; + int i; + int const len_l = len < INT_MAX ? (int) len : INT_MAX; + int const psize_l = psize < INT_MAX ? (int) psize : INT_MAX; + + mp3data->header_parsed = 0; + ret = (*decodeMP3_ptr) (pmp, buffer, len_l, p, psize_l, &processed_bytes); + /* three cases: + * 1. headers parsed, but data not complete + * pmp->header_parsed==1 + * pmp->framesize=0 + * pmp->fsizeold=size of last frame, or 0 if this is first frame + * + * 2. headers, data parsed, but ancillary data not complete + * pmp->header_parsed==1 + * pmp->framesize=size of frame + * pmp->fsizeold=size of last frame, or 0 if this is first frame + * + * 3. frame fully decoded: + * pmp->header_parsed==0 + * pmp->framesize=0 + * pmp->fsizeold=size of frame (which is now the last frame) + * + */ + if (pmp->header_parsed || pmp->fsizeold > 0 || pmp->framesize > 0) { + mp3data->header_parsed = 1; + mp3data->stereo = pmp->fr.stereo; + mp3data->samplerate = freqs[pmp->fr.sampling_frequency]; + mp3data->mode = pmp->fr.mode; + mp3data->mode_ext = pmp->fr.mode_ext; + mp3data->framesize = smpls[pmp->fr.lsf][pmp->fr.lay]; + + /* free format, we need the entire frame before we can determine + * the bitrate. If we haven't gotten the entire frame, bitrate=0 */ + if (pmp->fsizeold > 0) /* works for free format and fixed, no overrun, temporal results are < 400.e6 */ + mp3data->bitrate = 8 * (4 + pmp->fsizeold) * mp3data->samplerate / + (1.e3 * mp3data->framesize) + 0.5; + else if (pmp->framesize > 0) + mp3data->bitrate = 8 * (4 + pmp->framesize) * mp3data->samplerate / + (1.e3 * mp3data->framesize) + 0.5; + else + mp3data->bitrate = tabsel_123[pmp->fr.lsf][pmp->fr.lay - 1][pmp->fr.bitrate_index]; + + + + if (pmp->num_frames > 0) { + /* Xing VBR header found and num_frames was set */ + mp3data->totalframes = pmp->num_frames; + mp3data->nsamp = mp3data->framesize * pmp->num_frames; + *enc_delay = pmp->enc_delay; + *enc_padding = pmp->enc_padding; + } + } + + switch (ret) { + case MP3_OK: + switch (pmp->fr.stereo) { + case 1: + processed_samples = processed_bytes / decoded_sample_size; + if (decoded_sample_size == sizeof(short)) { + COPY_MONO(short, short) + } + else { + COPY_MONO(sample_t, FLOAT) + } + break; + case 2: + processed_samples = (processed_bytes / decoded_sample_size) >> 1; + if (decoded_sample_size == sizeof(short)) { + COPY_STEREO(short, short) + } + else { + COPY_STEREO(sample_t, FLOAT) + } + break; + default: + processed_samples = -1; + assert(0); + break; + } + break; + + case MP3_NEED_MORE: + processed_samples = 0; + break; + + case MP3_ERR: + processed_samples = -1; + break; + + default: + processed_samples = -1; + assert(0); + break; + } + + /*fprintf(stderr,"ok, more, err: %i %i %i\n", MP3_OK, MP3_NEED_MORE, MP3_ERR ); */ + /*fprintf(stderr,"ret = %i out=%i\n", ret, processed_samples ); */ + return processed_samples; +} + + +#define OUTSIZE_CLIPPED (4096*sizeof(short)) + +int +lame_decode1_headersB(unsigned char *buffer, + int len, + short pcm_l[], short pcm_r[], mp3data_struct * mp3data, + int *enc_delay, int *enc_padding) +{ + static char out[OUTSIZE_CLIPPED]; + + return decode1_headersB_clipchoice(&mp, buffer, len, (char *) pcm_l, (char *) pcm_r, mp3data, + enc_delay, enc_padding, out, OUTSIZE_CLIPPED, + sizeof(short), decodeMP3); +} + + + + + +/* + * For lame_decode: return code + * -1 error + * 0 ok, but need more data before outputing any samples + * n number of samples output. Will be at most one frame of + * MPEG data. + */ + +int +lame_decode1_headers(unsigned char *buffer, + int len, short pcm_l[], short pcm_r[], mp3data_struct * mp3data) +{ + int enc_delay, enc_padding; + return lame_decode1_headersB(buffer, len, pcm_l, pcm_r, mp3data, &enc_delay, &enc_padding); +} + + +int +lame_decode1(unsigned char *buffer, int len, short pcm_l[], short pcm_r[]) +{ + mp3data_struct mp3data; + + return lame_decode1_headers(buffer, len, pcm_l, pcm_r, &mp3data); +} + + +/* + * For lame_decode: return code + * -1 error + * 0 ok, but need more data before outputing any samples + * n number of samples output. a multiple of 576 or 1152 depending on MP3 file. + */ + +int +lame_decode_headers(unsigned char *buffer, + int len, short pcm_l[], short pcm_r[], mp3data_struct * mp3data) +{ + int ret; + int totsize = 0; /* number of decoded samples per channel */ + + for (;;) { + switch (ret = lame_decode1_headers(buffer, len, pcm_l + totsize, pcm_r + totsize, mp3data)) { + case -1: + return ret; + case 0: + return totsize; + default: + totsize += ret; + len = 0; /* future calls to decodeMP3 are just to flush buffers */ + break; + } + } +} + + +int +lame_decode(unsigned char *buffer, int len, short pcm_l[], short pcm_r[]) +{ + mp3data_struct mp3data; + + return lame_decode_headers(buffer, len, pcm_l, pcm_r, &mp3data); +} + + + + +hip_t hip_decode_init(void) +{ + hip_t hip = lame_calloc(hip_global_flags, 1); + InitMP3(hip); + return hip; +} + + +int hip_decode_exit(hip_t hip) +{ + if (hip) { + ExitMP3(hip); + free(hip); + } + return 0; +} + + +/* we forbid input with more than 1152 samples per channel for output in the unclipped mode */ +#define OUTSIZE_UNCLIPPED (1152*2*sizeof(FLOAT)) + +int +hip_decode1_unclipped(hip_t hip, unsigned char *buffer, size_t len, sample_t pcm_l[], sample_t pcm_r[]) +{ + static char out[OUTSIZE_UNCLIPPED]; + mp3data_struct mp3data; + int enc_delay, enc_padding; + + if (hip) { + return decode1_headersB_clipchoice(hip, buffer, len, (char *) pcm_l, (char *) pcm_r, &mp3data, + &enc_delay, &enc_padding, out, OUTSIZE_UNCLIPPED, + sizeof(FLOAT), decodeMP3_unclipped); + } + return 0; +} + +/* + * For hip_decode: return code + * -1 error + * 0 ok, but need more data before outputing any samples + * n number of samples output. Will be at most one frame of + * MPEG data. + */ + +int +hip_decode1_headers(hip_t hip, unsigned char *buffer, + size_t len, short pcm_l[], short pcm_r[], mp3data_struct * mp3data) +{ + int enc_delay, enc_padding; + return hip_decode1_headersB(hip, buffer, len, pcm_l, pcm_r, mp3data, &enc_delay, &enc_padding); +} + + +int +hip_decode1(hip_t hip, unsigned char *buffer, size_t len, short pcm_l[], short pcm_r[]) +{ + mp3data_struct mp3data; + return hip_decode1_headers(hip, buffer, len, pcm_l, pcm_r, &mp3data); +} + + +/* + * For hip_decode: return code + * -1 error + * 0 ok, but need more data before outputing any samples + * n number of samples output. a multiple of 576 or 1152 depending on MP3 file. + */ + +int +hip_decode_headers(hip_t hip, unsigned char *buffer, + size_t len, short pcm_l[], short pcm_r[], mp3data_struct * mp3data) +{ + int ret; + int totsize = 0; /* number of decoded samples per channel */ + + for (;;) { + switch (ret = hip_decode1_headers(hip, buffer, len, pcm_l + totsize, pcm_r + totsize, mp3data)) { + case -1: + return ret; + case 0: + return totsize; + default: + totsize += ret; + len = 0; /* future calls to decodeMP3 are just to flush buffers */ + break; + } + } +} + + +int +hip_decode(hip_t hip, unsigned char *buffer, size_t len, short pcm_l[], short pcm_r[]) +{ + mp3data_struct mp3data; + return hip_decode_headers(hip, buffer, len, pcm_l, pcm_r, &mp3data); +} + + +int +hip_decode1_headersB(hip_t hip, unsigned char *buffer, + size_t len, + short pcm_l[], short pcm_r[], mp3data_struct * mp3data, + int *enc_delay, int *enc_padding) +{ + static char out[OUTSIZE_CLIPPED]; + if (hip) { + return decode1_headersB_clipchoice(hip, buffer, len, (char *) pcm_l, (char *) pcm_r, mp3data, + enc_delay, enc_padding, out, OUTSIZE_CLIPPED, + sizeof(short), decodeMP3); + } + return -1; +} + + +void hip_set_pinfo(hip_t hip, plotting_data* pinfo) +{ + if (hip) { + hip->pinfo = pinfo; + } +} + + + +void hip_set_errorf(hip_t hip, lame_report_function func) +{ + if (hip) { + hip->report_err = func; + } +} + +void hip_set_debugf(hip_t hip, lame_report_function func) +{ + if (hip) { + hip->report_dbg = func; + } +} + +void hip_set_msgf (hip_t hip, lame_report_function func) +{ + if (hip) { + hip->report_msg = func; + } +} + +#endif + +/* end of mpglib_interface.c */ diff --git a/pkg/lame/clame/newmdct.c b/pkg/lame/clame/newmdct.c new file mode 100644 index 0000000..596cac9 --- /dev/null +++ b/pkg/lame/clame/newmdct.c @@ -0,0 +1,1039 @@ +/* + * MP3 window subband -> subband filtering -> mdct routine + * + * Copyright (c) 1999-2000 Takehiro Tominaga + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Special Thanks to Patrick De Smet for your advices. + */ + +/* $Id: newmdct.c,v 1.39 2011/05/07 16:05:17 rbrito Exp $ */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "lame.h" +#include "machine.h" +#include "encoder.h" +#include "util.h" +#include "newmdct.h" + + + +#ifndef USE_GOGO_SUBBAND +static const FLOAT enwindow[] = { + -4.77e-07 * 0.740951125354959 / 2.384e-06, 1.03951e-04 * 0.740951125354959 / 2.384e-06, + 9.53674e-04 * 0.740951125354959 / 2.384e-06, 2.841473e-03 * 0.740951125354959 / 2.384e-06, + 3.5758972e-02 * 0.740951125354959 / 2.384e-06, 3.401756e-03 * 0.740951125354959 / 2.384e-06, 9.83715e-04 * 0.740951125354959 / 2.384e-06, 9.9182e-05 * 0.740951125354959 / 2.384e-06, /* 15 */ + 1.2398e-05 * 0.740951125354959 / 2.384e-06, 1.91212e-04 * 0.740951125354959 / 2.384e-06, + 2.283096e-03 * 0.740951125354959 / 2.384e-06, 1.6994476e-02 * 0.740951125354959 / 2.384e-06, + -1.8756866e-02 * 0.740951125354959 / 2.384e-06, -2.630711e-03 * 0.740951125354959 / 2.384e-06, + -2.47478e-04 * 0.740951125354959 / 2.384e-06, -1.4782e-05 * 0.740951125354959 / 2.384e-06, + 9.063471690191471e-01, + 1.960342806591213e-01, + + + -4.77e-07 * 0.773010453362737 / 2.384e-06, 1.05858e-04 * 0.773010453362737 / 2.384e-06, + 9.30786e-04 * 0.773010453362737 / 2.384e-06, 2.521515e-03 * 0.773010453362737 / 2.384e-06, + 3.5694122e-02 * 0.773010453362737 / 2.384e-06, 3.643036e-03 * 0.773010453362737 / 2.384e-06, 9.91821e-04 * 0.773010453362737 / 2.384e-06, 9.6321e-05 * 0.773010453362737 / 2.384e-06, /* 14 */ + 1.1444e-05 * 0.773010453362737 / 2.384e-06, 1.65462e-04 * 0.773010453362737 / 2.384e-06, + 2.110004e-03 * 0.773010453362737 / 2.384e-06, 1.6112804e-02 * 0.773010453362737 / 2.384e-06, + -1.9634247e-02 * 0.773010453362737 / 2.384e-06, -2.803326e-03 * 0.773010453362737 / 2.384e-06, + -2.77042e-04 * 0.773010453362737 / 2.384e-06, -1.6689e-05 * 0.773010453362737 / 2.384e-06, + 8.206787908286602e-01, + 3.901806440322567e-01, + + + -4.77e-07 * 0.803207531480645 / 2.384e-06, 1.07288e-04 * 0.803207531480645 / 2.384e-06, + 9.02653e-04 * 0.803207531480645 / 2.384e-06, 2.174854e-03 * 0.803207531480645 / 2.384e-06, + 3.5586357e-02 * 0.803207531480645 / 2.384e-06, 3.858566e-03 * 0.803207531480645 / 2.384e-06, 9.95159e-04 * 0.803207531480645 / 2.384e-06, 9.3460e-05 * 0.803207531480645 / 2.384e-06, /* 13 */ + 1.0014e-05 * 0.803207531480645 / 2.384e-06, 1.40190e-04 * 0.803207531480645 / 2.384e-06, + 1.937389e-03 * 0.803207531480645 / 2.384e-06, 1.5233517e-02 * 0.803207531480645 / 2.384e-06, + -2.0506859e-02 * 0.803207531480645 / 2.384e-06, -2.974033e-03 * 0.803207531480645 / 2.384e-06, + -3.07560e-04 * 0.803207531480645 / 2.384e-06, -1.8120e-05 * 0.803207531480645 / 2.384e-06, + 7.416505462720353e-01, + 5.805693545089249e-01, + + + -4.77e-07 * 0.831469612302545 / 2.384e-06, 1.08242e-04 * 0.831469612302545 / 2.384e-06, + 8.68797e-04 * 0.831469612302545 / 2.384e-06, 1.800537e-03 * 0.831469612302545 / 2.384e-06, + 3.5435200e-02 * 0.831469612302545 / 2.384e-06, 4.049301e-03 * 0.831469612302545 / 2.384e-06, 9.94205e-04 * 0.831469612302545 / 2.384e-06, 9.0599e-05 * 0.831469612302545 / 2.384e-06, /* 12 */ + 9.060e-06 * 0.831469612302545 / 2.384e-06, 1.16348e-04 * 0.831469612302545 / 2.384e-06, + 1.766682e-03 * 0.831469612302545 / 2.384e-06, 1.4358521e-02 * 0.831469612302545 / 2.384e-06, + -2.1372318e-02 * 0.831469612302545 / 2.384e-06, -3.14188e-03 * 0.831469612302545 / 2.384e-06, + -3.39031e-04 * 0.831469612302545 / 2.384e-06, -1.9550e-05 * 0.831469612302545 / 2.384e-06, + 6.681786379192989e-01, + 7.653668647301797e-01, + + + -4.77e-07 * 0.857728610000272 / 2.384e-06, 1.08719e-04 * 0.857728610000272 / 2.384e-06, + 8.29220e-04 * 0.857728610000272 / 2.384e-06, 1.399517e-03 * 0.857728610000272 / 2.384e-06, + 3.5242081e-02 * 0.857728610000272 / 2.384e-06, 4.215240e-03 * 0.857728610000272 / 2.384e-06, 9.89437e-04 * 0.857728610000272 / 2.384e-06, 8.7261e-05 * 0.857728610000272 / 2.384e-06, /* 11 */ + 8.106e-06 * 0.857728610000272 / 2.384e-06, 9.3937e-05 * 0.857728610000272 / 2.384e-06, + 1.597881e-03 * 0.857728610000272 / 2.384e-06, 1.3489246e-02 * 0.857728610000272 / 2.384e-06, + -2.2228718e-02 * 0.857728610000272 / 2.384e-06, -3.306866e-03 * 0.857728610000272 / 2.384e-06, + -3.71456e-04 * 0.857728610000272 / 2.384e-06, -2.1458e-05 * 0.857728610000272 / 2.384e-06, + 5.993769336819237e-01, + 9.427934736519954e-01, + + + -4.77e-07 * 0.881921264348355 / 2.384e-06, 1.08719e-04 * 0.881921264348355 / 2.384e-06, + 7.8392e-04 * 0.881921264348355 / 2.384e-06, 9.71317e-04 * 0.881921264348355 / 2.384e-06, + 3.5007000e-02 * 0.881921264348355 / 2.384e-06, 4.357815e-03 * 0.881921264348355 / 2.384e-06, 9.80854e-04 * 0.881921264348355 / 2.384e-06, 8.3923e-05 * 0.881921264348355 / 2.384e-06, /* 10 */ + 7.629e-06 * 0.881921264348355 / 2.384e-06, 7.2956e-05 * 0.881921264348355 / 2.384e-06, + 1.432419e-03 * 0.881921264348355 / 2.384e-06, 1.2627602e-02 * 0.881921264348355 / 2.384e-06, + -2.3074150e-02 * 0.881921264348355 / 2.384e-06, -3.467083e-03 * 0.881921264348355 / 2.384e-06, + -4.04358e-04 * 0.881921264348355 / 2.384e-06, -2.3365e-05 * 0.881921264348355 / 2.384e-06, + 5.345111359507916e-01, + 1.111140466039205e+00, + + + -9.54e-07 * 0.903989293123443 / 2.384e-06, 1.08242e-04 * 0.903989293123443 / 2.384e-06, + 7.31945e-04 * 0.903989293123443 / 2.384e-06, 5.15938e-04 * 0.903989293123443 / 2.384e-06, + 3.4730434e-02 * 0.903989293123443 / 2.384e-06, 4.477024e-03 * 0.903989293123443 / 2.384e-06, 9.68933e-04 * 0.903989293123443 / 2.384e-06, 8.0585e-05 * 0.903989293123443 / 2.384e-06, /* 9 */ + 6.676e-06 * 0.903989293123443 / 2.384e-06, 5.2929e-05 * 0.903989293123443 / 2.384e-06, + 1.269817e-03 * 0.903989293123443 / 2.384e-06, 1.1775017e-02 * 0.903989293123443 / 2.384e-06, + -2.3907185e-02 * 0.903989293123443 / 2.384e-06, -3.622532e-03 * 0.903989293123443 / 2.384e-06, + -4.38213e-04 * 0.903989293123443 / 2.384e-06, -2.5272e-05 * 0.903989293123443 / 2.384e-06, + 4.729647758913199e-01, + 1.268786568327291e+00, + + + -9.54e-07 * 0.92387953251128675613 / 2.384e-06, + 1.06812e-04 * 0.92387953251128675613 / 2.384e-06, + 6.74248e-04 * 0.92387953251128675613 / 2.384e-06, + 3.3379e-05 * 0.92387953251128675613 / 2.384e-06, + 3.4412861e-02 * 0.92387953251128675613 / 2.384e-06, + 4.573822e-03 * 0.92387953251128675613 / 2.384e-06, + 9.54151e-04 * 0.92387953251128675613 / 2.384e-06, + 7.6771e-05 * 0.92387953251128675613 / 2.384e-06, + 6.199e-06 * 0.92387953251128675613 / 2.384e-06, 3.4332e-05 * 0.92387953251128675613 / 2.384e-06, + 1.111031e-03 * 0.92387953251128675613 / 2.384e-06, + 1.0933399e-02 * 0.92387953251128675613 / 2.384e-06, + -2.4725437e-02 * 0.92387953251128675613 / 2.384e-06, + -3.771782e-03 * 0.92387953251128675613 / 2.384e-06, + -4.72546e-04 * 0.92387953251128675613 / 2.384e-06, + -2.7657e-05 * 0.92387953251128675613 / 2.384e-06, + 4.1421356237309504879e-01, /* tan(PI/8) */ + 1.414213562373095e+00, + + + -9.54e-07 * 0.941544065183021 / 2.384e-06, 1.05381e-04 * 0.941544065183021 / 2.384e-06, + 6.10352e-04 * 0.941544065183021 / 2.384e-06, -4.75883e-04 * 0.941544065183021 / 2.384e-06, + 3.4055710e-02 * 0.941544065183021 / 2.384e-06, 4.649162e-03 * 0.941544065183021 / 2.384e-06, 9.35555e-04 * 0.941544065183021 / 2.384e-06, 7.3433e-05 * 0.941544065183021 / 2.384e-06, /* 7 */ + 5.245e-06 * 0.941544065183021 / 2.384e-06, 1.7166e-05 * 0.941544065183021 / 2.384e-06, + 9.56535e-04 * 0.941544065183021 / 2.384e-06, 1.0103703e-02 * 0.941544065183021 / 2.384e-06, + -2.5527000e-02 * 0.941544065183021 / 2.384e-06, -3.914356e-03 * 0.941544065183021 / 2.384e-06, + -5.07355e-04 * 0.941544065183021 / 2.384e-06, -3.0041e-05 * 0.941544065183021 / 2.384e-06, + 3.578057213145241e-01, + 1.546020906725474e+00, + + + -9.54e-07 * 0.956940335732209 / 2.384e-06, 1.02520e-04 * 0.956940335732209 / 2.384e-06, + 5.39303e-04 * 0.956940335732209 / 2.384e-06, -1.011848e-03 * 0.956940335732209 / 2.384e-06, + 3.3659935e-02 * 0.956940335732209 / 2.384e-06, 4.703045e-03 * 0.956940335732209 / 2.384e-06, 9.15051e-04 * 0.956940335732209 / 2.384e-06, 7.0095e-05 * 0.956940335732209 / 2.384e-06, /* 6 */ + 4.768e-06 * 0.956940335732209 / 2.384e-06, 9.54e-07 * 0.956940335732209 / 2.384e-06, + 8.06808e-04 * 0.956940335732209 / 2.384e-06, 9.287834e-03 * 0.956940335732209 / 2.384e-06, + -2.6310921e-02 * 0.956940335732209 / 2.384e-06, -4.048824e-03 * 0.956940335732209 / 2.384e-06, + -5.42164e-04 * 0.956940335732209 / 2.384e-06, -3.2425e-05 * 0.956940335732209 / 2.384e-06, + 3.033466836073424e-01, + 1.662939224605090e+00, + + + -1.431e-06 * 0.970031253194544 / 2.384e-06, 9.9182e-05 * 0.970031253194544 / 2.384e-06, + 4.62532e-04 * 0.970031253194544 / 2.384e-06, -1.573563e-03 * 0.970031253194544 / 2.384e-06, + 3.3225536e-02 * 0.970031253194544 / 2.384e-06, 4.737377e-03 * 0.970031253194544 / 2.384e-06, 8.91685e-04 * 0.970031253194544 / 2.384e-06, 6.6280e-05 * 0.970031253194544 / 2.384e-06, /* 5 */ + 4.292e-06 * 0.970031253194544 / 2.384e-06, -1.3828e-05 * 0.970031253194544 / 2.384e-06, + 6.61850e-04 * 0.970031253194544 / 2.384e-06, 8.487225e-03 * 0.970031253194544 / 2.384e-06, + -2.7073860e-02 * 0.970031253194544 / 2.384e-06, -4.174709e-03 * 0.970031253194544 / 2.384e-06, + -5.76973e-04 * 0.970031253194544 / 2.384e-06, -3.4809e-05 * 0.970031253194544 / 2.384e-06, + 2.504869601913055e-01, + 1.763842528696710e+00, + + + -1.431e-06 * 0.98078528040323 / 2.384e-06, 9.5367e-05 * 0.98078528040323 / 2.384e-06, + 3.78609e-04 * 0.98078528040323 / 2.384e-06, -2.161503e-03 * 0.98078528040323 / 2.384e-06, + 3.2754898e-02 * 0.98078528040323 / 2.384e-06, 4.752159e-03 * 0.98078528040323 / 2.384e-06, 8.66413e-04 * 0.98078528040323 / 2.384e-06, 6.2943e-05 * 0.98078528040323 / 2.384e-06, /* 4 */ + 3.815e-06 * 0.98078528040323 / 2.384e-06, -2.718e-05 * 0.98078528040323 / 2.384e-06, + 5.22137e-04 * 0.98078528040323 / 2.384e-06, 7.703304e-03 * 0.98078528040323 / 2.384e-06, + -2.7815342e-02 * 0.98078528040323 / 2.384e-06, -4.290581e-03 * 0.98078528040323 / 2.384e-06, + -6.11782e-04 * 0.98078528040323 / 2.384e-06, -3.7670e-05 * 0.98078528040323 / 2.384e-06, + 1.989123673796580e-01, + 1.847759065022573e+00, + + + -1.907e-06 * 0.989176509964781 / 2.384e-06, 9.0122e-05 * 0.989176509964781 / 2.384e-06, + 2.88486e-04 * 0.989176509964781 / 2.384e-06, -2.774239e-03 * 0.989176509964781 / 2.384e-06, + 3.2248020e-02 * 0.989176509964781 / 2.384e-06, 4.748821e-03 * 0.989176509964781 / 2.384e-06, 8.38757e-04 * 0.989176509964781 / 2.384e-06, 5.9605e-05 * 0.989176509964781 / 2.384e-06, /* 3 */ + 3.338e-06 * 0.989176509964781 / 2.384e-06, -3.9577e-05 * 0.989176509964781 / 2.384e-06, + 3.88145e-04 * 0.989176509964781 / 2.384e-06, 6.937027e-03 * 0.989176509964781 / 2.384e-06, + -2.8532982e-02 * 0.989176509964781 / 2.384e-06, -4.395962e-03 * 0.989176509964781 / 2.384e-06, + -6.46591e-04 * 0.989176509964781 / 2.384e-06, -4.0531e-05 * 0.989176509964781 / 2.384e-06, + 1.483359875383474e-01, + 1.913880671464418e+00, + + + -1.907e-06 * 0.995184726672197 / 2.384e-06, 8.4400e-05 * 0.995184726672197 / 2.384e-06, + 1.91689e-04 * 0.995184726672197 / 2.384e-06, -3.411293e-03 * 0.995184726672197 / 2.384e-06, + 3.1706810e-02 * 0.995184726672197 / 2.384e-06, 4.728317e-03 * 0.995184726672197 / 2.384e-06, + 8.09669e-04 * 0.995184726672197 / 2.384e-06, 5.579e-05 * 0.995184726672197 / 2.384e-06, + 3.338e-06 * 0.995184726672197 / 2.384e-06, -5.0545e-05 * 0.995184726672197 / 2.384e-06, + 2.59876e-04 * 0.995184726672197 / 2.384e-06, 6.189346e-03 * 0.995184726672197 / 2.384e-06, + -2.9224873e-02 * 0.995184726672197 / 2.384e-06, -4.489899e-03 * 0.995184726672197 / 2.384e-06, + -6.80923e-04 * 0.995184726672197 / 2.384e-06, -4.3392e-05 * 0.995184726672197 / 2.384e-06, + 9.849140335716425e-02, + 1.961570560806461e+00, + + + -2.384e-06 * 0.998795456205172 / 2.384e-06, 7.7724e-05 * 0.998795456205172 / 2.384e-06, + 8.8215e-05 * 0.998795456205172 / 2.384e-06, -4.072189e-03 * 0.998795456205172 / 2.384e-06, + 3.1132698e-02 * 0.998795456205172 / 2.384e-06, 4.691124e-03 * 0.998795456205172 / 2.384e-06, + 7.79152e-04 * 0.998795456205172 / 2.384e-06, 5.2929e-05 * 0.998795456205172 / 2.384e-06, + 2.861e-06 * 0.998795456205172 / 2.384e-06, -6.0558e-05 * 0.998795456205172 / 2.384e-06, + 1.37329e-04 * 0.998795456205172 / 2.384e-06, 5.462170e-03 * 0.998795456205172 / 2.384e-06, + -2.9890060e-02 * 0.998795456205172 / 2.384e-06, -4.570484e-03 * 0.998795456205172 / 2.384e-06, + -7.14302e-04 * 0.998795456205172 / 2.384e-06, -4.6253e-05 * 0.998795456205172 / 2.384e-06, + 4.912684976946725e-02, + 1.990369453344394e+00, + + + 3.5780907e-02 * SQRT2 * 0.5 / 2.384e-06, 1.7876148e-02 * SQRT2 * 0.5 / 2.384e-06, + 3.134727e-03 * SQRT2 * 0.5 / 2.384e-06, 2.457142e-03 * SQRT2 * 0.5 / 2.384e-06, + 9.71317e-04 * SQRT2 * 0.5 / 2.384e-06, 2.18868e-04 * SQRT2 * 0.5 / 2.384e-06, + 1.01566e-04 * SQRT2 * 0.5 / 2.384e-06, 1.3828e-05 * SQRT2 * 0.5 / 2.384e-06, + + 3.0526638e-02 / 2.384e-06, 4.638195e-03 / 2.384e-06, 7.47204e-04 / 2.384e-06, + 4.9591e-05 / 2.384e-06, + 4.756451e-03 / 2.384e-06, 2.1458e-05 / 2.384e-06, -6.9618e-05 / 2.384e-06, /* 2.384e-06/2.384e-06 */ +}; +#endif + + +#define NS 12 +#define NL 36 + +static const FLOAT win[4][NL] = { + { + 2.382191739347913e-13, + 6.423305872147834e-13, + 9.400849094049688e-13, + 1.122435026096556e-12, + 1.183840321267481e-12, + 1.122435026096556e-12, + 9.400849094049690e-13, + 6.423305872147839e-13, + 2.382191739347918e-13, + + 5.456116108943412e-12, + 4.878985199565852e-12, + 4.240448995017367e-12, + 3.559909094758252e-12, + 2.858043359288075e-12, + 2.156177623817898e-12, + 1.475637723558783e-12, + 8.371015190102974e-13, + 2.599706096327376e-13, + + -5.456116108943412e-12, + -4.878985199565852e-12, + -4.240448995017367e-12, + -3.559909094758252e-12, + -2.858043359288076e-12, + -2.156177623817898e-12, + -1.475637723558783e-12, + -8.371015190102975e-13, + -2.599706096327376e-13, + + -2.382191739347923e-13, + -6.423305872147843e-13, + -9.400849094049696e-13, + -1.122435026096556e-12, + -1.183840321267481e-12, + -1.122435026096556e-12, + -9.400849094049694e-13, + -6.423305872147840e-13, + -2.382191739347918e-13, + }, + { + 2.382191739347913e-13, + 6.423305872147834e-13, + 9.400849094049688e-13, + 1.122435026096556e-12, + 1.183840321267481e-12, + 1.122435026096556e-12, + 9.400849094049688e-13, + 6.423305872147841e-13, + 2.382191739347918e-13, + + 5.456116108943413e-12, + 4.878985199565852e-12, + 4.240448995017367e-12, + 3.559909094758253e-12, + 2.858043359288075e-12, + 2.156177623817898e-12, + 1.475637723558782e-12, + 8.371015190102975e-13, + 2.599706096327376e-13, + + -5.461314069809755e-12, + -4.921085770524055e-12, + -4.343405037091838e-12, + -3.732668368707687e-12, + -3.093523840190885e-12, + -2.430835727329465e-12, + -1.734679010007751e-12, + -9.748253656609281e-13, + -2.797435120168326e-13, + + 0.000000000000000e+00, + 0.000000000000000e+00, + 0.000000000000000e+00, + 0.000000000000000e+00, + 0.000000000000000e+00, + 0.000000000000000e+00, + -2.283748241799531e-13, + -4.037858874020686e-13, + -2.146547464825323e-13, + }, + { + 1.316524975873958e-01, /* win[SHORT_TYPE] */ + 4.142135623730950e-01, + 7.673269879789602e-01, + + 1.091308501069271e+00, /* tantab_l */ + 1.303225372841206e+00, + 1.569685577117490e+00, + 1.920982126971166e+00, + 2.414213562373094e+00, + 3.171594802363212e+00, + 4.510708503662055e+00, + 7.595754112725146e+00, + 2.290376554843115e+01, + + 0.98480775301220802032, /* cx */ + 0.64278760968653936292, + 0.34202014332566882393, + 0.93969262078590842791, + -0.17364817766693030343, + -0.76604444311897790243, + 0.86602540378443870761, + 0.500000000000000e+00, + + -5.144957554275265e-01, /* ca */ + -4.717319685649723e-01, + -3.133774542039019e-01, + -1.819131996109812e-01, + -9.457419252642064e-02, + -4.096558288530405e-02, + -1.419856857247115e-02, + -3.699974673760037e-03, + + 8.574929257125442e-01, /* cs */ + 8.817419973177052e-01, + 9.496286491027329e-01, + 9.833145924917901e-01, + 9.955178160675857e-01, + 9.991605581781475e-01, + 9.998991952444470e-01, + 9.999931550702802e-01, + }, + { + 0.000000000000000e+00, + 0.000000000000000e+00, + 0.000000000000000e+00, + 0.000000000000000e+00, + 0.000000000000000e+00, + 0.000000000000000e+00, + 2.283748241799531e-13, + 4.037858874020686e-13, + 2.146547464825323e-13, + + 5.461314069809755e-12, + 4.921085770524055e-12, + 4.343405037091838e-12, + 3.732668368707687e-12, + 3.093523840190885e-12, + 2.430835727329466e-12, + 1.734679010007751e-12, + 9.748253656609281e-13, + 2.797435120168326e-13, + + -5.456116108943413e-12, + -4.878985199565852e-12, + -4.240448995017367e-12, + -3.559909094758253e-12, + -2.858043359288075e-12, + -2.156177623817898e-12, + -1.475637723558782e-12, + -8.371015190102975e-13, + -2.599706096327376e-13, + + -2.382191739347913e-13, + -6.423305872147834e-13, + -9.400849094049688e-13, + -1.122435026096556e-12, + -1.183840321267481e-12, + -1.122435026096556e-12, + -9.400849094049688e-13, + -6.423305872147841e-13, + -2.382191739347918e-13, + } +}; + +#define tantab_l (win[SHORT_TYPE]+3) +#define cx (win[SHORT_TYPE]+12) +#define ca (win[SHORT_TYPE]+20) +#define cs (win[SHORT_TYPE]+28) + +/************************************************************************ +* +* window_subband() +* +* PURPOSE: Overlapping window on PCM samples +* +* SEMANTICS: +* 32 16-bit pcm samples are scaled to fractional 2's complement and +* concatenated to the end of the window buffer #x#. The updated window +* buffer #x# is then windowed by the analysis window #c# to produce the +* windowed sample #z# +* +************************************************************************/ + +/* + * new IDCT routine written by Takehiro TOMINAGA + */ +static const int order[] = { + 0, 1, 16, 17, 8, 9, 24, 25, 4, 5, 20, 21, 12, 13, 28, 29, + 2, 3, 18, 19, 10, 11, 26, 27, 6, 7, 22, 23, 14, 15, 30, 31 +}; + + +/* returns sum_j=0^31 a[j]*cos(PI*j*(k+1/2)/32), 0<=k<32 */ +inline static void +window_subband(const sample_t * x1, FLOAT a[SBLIMIT]) +{ + int i; + FLOAT const *wp = enwindow + 10; + + const sample_t *x2 = &x1[238 - 14 - 286]; + + for (i = -15; i < 0; i++) { + FLOAT w, s, t; + + w = wp[-10]; + s = x2[-224] * w; + t = x1[224] * w; + w = wp[-9]; + s += x2[-160] * w; + t += x1[160] * w; + w = wp[-8]; + s += x2[-96] * w; + t += x1[96] * w; + w = wp[-7]; + s += x2[-32] * w; + t += x1[32] * w; + w = wp[-6]; + s += x2[32] * w; + t += x1[-32] * w; + w = wp[-5]; + s += x2[96] * w; + t += x1[-96] * w; + w = wp[-4]; + s += x2[160] * w; + t += x1[-160] * w; + w = wp[-3]; + s += x2[224] * w; + t += x1[-224] * w; + + w = wp[-2]; + s += x1[-256] * w; + t -= x2[256] * w; + w = wp[-1]; + s += x1[-192] * w; + t -= x2[192] * w; + w = wp[0]; + s += x1[-128] * w; + t -= x2[128] * w; + w = wp[1]; + s += x1[-64] * w; + t -= x2[64] * w; + w = wp[2]; + s += x1[0] * w; + t -= x2[0] * w; + w = wp[3]; + s += x1[64] * w; + t -= x2[-64] * w; + w = wp[4]; + s += x1[128] * w; + t -= x2[-128] * w; + w = wp[5]; + s += x1[192] * w; + t -= x2[-192] * w; + + /* + * this multiplyer could be removed, but it needs more 256 FLOAT data. + * thinking about the data cache performance, I think we should not + * use such a huge table. tt 2000/Oct/25 + */ + s *= wp[6]; + w = t - s; + a[30 + i * 2] = t + s; + a[31 + i * 2] = wp[7] * w; + wp += 18; + x1--; + x2++; + } + { + FLOAT s, t, u, v; + t = x1[-16] * wp[-10]; + s = x1[-32] * wp[-2]; + t += (x1[-48] - x1[16]) * wp[-9]; + s += x1[-96] * wp[-1]; + t += (x1[-80] + x1[48]) * wp[-8]; + s += x1[-160] * wp[0]; + t += (x1[-112] - x1[80]) * wp[-7]; + s += x1[-224] * wp[1]; + t += (x1[-144] + x1[112]) * wp[-6]; + s -= x1[32] * wp[2]; + t += (x1[-176] - x1[144]) * wp[-5]; + s -= x1[96] * wp[3]; + t += (x1[-208] + x1[176]) * wp[-4]; + s -= x1[160] * wp[4]; + t += (x1[-240] - x1[208]) * wp[-3]; + s -= x1[224]; + + u = s - t; + v = s + t; + + t = a[14]; + s = a[15] - t; + + a[31] = v + t; /* A0 */ + a[30] = u + s; /* A1 */ + a[15] = u - s; /* A2 */ + a[14] = v - t; /* A3 */ + } + { + FLOAT xr; + xr = a[28] - a[0]; + a[0] += a[28]; + a[28] = xr * wp[-2 * 18 + 7]; + xr = a[29] - a[1]; + a[1] += a[29]; + a[29] = xr * wp[-2 * 18 + 7]; + + xr = a[26] - a[2]; + a[2] += a[26]; + a[26] = xr * wp[-4 * 18 + 7]; + xr = a[27] - a[3]; + a[3] += a[27]; + a[27] = xr * wp[-4 * 18 + 7]; + + xr = a[24] - a[4]; + a[4] += a[24]; + a[24] = xr * wp[-6 * 18 + 7]; + xr = a[25] - a[5]; + a[5] += a[25]; + a[25] = xr * wp[-6 * 18 + 7]; + + xr = a[22] - a[6]; + a[6] += a[22]; + a[22] = xr * SQRT2; + xr = a[23] - a[7]; + a[7] += a[23]; + a[23] = xr * SQRT2 - a[7]; + a[7] -= a[6]; + a[22] -= a[7]; + a[23] -= a[22]; + + xr = a[6]; + a[6] = a[31] - xr; + a[31] = a[31] + xr; + xr = a[7]; + a[7] = a[30] - xr; + a[30] = a[30] + xr; + xr = a[22]; + a[22] = a[15] - xr; + a[15] = a[15] + xr; + xr = a[23]; + a[23] = a[14] - xr; + a[14] = a[14] + xr; + + xr = a[20] - a[8]; + a[8] += a[20]; + a[20] = xr * wp[-10 * 18 + 7]; + xr = a[21] - a[9]; + a[9] += a[21]; + a[21] = xr * wp[-10 * 18 + 7]; + + xr = a[18] - a[10]; + a[10] += a[18]; + a[18] = xr * wp[-12 * 18 + 7]; + xr = a[19] - a[11]; + a[11] += a[19]; + a[19] = xr * wp[-12 * 18 + 7]; + + xr = a[16] - a[12]; + a[12] += a[16]; + a[16] = xr * wp[-14 * 18 + 7]; + xr = a[17] - a[13]; + a[13] += a[17]; + a[17] = xr * wp[-14 * 18 + 7]; + + xr = -a[20] + a[24]; + a[20] += a[24]; + a[24] = xr * wp[-12 * 18 + 7]; + xr = -a[21] + a[25]; + a[21] += a[25]; + a[25] = xr * wp[-12 * 18 + 7]; + + xr = a[4] - a[8]; + a[4] += a[8]; + a[8] = xr * wp[-12 * 18 + 7]; + xr = a[5] - a[9]; + a[5] += a[9]; + a[9] = xr * wp[-12 * 18 + 7]; + + xr = a[0] - a[12]; + a[0] += a[12]; + a[12] = xr * wp[-4 * 18 + 7]; + xr = a[1] - a[13]; + a[1] += a[13]; + a[13] = xr * wp[-4 * 18 + 7]; + xr = a[16] - a[28]; + a[16] += a[28]; + a[28] = xr * wp[-4 * 18 + 7]; + xr = -a[17] + a[29]; + a[17] += a[29]; + a[29] = xr * wp[-4 * 18 + 7]; + + xr = SQRT2 * (a[2] - a[10]); + a[2] += a[10]; + a[10] = xr; + xr = SQRT2 * (a[3] - a[11]); + a[3] += a[11]; + a[11] = xr; + xr = SQRT2 * (-a[18] + a[26]); + a[18] += a[26]; + a[26] = xr - a[18]; + xr = SQRT2 * (-a[19] + a[27]); + a[19] += a[27]; + a[27] = xr - a[19]; + + xr = a[2]; + a[19] -= a[3]; + a[3] -= xr; + a[2] = a[31] - xr; + a[31] += xr; + xr = a[3]; + a[11] -= a[19]; + a[18] -= xr; + a[3] = a[30] - xr; + a[30] += xr; + xr = a[18]; + a[27] -= a[11]; + a[19] -= xr; + a[18] = a[15] - xr; + a[15] += xr; + + xr = a[19]; + a[10] -= xr; + a[19] = a[14] - xr; + a[14] += xr; + xr = a[10]; + a[11] -= xr; + a[10] = a[23] - xr; + a[23] += xr; + xr = a[11]; + a[26] -= xr; + a[11] = a[22] - xr; + a[22] += xr; + xr = a[26]; + a[27] -= xr; + a[26] = a[7] - xr; + a[7] += xr; + + xr = a[27]; + a[27] = a[6] - xr; + a[6] += xr; + + xr = SQRT2 * (a[0] - a[4]); + a[0] += a[4]; + a[4] = xr; + xr = SQRT2 * (a[1] - a[5]); + a[1] += a[5]; + a[5] = xr; + xr = SQRT2 * (a[16] - a[20]); + a[16] += a[20]; + a[20] = xr; + xr = SQRT2 * (a[17] - a[21]); + a[17] += a[21]; + a[21] = xr; + + xr = -SQRT2 * (a[8] - a[12]); + a[8] += a[12]; + a[12] = xr - a[8]; + xr = -SQRT2 * (a[9] - a[13]); + a[9] += a[13]; + a[13] = xr - a[9]; + xr = -SQRT2 * (a[25] - a[29]); + a[25] += a[29]; + a[29] = xr - a[25]; + xr = -SQRT2 * (a[24] + a[28]); + a[24] -= a[28]; + a[28] = xr - a[24]; + + xr = a[24] - a[16]; + a[24] = xr; + xr = a[20] - xr; + a[20] = xr; + xr = a[28] - xr; + a[28] = xr; + + xr = a[25] - a[17]; + a[25] = xr; + xr = a[21] - xr; + a[21] = xr; + xr = a[29] - xr; + a[29] = xr; + + xr = a[17] - a[1]; + a[17] = xr; + xr = a[9] - xr; + a[9] = xr; + xr = a[25] - xr; + a[25] = xr; + xr = a[5] - xr; + a[5] = xr; + xr = a[21] - xr; + a[21] = xr; + xr = a[13] - xr; + a[13] = xr; + xr = a[29] - xr; + a[29] = xr; + + xr = a[1] - a[0]; + a[1] = xr; + xr = a[16] - xr; + a[16] = xr; + xr = a[17] - xr; + a[17] = xr; + xr = a[8] - xr; + a[8] = xr; + xr = a[9] - xr; + a[9] = xr; + xr = a[24] - xr; + a[24] = xr; + xr = a[25] - xr; + a[25] = xr; + xr = a[4] - xr; + a[4] = xr; + xr = a[5] - xr; + a[5] = xr; + xr = a[20] - xr; + a[20] = xr; + xr = a[21] - xr; + a[21] = xr; + xr = a[12] - xr; + a[12] = xr; + xr = a[13] - xr; + a[13] = xr; + xr = a[28] - xr; + a[28] = xr; + xr = a[29] - xr; + a[29] = xr; + + xr = a[0]; + a[0] += a[31]; + a[31] -= xr; + xr = a[1]; + a[1] += a[30]; + a[30] -= xr; + xr = a[16]; + a[16] += a[15]; + a[15] -= xr; + xr = a[17]; + a[17] += a[14]; + a[14] -= xr; + xr = a[8]; + a[8] += a[23]; + a[23] -= xr; + xr = a[9]; + a[9] += a[22]; + a[22] -= xr; + xr = a[24]; + a[24] += a[7]; + a[7] -= xr; + xr = a[25]; + a[25] += a[6]; + a[6] -= xr; + xr = a[4]; + a[4] += a[27]; + a[27] -= xr; + xr = a[5]; + a[5] += a[26]; + a[26] -= xr; + xr = a[20]; + a[20] += a[11]; + a[11] -= xr; + xr = a[21]; + a[21] += a[10]; + a[10] -= xr; + xr = a[12]; + a[12] += a[19]; + a[19] -= xr; + xr = a[13]; + a[13] += a[18]; + a[18] -= xr; + xr = a[28]; + a[28] += a[3]; + a[3] -= xr; + xr = a[29]; + a[29] += a[2]; + a[2] -= xr; + } + +} + + +/*-------------------------------------------------------------------*/ +/* */ +/* Function: Calculation of the MDCT */ +/* In the case of long blocks (type 0,1,3) there are */ +/* 36 coefficents in the time domain and 18 in the frequency */ +/* domain. */ +/* In the case of short blocks (type 2) there are 3 */ +/* transformations with short length. This leads to 12 coefficents */ +/* in the time and 6 in the frequency domain. In this case the */ +/* results are stored side by side in the vector out[]. */ +/* */ +/* New layer3 */ +/* */ +/*-------------------------------------------------------------------*/ + +inline static void +mdct_short(FLOAT * inout) +{ + int l; + for (l = 0; l < 3; l++) { + FLOAT tc0, tc1, tc2, ts0, ts1, ts2; + + ts0 = inout[2 * 3] * win[SHORT_TYPE][0] - inout[5 * 3]; + tc0 = inout[0 * 3] * win[SHORT_TYPE][2] - inout[3 * 3]; + tc1 = ts0 + tc0; + tc2 = ts0 - tc0; + + ts0 = inout[5 * 3] * win[SHORT_TYPE][0] + inout[2 * 3]; + tc0 = inout[3 * 3] * win[SHORT_TYPE][2] + inout[0 * 3]; + ts1 = ts0 + tc0; + ts2 = -ts0 + tc0; + + tc0 = (inout[1 * 3] * win[SHORT_TYPE][1] - inout[4 * 3]) * 2.069978111953089e-11; /* tritab_s[1] */ + ts0 = (inout[4 * 3] * win[SHORT_TYPE][1] + inout[1 * 3]) * 2.069978111953089e-11; /* tritab_s[1] */ + + inout[3 * 0] = tc1 * 1.907525191737280e-11 /* tritab_s[2] */ + tc0; + inout[3 * 5] = -ts1 * 1.907525191737280e-11 /* tritab_s[0] */ + ts0; + + tc2 = tc2 * 0.86602540378443870761 * 1.907525191737281e-11 /* tritab_s[2] */ ; + ts1 = ts1 * 0.5 * 1.907525191737281e-11 + ts0; + inout[3 * 1] = tc2 - ts1; + inout[3 * 2] = tc2 + ts1; + + tc1 = tc1 * 0.5 * 1.907525191737281e-11 - tc0; + ts2 = ts2 * 0.86602540378443870761 * 1.907525191737281e-11 /* tritab_s[0] */ ; + inout[3 * 3] = tc1 + ts2; + inout[3 * 4] = tc1 - ts2; + + inout++; + } +} + +inline static void +mdct_long(FLOAT * out, FLOAT const *in) +{ + FLOAT ct, st; + { + FLOAT tc1, tc2, tc3, tc4, ts5, ts6, ts7, ts8; + /* 1,2, 5,6, 9,10, 13,14, 17 */ + tc1 = in[17] - in[9]; + tc3 = in[15] - in[11]; + tc4 = in[14] - in[12]; + ts5 = in[0] + in[8]; + ts6 = in[1] + in[7]; + ts7 = in[2] + in[6]; + ts8 = in[3] + in[5]; + + out[17] = (ts5 + ts7 - ts8) - (ts6 - in[4]); + st = (ts5 + ts7 - ts8) * cx[7] + (ts6 - in[4]); + ct = (tc1 - tc3 - tc4) * cx[6]; + out[5] = ct + st; + out[6] = ct - st; + + tc2 = (in[16] - in[10]) * cx[6]; + ts6 = ts6 * cx[7] + in[4]; + ct = tc1 * cx[0] + tc2 + tc3 * cx[1] + tc4 * cx[2]; + st = -ts5 * cx[4] + ts6 - ts7 * cx[5] + ts8 * cx[3]; + out[1] = ct + st; + out[2] = ct - st; + + ct = tc1 * cx[1] - tc2 - tc3 * cx[2] + tc4 * cx[0]; + st = -ts5 * cx[5] + ts6 - ts7 * cx[3] + ts8 * cx[4]; + out[9] = ct + st; + out[10] = ct - st; + + ct = tc1 * cx[2] - tc2 + tc3 * cx[0] - tc4 * cx[1]; + st = ts5 * cx[3] - ts6 + ts7 * cx[4] - ts8 * cx[5]; + out[13] = ct + st; + out[14] = ct - st; + } + { + FLOAT ts1, ts2, ts3, ts4, tc5, tc6, tc7, tc8; + + ts1 = in[8] - in[0]; + ts3 = in[6] - in[2]; + ts4 = in[5] - in[3]; + tc5 = in[17] + in[9]; + tc6 = in[16] + in[10]; + tc7 = in[15] + in[11]; + tc8 = in[14] + in[12]; + + out[0] = (tc5 + tc7 + tc8) + (tc6 + in[13]); + ct = (tc5 + tc7 + tc8) * cx[7] - (tc6 + in[13]); + st = (ts1 - ts3 + ts4) * cx[6]; + out[11] = ct + st; + out[12] = ct - st; + + ts2 = (in[7] - in[1]) * cx[6]; + tc6 = in[13] - tc6 * cx[7]; + ct = tc5 * cx[3] - tc6 + tc7 * cx[4] + tc8 * cx[5]; + st = ts1 * cx[2] + ts2 + ts3 * cx[0] + ts4 * cx[1]; + out[3] = ct + st; + out[4] = ct - st; + + ct = -tc5 * cx[5] + tc6 - tc7 * cx[3] - tc8 * cx[4]; + st = ts1 * cx[1] + ts2 - ts3 * cx[2] - ts4 * cx[0]; + out[7] = ct + st; + out[8] = ct - st; + + ct = -tc5 * cx[4] + tc6 - tc7 * cx[5] - tc8 * cx[3]; + st = ts1 * cx[0] - ts2 + ts3 * cx[1] - ts4 * cx[2]; + out[15] = ct + st; + out[16] = ct - st; + } +} + + +void +mdct_sub48(lame_internal_flags * gfc, const sample_t * w0, const sample_t * w1) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncStateVar_t *const esv = &gfc->sv_enc; + int gr, k, ch; + const sample_t *wk; + + wk = w0 + 286; + /* thinking cache performance, ch->gr loop is better than gr->ch loop */ + for (ch = 0; ch < cfg->channels_out; ch++) { + for (gr = 0; gr < cfg->mode_gr; gr++) { + int band; + gr_info *const gi = &(gfc->l3_side.tt[gr][ch]); + FLOAT *mdct_enc = gi->xr; + FLOAT *samp = esv->sb_sample[ch][1 - gr][0]; + + for (k = 0; k < 18 / 2; k++) { + window_subband(wk, samp); + window_subband(wk + 32, samp + 32); + samp += 64; + wk += 64; + /* + * Compensate for inversion in the analysis filter + */ + for (band = 1; band < 32; band += 2) { + samp[band - 32] *= -1; + } + } + + /* + * Perform imdct of 18 previous subband samples + * + 18 current subband samples + */ + for (band = 0; band < 32; band++, mdct_enc += 18) { + int type = gi->block_type; + FLOAT const *const band0 = esv->sb_sample[ch][gr][0] + order[band]; + FLOAT *const band1 = esv->sb_sample[ch][1 - gr][0] + order[band]; + if (gi->mixed_block_flag && band < 2) + type = 0; + if (esv->amp_filter[band] < 1e-12) { + memset(mdct_enc, 0, 18 * sizeof(FLOAT)); + } + else { + if (esv->amp_filter[band] < 1.0) { + for (k = 0; k < 18; k++) + band1[k * 32] *= esv->amp_filter[band]; + } + if (type == SHORT_TYPE) { + for (k = -NS / 4; k < 0; k++) { + FLOAT const w = win[SHORT_TYPE][k + 3]; + mdct_enc[k * 3 + 9] = band0[(9 + k) * 32] * w - band0[(8 - k) * 32]; + mdct_enc[k * 3 + 18] = band0[(14 - k) * 32] * w + band0[(15 + k) * 32]; + mdct_enc[k * 3 + 10] = band0[(15 + k) * 32] * w - band0[(14 - k) * 32]; + mdct_enc[k * 3 + 19] = band1[(2 - k) * 32] * w + band1[(3 + k) * 32]; + mdct_enc[k * 3 + 11] = band1[(3 + k) * 32] * w - band1[(2 - k) * 32]; + mdct_enc[k * 3 + 20] = band1[(8 - k) * 32] * w + band1[(9 + k) * 32]; + } + mdct_short(mdct_enc); + } + else { + FLOAT work[18]; + for (k = -NL / 4; k < 0; k++) { + FLOAT a, b; + a = win[type][k + 27] * band1[(k + 9) * 32] + + win[type][k + 36] * band1[(8 - k) * 32]; + b = win[type][k + 9] * band0[(k + 9) * 32] + - win[type][k + 18] * band0[(8 - k) * 32]; + work[k + 9] = a - b * tantab_l[k + 9]; + work[k + 18] = a * tantab_l[k + 9] + b; + } + + mdct_long(mdct_enc, work); + } + } + /* + * Perform aliasing reduction butterfly + */ + if (type != SHORT_TYPE && band != 0) { + for (k = 7; k >= 0; --k) { + FLOAT bu, bd; + bu = mdct_enc[k] * ca[k] + mdct_enc[-1 - k] * cs[k]; + bd = mdct_enc[k] * cs[k] - mdct_enc[-1 - k] * ca[k]; + + mdct_enc[-1 - k] = bu; + mdct_enc[k] = bd; + } + } + } + } + wk = w1 + 286; + if (cfg->mode_gr == 1) { + memcpy(esv->sb_sample[ch][0], esv->sb_sample[ch][1], 576 * sizeof(FLOAT)); + } + } +} diff --git a/pkg/lame/clame/newmdct.h b/pkg/lame/clame/newmdct.h new file mode 100644 index 0000000..0b58a95 --- /dev/null +++ b/pkg/lame/clame/newmdct.h @@ -0,0 +1,27 @@ +/* + * New Modified DCT include file + * + * Copyright (c) 1999 Takehiro TOMINAGA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef LAME_NEWMDCT_H +#define LAME_NEWMDCT_H + +void mdct_sub48(lame_internal_flags * gfc, const sample_t * w0, const sample_t * w1); + +#endif /* LAME_NEWMDCT_H */ diff --git a/pkg/lame/clame/presets.c b/pkg/lame/clame/presets.c new file mode 100644 index 0000000..93594f5 --- /dev/null +++ b/pkg/lame/clame/presets.c @@ -0,0 +1,404 @@ +/* + * presets.c -- Apply presets + * + * Copyright (c) 2002-2008 Gabriel Bouvigne + * Copyright (c) 2007-2012 Robert Hegemann + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ + + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "lame.h" +#include "machine.h" +#include "set_get.h" +#include "encoder.h" +#include "util.h" +#include "lame_global_flags.h" + +#define SET_OPTION(opt, val, def) if (enforce) \ + (void) lame_set_##opt(gfp, val); \ + else if (!(fabs(lame_get_##opt(gfp) - def) > 0)) \ + (void) lame_set_##opt(gfp, val); + +#define SET__OPTION(opt, val, def) if (enforce) \ + lame_set_##opt(gfp, val); \ + else if (!(fabs(lame_get_##opt(gfp) - def) > 0)) \ + lame_set_##opt(gfp, val); + +#undef Min +#undef Max + +static inline int +min_int(int a, int b) +{ + if (a < b) { + return a; + } + return b; +} + +static inline int +max_int(int a, int b) +{ + if (a > b) { + return a; + } + return b; +} + + + +typedef struct { + int vbr_q; + int quant_comp; + int quant_comp_s; + int expY; + FLOAT st_lrm; /*short threshold */ + FLOAT st_s; + FLOAT masking_adj; + FLOAT masking_adj_short; + FLOAT ath_lower; + FLOAT ath_curve; + FLOAT ath_sensitivity; + FLOAT interch; + int safejoint; + int sfb21mod; + FLOAT msfix; + FLOAT minval; + FLOAT ath_fixpoint; +} vbr_presets_t; + + /* *INDENT-OFF* */ + + /* Switch mappings for VBR mode VBR_RH */ + static const vbr_presets_t vbr_old_switch_map[] = { + /*vbr_q qcomp_l qcomp_s expY st_lrm st_s mask adj_l adj_s ath_lower ath_curve ath_sens interChR safejoint sfb21mod msfix */ + {0, 9, 9, 0, 5.20, 125.0, -4.2, -6.3, 4.8, 1, 0, 0, 2, 21, 0.97, 5, 100}, + {1, 9, 9, 0, 5.30, 125.0, -3.6, -5.6, 4.5, 1.5, 0, 0, 2, 21, 1.35, 5, 100}, + {2, 9, 9, 0, 5.60, 125.0, -2.2, -3.5, 2.8, 2, 0, 0, 2, 21, 1.49, 5, 100}, + {3, 9, 9, 1, 5.80, 130.0, -1.8, -2.8, 2.6, 3, -4, 0, 2, 20, 1.64, 5, 100}, + {4, 9, 9, 1, 6.00, 135.0, -0.7, -1.1, 1.1, 3.5, -8, 0, 2, 0, 1.79, 5, 100}, + {5, 9, 9, 1, 6.40, 140.0, 0.5, 0.4, -7.5, 4, -12, 0.0002, 0, 0, 1.95, 5, 100}, + {6, 9, 9, 1, 6.60, 145.0, 0.67, 0.65, -14.7, 6.5, -19, 0.0004, 0, 0, 2.30, 5, 100}, + {7, 9, 9, 1, 6.60, 145.0, 0.8, 0.75, -19.7, 8, -22, 0.0006, 0, 0, 2.70, 5, 100}, + {8, 9, 9, 1, 6.60, 145.0, 1.2, 1.15, -27.5, 10, -23, 0.0007, 0, 0, 0, 5, 100}, + {9, 9, 9, 1, 6.60, 145.0, 1.6, 1.6, -36, 11, -25, 0.0008, 0, 0, 0, 5, 100}, + {10, 9, 9, 1, 6.60, 145.0, 2.0, 2.0, -36, 12, -25, 0.0008, 0, 0, 0, 5, 100} + }; + + static const vbr_presets_t vbr_mt_psy_switch_map[] = { + /*vbr_q qcomp_l qcomp_s expY st_lrm st_s mask adj_l adj_s ath_lower ath_curve ath_sens --- safejoint sfb21mod msfix */ + {0, 9, 9, 0, 4.20, 25.0, -6.8, -6.8, 7.1, 1, 0, 0, 2, 31, 1.000, 5, 100}, + {1, 9, 9, 0, 4.20, 25.0, -4.8, -4.8, 5.4, 1.4, -1, 0, 2, 27, 1.122, 5, 98}, + {2, 9, 9, 0, 4.20, 25.0, -2.6, -2.6, 3.7, 2.0, -3, 0, 2, 23, 1.288, 5, 97}, + {3, 9, 9, 1, 4.20, 25.0, -1.6, -1.6, 2.0, 2.0, -5, 0, 2, 18, 1.479, 5, 96}, + {4, 9, 9, 1, 4.20, 25.0, -0.0, -0.0, 0.0, 2.0, -8, 0, 2, 12, 1.698, 5, 95}, + {5, 9, 9, 1, 4.20, 25.0, 1.3, 1.3, -6, 3.5, -11, 0, 2, 8, 1.950, 5, 94.2}, +#if 0 + {6, 9, 9, 1, 4.50, 100.0, 1.5, 1.5, -24.0, 6.0, -14, 0, 2, 4, 2.239, 3, 93.9}, + {7, 9, 9, 1, 4.80, 200.0, 1.7, 1.7, -28.0, 9.0, -20, 0, 2, 0, 2.570, 1, 93.6}, +#else + {6, 9, 9, 1, 4.50, 100.0, 2.2, 2.3, -12.0, 6.0, -14, 0, 2, 4, 2.239, 3, 93.9}, + {7, 9, 9, 1, 4.80, 200.0, 2.7, 2.7, -18.0, 9.0, -17, 0, 2, 0, 2.570, 1, 93.6}, +#endif + {8, 9, 9, 1, 5.30, 300.0, 2.8, 2.8, -21.0, 10.0, -23, 0.0002, 0, 0, 2.951, 0, 93.3}, + {9, 9, 9, 1, 6.60, 300.0, 2.8, 2.8, -23.0, 11.0, -25, 0.0006, 0, 0, 3.388, 0, 93.3}, + {10, 9, 9, 1, 25.00, 300.0, 2.8, 2.8, -25.0, 12.0, -27, 0.0025, 0, 0, 3.500, 0, 93.3} + }; + + /* *INDENT-ON* */ + +static vbr_presets_t const* +get_vbr_preset(int v) +{ + switch (v) { + case vbr_mtrh: + case vbr_mt: + return &vbr_mt_psy_switch_map[0]; + default: + return &vbr_old_switch_map[0]; + } +} + +#define NOOP(m) (void)p.m +#define LERP(m) (p.m = p.m + x * (q.m - p.m)) + +static void +apply_vbr_preset(lame_global_flags * gfp, int a, int enforce) +{ + vbr_presets_t const *vbr_preset = get_vbr_preset(lame_get_VBR(gfp)); + float x = gfp->VBR_q_frac; + vbr_presets_t p = vbr_preset[a]; + vbr_presets_t q = vbr_preset[a + 1]; + vbr_presets_t const *set = &p; + + NOOP(vbr_q); + NOOP(quant_comp); + NOOP(quant_comp_s); + NOOP(expY); + LERP(st_lrm); + LERP(st_s); + LERP(masking_adj); + LERP(masking_adj_short); + LERP(ath_lower); + LERP(ath_curve); + LERP(ath_sensitivity); + LERP(interch); + NOOP(safejoint); + LERP(sfb21mod); + LERP(msfix); + LERP(minval); + LERP(ath_fixpoint); + + (void) lame_set_VBR_q(gfp, set->vbr_q); + SET_OPTION(quant_comp, set->quant_comp, -1); + SET_OPTION(quant_comp_short, set->quant_comp_s, -1); + if (set->expY) { + (void) lame_set_experimentalY(gfp, set->expY); + } + SET_OPTION(short_threshold_lrm, set->st_lrm, -1); + SET_OPTION(short_threshold_s, set->st_s, -1); + SET_OPTION(maskingadjust, set->masking_adj, 0); + SET_OPTION(maskingadjust_short, set->masking_adj_short, 0); + if (lame_get_VBR(gfp) == vbr_mt || lame_get_VBR(gfp) == vbr_mtrh) { + lame_set_ATHtype(gfp, 5); + } + SET_OPTION(ATHlower, set->ath_lower, 0); + SET_OPTION(ATHcurve, set->ath_curve, -1); + SET_OPTION(athaa_sensitivity, set->ath_sensitivity, 0); + if (set->interch > 0) { + SET_OPTION(interChRatio, set->interch, -1); + } + + /* parameters for which there is no proper set/get interface */ + if (set->safejoint > 0) { + (void) lame_set_exp_nspsytune(gfp, lame_get_exp_nspsytune(gfp) | 2); + } + if (set->sfb21mod > 0) { + int const nsp = lame_get_exp_nspsytune(gfp); + int const val = (nsp >> 20) & 63; + if (val == 0) { + int const sf21mod = (set->sfb21mod << 20) | nsp; + (void) lame_set_exp_nspsytune(gfp, sf21mod); + } + } + SET__OPTION(msfix, set->msfix, -1); + + if (enforce == 0) { + gfp->VBR_q = a; + gfp->VBR_q_frac = x; + } + gfp->internal_flags->cfg.minval = set->minval; + { /* take care of gain adjustments */ + double const x = fabs(gfp->scale); + double const y = (x > 0.f) ? (10.f * log10(x)) : 0.f; + gfp->internal_flags->cfg.ATHfixpoint = set->ath_fixpoint - y; + } +} + +static int +apply_abr_preset(lame_global_flags * gfp, int preset, int enforce) +{ + typedef struct { + int abr_kbps; + int quant_comp; + int quant_comp_s; + int safejoint; + FLOAT nsmsfix; + FLOAT st_lrm; /*short threshold */ + FLOAT st_s; + FLOAT scale; + FLOAT masking_adj; + FLOAT ath_lower; + FLOAT ath_curve; + FLOAT interch; + int sfscale; + } abr_presets_t; + + + /* *INDENT-OFF* */ + + /* + * Switch mappings for ABR mode + */ + const abr_presets_t abr_switch_map[] = { + /* kbps quant q_s safejoint nsmsfix st_lrm st_s scale msk ath_lwr ath_curve interch , sfscale */ + { 8, 9, 9, 0, 0, 6.60, 145, 0.95, 0, -30.0, 11, 0.0012, 1}, /* 8, impossible to use in stereo */ + { 16, 9, 9, 0, 0, 6.60, 145, 0.95, 0, -25.0, 11, 0.0010, 1}, /* 16 */ + { 24, 9, 9, 0, 0, 6.60, 145, 0.95, 0, -20.0, 11, 0.0010, 1}, /* 24 */ + { 32, 9, 9, 0, 0, 6.60, 145, 0.95, 0, -15.0, 11, 0.0010, 1}, /* 32 */ + { 40, 9, 9, 0, 0, 6.60, 145, 0.95, 0, -10.0, 11, 0.0009, 1}, /* 40 */ + { 48, 9, 9, 0, 0, 6.60, 145, 0.95, 0, -10.0, 11, 0.0009, 1}, /* 48 */ + { 56, 9, 9, 0, 0, 6.60, 145, 0.95, 0, -6.0, 11, 0.0008, 1}, /* 56 */ + { 64, 9, 9, 0, 0, 6.60, 145, 0.95, 0, -2.0, 11, 0.0008, 1}, /* 64 */ + { 80, 9, 9, 0, 0, 6.60, 145, 0.95, 0, .0, 8, 0.0007, 1}, /* 80 */ + { 96, 9, 9, 0, 2.50, 6.60, 145, 0.95, 0, 1.0, 5.5, 0.0006, 1}, /* 96 */ + {112, 9, 9, 0, 2.25, 6.60, 145, 0.95, 0, 2.0, 4.5, 0.0005, 1}, /* 112 */ + {128, 9, 9, 0, 1.95, 6.40, 140, 0.95, 0, 3.0, 4, 0.0002, 1}, /* 128 */ + {160, 9, 9, 1, 1.79, 6.00, 135, 0.95, -2, 5.0, 3.5, 0, 1}, /* 160 */ + {192, 9, 9, 1, 1.49, 5.60, 125, 0.97, -4, 7.0, 3, 0, 0}, /* 192 */ + {224, 9, 9, 1, 1.25, 5.20, 125, 0.98, -6, 9.0, 2, 0, 0}, /* 224 */ + {256, 9, 9, 1, 0.97, 5.20, 125, 1.00, -8, 10.0, 1, 0, 0}, /* 256 */ + {320, 9, 9, 1, 0.90, 5.20, 125, 1.00, -10, 12.0, 0, 0, 0} /* 320 */ + }; + + /* *INDENT-ON* */ + + /* Variables for the ABR stuff */ + int r; + int actual_bitrate = preset; + + r = nearestBitrateFullIndex(preset); + + (void) lame_set_VBR(gfp, vbr_abr); + (void) lame_set_VBR_mean_bitrate_kbps(gfp, (actual_bitrate)); + (void) lame_set_VBR_mean_bitrate_kbps(gfp, min_int(lame_get_VBR_mean_bitrate_kbps(gfp), 320)); + (void) lame_set_VBR_mean_bitrate_kbps(gfp, max_int(lame_get_VBR_mean_bitrate_kbps(gfp), 8)); + (void) lame_set_brate(gfp, lame_get_VBR_mean_bitrate_kbps(gfp)); + + + /* parameters for which there is no proper set/get interface */ + if (abr_switch_map[r].safejoint > 0) + (void) lame_set_exp_nspsytune(gfp, lame_get_exp_nspsytune(gfp) | 2); /* safejoint */ + + if (abr_switch_map[r].sfscale > 0) + (void) lame_set_sfscale(gfp, 1); + + + SET_OPTION(quant_comp, abr_switch_map[r].quant_comp, -1); + SET_OPTION(quant_comp_short, abr_switch_map[r].quant_comp_s, -1); + + SET__OPTION(msfix, abr_switch_map[r].nsmsfix, -1); + + SET_OPTION(short_threshold_lrm, abr_switch_map[r].st_lrm, -1); + SET_OPTION(short_threshold_s, abr_switch_map[r].st_s, -1); + + /* ABR seems to have big problems with clipping, especially at low bitrates */ + /* so we compensate for that here by using a scale value depending on bitrate */ + lame_set_scale(gfp, lame_get_scale(gfp) * abr_switch_map[r].scale); + + SET_OPTION(maskingadjust, abr_switch_map[r].masking_adj, 0); + if (abr_switch_map[r].masking_adj > 0) { + SET_OPTION(maskingadjust_short, abr_switch_map[r].masking_adj * .9, 0); + } + else { + SET_OPTION(maskingadjust_short, abr_switch_map[r].masking_adj * 1.1, 0); + } + + + SET_OPTION(ATHlower, abr_switch_map[r].ath_lower, 0); + SET_OPTION(ATHcurve, abr_switch_map[r].ath_curve, -1); + + SET_OPTION(interChRatio, abr_switch_map[r].interch, -1); + + (void) abr_switch_map[r].abr_kbps; + + gfp->internal_flags->cfg.minval = 5. * (abr_switch_map[r].abr_kbps / 320.); + + return preset; +} + + + +int +apply_preset(lame_global_flags * gfp, int preset, int enforce) +{ + /*translate legacy presets */ + switch (preset) { + case R3MIX: + { + preset = V3; + (void) lame_set_VBR(gfp, vbr_mtrh); + break; + } + case MEDIUM: + case MEDIUM_FAST: + { + preset = V4; + (void) lame_set_VBR(gfp, vbr_mtrh); + break; + } + case STANDARD: + case STANDARD_FAST: + { + preset = V2; + (void) lame_set_VBR(gfp, vbr_mtrh); + break; + } + case EXTREME: + case EXTREME_FAST: + { + preset = V0; + (void) lame_set_VBR(gfp, vbr_mtrh); + break; + } + case INSANE: + { + preset = 320; + gfp->preset = preset; + (void) apply_abr_preset(gfp, preset, enforce); + lame_set_VBR(gfp, vbr_off); + return preset; + } + } + + gfp->preset = preset; + { + switch (preset) { + case V9: + apply_vbr_preset(gfp, 9, enforce); + return preset; + case V8: + apply_vbr_preset(gfp, 8, enforce); + return preset; + case V7: + apply_vbr_preset(gfp, 7, enforce); + return preset; + case V6: + apply_vbr_preset(gfp, 6, enforce); + return preset; + case V5: + apply_vbr_preset(gfp, 5, enforce); + return preset; + case V4: + apply_vbr_preset(gfp, 4, enforce); + return preset; + case V3: + apply_vbr_preset(gfp, 3, enforce); + return preset; + case V2: + apply_vbr_preset(gfp, 2, enforce); + return preset; + case V1: + apply_vbr_preset(gfp, 1, enforce); + return preset; + case V0: + apply_vbr_preset(gfp, 0, enforce); + return preset; + default: + break; + } + } + if (8 <= preset && preset <= 320) { + return apply_abr_preset(gfp, preset, enforce); + } + + gfp->preset = 0; /*no corresponding preset found */ + return preset; +} diff --git a/pkg/lame/clame/psymodel.c b/pkg/lame/clame/psymodel.c new file mode 100644 index 0000000..60076ee --- /dev/null +++ b/pkg/lame/clame/psymodel.c @@ -0,0 +1,2167 @@ +/* + * psymodel.c + * + * Copyright (c) 1999-2000 Mark Taylor + * Copyright (c) 2001-2002 Naoki Shibata + * Copyright (c) 2000-2003 Takehiro Tominaga + * Copyright (c) 2000-2012 Robert Hegemann + * Copyright (c) 2000-2005 Gabriel Bouvigne + * Copyright (c) 2000-2005 Alexander Leidinger + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* $Id: psymodel.c,v 1.216 2017/09/06 19:38:23 aleidinger Exp $ */ + + +/* +PSYCHO ACOUSTICS + + +This routine computes the psycho acoustics, delayed by one granule. + +Input: buffer of PCM data (1024 samples). + +This window should be centered over the 576 sample granule window. +The routine will compute the psycho acoustics for +this granule, but return the psycho acoustics computed +for the *previous* granule. This is because the block +type of the previous granule can only be determined +after we have computed the psycho acoustics for the following +granule. + +Output: maskings and energies for each scalefactor band. +block type, PE, and some correlation measures. +The PE is used by CBR modes to determine if extra bits +from the bit reservoir should be used. The correlation +measures are used to determine mid/side or regular stereo. +*/ +/* +Notation: + +barks: a non-linear frequency scale. Mapping from frequency to + barks is given by freq2bark() + +scalefactor bands: The spectrum (frequencies) are broken into + SBMAX "scalefactor bands". Thes bands + are determined by the MPEG ISO spec. In + the noise shaping/quantization code, we allocate + bits among the partition bands to achieve the + best possible quality + +partition bands: The spectrum is also broken into about + 64 "partition bands". Each partition + band is about .34 barks wide. There are about 2-5 + partition bands for each scalefactor band. + +LAME computes all psycho acoustic information for each partition +band. Then at the end of the computations, this information +is mapped to scalefactor bands. The energy in each scalefactor +band is taken as the sum of the energy in all partition bands +which overlap the scalefactor band. The maskings can be computed +in the same way (and thus represent the average masking in that band) +or by taking the minmum value multiplied by the number of +partition bands used (which represents a minimum masking in that band). +*/ +/* +The general outline is as follows: + +1. compute the energy in each partition band +2. compute the tonality in each partition band +3. compute the strength of each partion band "masker" +4. compute the masking (via the spreading function applied to each masker) +5. Modifications for mid/side masking. + +Each partition band is considiered a "masker". The strength +of the i'th masker in band j is given by: + + s3(bark(i)-bark(j))*strength(i) + +The strength of the masker is a function of the energy and tonality. +The more tonal, the less masking. LAME uses a simple linear formula +(controlled by NMT and TMN) which says the strength is given by the +energy divided by a linear function of the tonality. +*/ +/* +s3() is the "spreading function". It is given by a formula +determined via listening tests. + +The total masking in the j'th partition band is the sum over +all maskings i. It is thus given by the convolution of +the strength with s3(), the "spreading function." + +masking(j) = sum_over_i s3(i-j)*strength(i) = s3 o strength + +where "o" = convolution operator. s3 is given by a formula determined +via listening tests. It is normalized so that s3 o 1 = 1. + +Note: instead of a simple convolution, LAME also has the +option of using "additive masking" + +The most critical part is step 2, computing the tonality of each +partition band. LAME has two tonality estimators. The first +is based on the ISO spec, and measures how predictiable the +signal is over time. The more predictable, the more tonal. +The second measure is based on looking at the spectrum of +a single granule. The more peaky the spectrum, the more +tonal. By most indications, the latter approach is better. + +Finally, in step 5, the maskings for the mid and side +channel are possibly increased. Under certain circumstances, +noise in the mid & side channels is assumed to also +be masked by strong maskers in the L or R channels. + + +Other data computed by the psy-model: + +ms_ratio side-channel / mid-channel masking ratio (for previous granule) +ms_ratio_next side-channel / mid-channel masking ratio for this granule + +percep_entropy[2] L and R values (prev granule) of PE - A measure of how + much pre-echo is in the previous granule +percep_entropy_MS[2] mid and side channel values (prev granule) of percep_entropy +energy[4] L,R,M,S energy in each channel, prev granule +blocktype_d[2] block type to use for previous granule +*/ + + + + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "lame.h" +#include "machine.h" +#include "encoder.h" +#include "util.h" +#include "psymodel.h" +#include "lame_global_flags.h" +#include "fft.h" +#include "lame-analysis.h" + + +#define NSFIRLEN 21 + +#ifdef M_LN10 +#define LN_TO_LOG10 (M_LN10/10) +#else +#define LN_TO_LOG10 0.2302585093 +#endif + + +/* + L3psycho_anal. Compute psycho acoustics. + + Data returned to the calling program must be delayed by one + granule. + + This is done in two places. + If we do not need to know the blocktype, the copying + can be done here at the top of the program: we copy the data for + the last granule (computed during the last call) before it is + overwritten with the new data. It looks like this: + + 0. static psymodel_data + 1. calling_program_data = psymodel_data + 2. compute psymodel_data + + For data which needs to know the blocktype, the copying must be + done at the end of this loop, and the old values must be saved: + + 0. static psymodel_data_old + 1. compute psymodel_data + 2. compute possible block type of this granule + 3. compute final block type of previous granule based on #2. + 4. calling_program_data = psymodel_data_old + 5. psymodel_data_old = psymodel_data +*/ + + + + + +/* psycho_loudness_approx + jd - 2001 mar 12 +in: energy - BLKSIZE/2 elements of frequency magnitudes ^ 2 + gfp - uses out_samplerate, ATHtype (also needed for ATHformula) +returns: loudness^2 approximation, a positive value roughly tuned for a value + of 1.0 for signals near clipping. +notes: When calibrated, feeding this function binary white noise at sample + values +32767 or -32768 should return values that approach 3. + ATHformula is used to approximate an equal loudness curve. +future: Data indicates that the shape of the equal loudness curve varies + with intensity. This function might be improved by using an equal + loudness curve shaped for typical playback levels (instead of the + ATH, that is shaped for the threshold). A flexible realization might + simply bend the existing ATH curve to achieve the desired shape. + However, the potential gain may not be enough to justify an effort. +*/ +static FLOAT +psycho_loudness_approx(FLOAT const *energy, FLOAT const *eql_w) +{ + int i; + FLOAT loudness_power; + + loudness_power = 0.0; + /* apply weights to power in freq. bands */ + for (i = 0; i < BLKSIZE / 2; ++i) + loudness_power += energy[i] * eql_w[i]; + loudness_power *= VO_SCALE; + + return loudness_power; +} + +/* mask_add optimization */ +/* init the limit values used to avoid computing log in mask_add when it is not necessary */ + +/* For example, with i = 10*log10(m2/m1)/10*16 (= log10(m2/m1)*16) + * + * abs(i)>8 is equivalent (as i is an integer) to + * abs(i)>=9 + * i>=9 || i<=-9 + * equivalent to (as i is the biggest integer smaller than log10(m2/m1)*16 + * or the smallest integer bigger than log10(m2/m1)*16 depending on the sign of log10(m2/m1)*16) + * log10(m2/m1)>=9/16 || log10(m2/m1)<=-9/16 + * exp10 is strictly increasing thus this is equivalent to + * m2/m1 >= 10^(9/16) || m2/m1<=10^(-9/16) which are comparisons to constants + */ + + +#define I1LIMIT 8 /* as in if(i>8) */ +#define I2LIMIT 23 /* as in if(i>24) -> changed 23 */ +#define MLIMIT 15 /* as in if(m<15) */ + +/* pow(10, (I1LIMIT + 1) / 16.0); */ +static const FLOAT ma_max_i1 = 3.6517412725483771; +/* pow(10, (I2LIMIT + 1) / 16.0); */ +static const FLOAT ma_max_i2 = 31.622776601683793; +/* pow(10, (MLIMIT) / 10.0); */ +static const FLOAT ma_max_m = 31.622776601683793; + + /*This is the masking table: + According to tonality, values are going from 0dB (TMN) + to 9.3dB (NMT). + After additive masking computation, 8dB are added, so + final values are going from 8dB to 17.3dB + */ +static const FLOAT tab[] = { + 1.0 /*pow(10, -0) */ , + 0.79433 /*pow(10, -0.1) */ , + 0.63096 /*pow(10, -0.2) */ , + 0.63096 /*pow(10, -0.2) */ , + 0.63096 /*pow(10, -0.2) */ , + 0.63096 /*pow(10, -0.2) */ , + 0.63096 /*pow(10, -0.2) */ , + 0.25119 /*pow(10, -0.6) */ , + 0.11749 /*pow(10, -0.93) */ +}; + +static const int tab_mask_add_delta[] = { 2, 2, 2, 1, 1, 1, 0, 0, -1 }; +#define STATIC_ASSERT_EQUAL_DIMENSION(A,B) enum{static_assert_##A=1/((dimension_of(A) == dimension_of(B))?1:0)} + +inline static int +mask_add_delta(int i) +{ + STATIC_ASSERT_EQUAL_DIMENSION(tab_mask_add_delta,tab); + assert(i < (int)dimension_of(tab)); + return tab_mask_add_delta[i]; +} + + +static void +init_mask_add_max_values(void) +{ +#ifndef NDEBUG + FLOAT const _ma_max_i1 = pow(10, (I1LIMIT + 1) / 16.0); + FLOAT const _ma_max_i2 = pow(10, (I2LIMIT + 1) / 16.0); + FLOAT const _ma_max_m = pow(10, (MLIMIT) / 10.0); + assert(fabs(ma_max_i1 - _ma_max_i1) <= FLT_EPSILON); + assert(fabs(ma_max_i2 - _ma_max_i2) <= FLT_EPSILON); + assert(fabs(ma_max_m - _ma_max_m ) <= FLT_EPSILON); +#endif +} + + + + +/* addition of simultaneous masking Naoki Shibata 2000/7 */ +inline static FLOAT +vbrpsy_mask_add(FLOAT m1, FLOAT m2, int b, int delta) +{ + static const FLOAT table2[] = { + 1.33352 * 1.33352, 1.35879 * 1.35879, 1.38454 * 1.38454, 1.39497 * 1.39497, + 1.40548 * 1.40548, 1.3537 * 1.3537, 1.30382 * 1.30382, 1.22321 * 1.22321, + 1.14758 * 1.14758, + 1 + }; + + FLOAT ratio; + + if (m1 < 0) { + m1 = 0; + } + if (m2 < 0) { + m2 = 0; + } + if (m1 <= 0) { + return m2; + } + if (m2 <= 0) { + return m1; + } + if (m2 > m1) { + ratio = m2 / m1; + } + else { + ratio = m1 / m2; + } + if (abs(b) <= delta) { /* approximately, 1 bark = 3 partitions */ + /* originally 'if(i > 8)' */ + if (ratio >= ma_max_i1) { + return m1 + m2; + } + else { + int i = (int) (FAST_LOG10_X(ratio, 16.0f)); + return (m1 + m2) * table2[i]; + } + } + if (ratio < ma_max_i2) { + return m1 + m2; + } + if (m1 < m2) { + m1 = m2; + } + return m1; +} + + +/* short block threshold calculation (part 2) + + partition band bo_s[sfb] is at the transition from scalefactor + band sfb to the next one sfb+1; enn and thmm have to be split + between them +*/ +static void +convert_partition2scalefac(PsyConst_CB2SB_t const *const gd, FLOAT const *eb, FLOAT const *thr, + FLOAT enn_out[], FLOAT thm_out[]) +{ + FLOAT enn, thmm; + int sb, b, n = gd->n_sb; + enn = thmm = 0.0f; + for (sb = b = 0; sb < n; ++b, ++sb) { + int const bo_sb = gd->bo[sb]; + int const npart = gd->npart; + int const b_lim = bo_sb < npart ? bo_sb : npart; + while (b < b_lim) { + assert(eb[b] >= 0); /* iff failed, it may indicate some index error elsewhere */ + assert(thr[b] >= 0); + enn += eb[b]; + thmm += thr[b]; + b++; + } + if (b >= npart) { + enn_out[sb] = enn; + thm_out[sb] = thmm; + ++sb; + break; + } + assert(eb[b] >= 0); /* iff failed, it may indicate some index error elsewhere */ + assert(thr[b] >= 0); + { + /* at transition sfb -> sfb+1 */ + FLOAT const w_curr = gd->bo_weight[sb]; + FLOAT const w_next = 1.0f - w_curr; + enn += w_curr * eb[b]; + thmm += w_curr * thr[b]; + enn_out[sb] = enn; + thm_out[sb] = thmm; + enn = w_next * eb[b]; + thmm = w_next * thr[b]; + } + } + /* zero initialize the rest */ + for (; sb < n; ++sb) { + enn_out[sb] = 0; + thm_out[sb] = 0; + } +} + +static void +convert_partition2scalefac_s(lame_internal_flags * gfc, FLOAT const *eb, FLOAT const *thr, int chn, + int sblock) +{ + PsyStateVar_t *const psv = &gfc->sv_psy; + PsyConst_CB2SB_t const *const gds = &gfc->cd_psy->s; + FLOAT enn[SBMAX_s], thm[SBMAX_s]; + int sb; + convert_partition2scalefac(gds, eb, thr, enn, thm); + for (sb = 0; sb < SBMAX_s; ++sb) { + psv->en[chn].s[sb][sblock] = enn[sb]; + psv->thm[chn].s[sb][sblock] = thm[sb]; + } +} + +/* longblock threshold calculation (part 2) */ +static void +convert_partition2scalefac_l(lame_internal_flags * gfc, FLOAT const *eb, FLOAT const *thr, int chn) +{ + PsyStateVar_t *const psv = &gfc->sv_psy; + PsyConst_CB2SB_t const *const gdl = &gfc->cd_psy->l; + FLOAT *enn = &psv->en[chn].l[0]; + FLOAT *thm = &psv->thm[chn].l[0]; + convert_partition2scalefac(gdl, eb, thr, enn, thm); +} + +static void +convert_partition2scalefac_l_to_s(lame_internal_flags * gfc, FLOAT const *eb, FLOAT const *thr, + int chn) +{ + PsyStateVar_t *const psv = &gfc->sv_psy; + PsyConst_CB2SB_t const *const gds = &gfc->cd_psy->l_to_s; + FLOAT enn[SBMAX_s], thm[SBMAX_s]; + int sb, sblock; + convert_partition2scalefac(gds, eb, thr, enn, thm); + for (sb = 0; sb < SBMAX_s; ++sb) { + FLOAT const scale = 1. / 64.f; + FLOAT const tmp_enn = enn[sb]; + FLOAT const tmp_thm = thm[sb] * scale; + for (sblock = 0; sblock < 3; ++sblock) { + psv->en[chn].s[sb][sblock] = tmp_enn; + psv->thm[chn].s[sb][sblock] = tmp_thm; + } + } +} + + + +static inline FLOAT +NS_INTERP(FLOAT x, FLOAT y, FLOAT r) +{ + /* was pow((x),(r))*pow((y),1-(r)) */ + if (r >= 1.0f) + return x; /* 99.7% of the time */ + if (r <= 0.0f) + return y; + if (y > 0.0f) + return powf(x / y, r) * y; /* rest of the time */ + return 0.0f; /* never happens */ +} + + + +static FLOAT +pecalc_s(III_psy_ratio const *mr, FLOAT masking_lower) +{ + FLOAT pe_s; + static const FLOAT regcoef_s[] = { + 11.8, /* these values are tuned only for 44.1kHz... */ + 13.6, + 17.2, + 32, + 46.5, + 51.3, + 57.5, + 67.1, + 71.5, + 84.6, + 97.6, + 130, +/* 255.8 */ + }; + unsigned int sb, sblock; + + pe_s = 1236.28f / 4; + for (sb = 0; sb < SBMAX_s - 1; sb++) { + for (sblock = 0; sblock < 3; sblock++) { + FLOAT const thm = mr->thm.s[sb][sblock]; + assert(sb < dimension_of(regcoef_s)); + if (thm > 0.0f) { + FLOAT const x = thm * masking_lower; + FLOAT const en = mr->en.s[sb][sblock]; + if (en > x) { + if (en > x * 1e10f) { + pe_s += regcoef_s[sb] * (10.0f * LOG10); + } + else { + assert(x > 0); + pe_s += regcoef_s[sb] * FAST_LOG10(en / x); + } + } + } + } + } + + return pe_s; +} + +static FLOAT +pecalc_l(III_psy_ratio const *mr, FLOAT masking_lower) +{ + FLOAT pe_l; + static const FLOAT regcoef_l[] = { + 6.8, /* these values are tuned only for 44.1kHz... */ + 5.8, + 5.8, + 6.4, + 6.5, + 9.9, + 12.1, + 14.4, + 15, + 18.9, + 21.6, + 26.9, + 34.2, + 40.2, + 46.8, + 56.5, + 60.7, + 73.9, + 85.7, + 93.4, + 126.1, +/* 241.3 */ + }; + unsigned int sb; + + pe_l = 1124.23f / 4; + for (sb = 0; sb < SBMAX_l - 1; sb++) { + FLOAT const thm = mr->thm.l[sb]; + assert(sb < dimension_of(regcoef_l)); + if (thm > 0.0f) { + FLOAT const x = thm * masking_lower; + FLOAT const en = mr->en.l[sb]; + if (en > x) { + if (en > x * 1e10f) { + pe_l += regcoef_l[sb] * (10.0f * LOG10); + } + else { + assert(x > 0); + pe_l += regcoef_l[sb] * FAST_LOG10(en / x); + } + } + } + } + + return pe_l; +} + + +static void +calc_energy(PsyConst_CB2SB_t const *l, FLOAT const *fftenergy, FLOAT * eb, FLOAT * max, FLOAT * avg) +{ + int b, j; + + for (b = j = 0; b < l->npart; ++b) { + FLOAT ebb = 0, m = 0; + int i; + for (i = 0; i < l->numlines[b]; ++i, ++j) { + FLOAT const el = fftenergy[j]; + assert(el >= 0); + ebb += el; + if (m < el) + m = el; + } + eb[b] = ebb; + max[b] = m; + avg[b] = ebb * l->rnumlines[b]; + assert(l->rnumlines[b] >= 0); + assert(ebb >= 0); + assert(eb[b] >= 0); + assert(max[b] >= 0); + assert(avg[b] >= 0); + } +} + + +static void +calc_mask_index_l(lame_internal_flags const *gfc, FLOAT const *max, + FLOAT const *avg, unsigned char *mask_idx) +{ + PsyConst_CB2SB_t const *const gdl = &gfc->cd_psy->l; + FLOAT m, a; + int b, k; + int const last_tab_entry = sizeof(tab) / sizeof(tab[0]) - 1; + b = 0; + a = avg[b] + avg[b + 1]; + assert(a >= 0); + if (a > 0.0f) { + m = max[b]; + if (m < max[b + 1]) + m = max[b + 1]; + assert((gdl->numlines[b] + gdl->numlines[b + 1] - 1) > 0); + a = 20.0f * (m * 2.0f - a) + / (a * (gdl->numlines[b] + gdl->numlines[b + 1] - 1)); + k = (int) a; + if (k > last_tab_entry) + k = last_tab_entry; + mask_idx[b] = k; + } + else { + mask_idx[b] = 0; + } + + for (b = 1; b < gdl->npart - 1; b++) { + a = avg[b - 1] + avg[b] + avg[b + 1]; + assert(a >= 0); + if (a > 0.0f) { + m = max[b - 1]; + if (m < max[b]) + m = max[b]; + if (m < max[b + 1]) + m = max[b + 1]; + assert((gdl->numlines[b - 1] + gdl->numlines[b] + gdl->numlines[b + 1] - 1) > 0); + a = 20.0f * (m * 3.0f - a) + / (a * (gdl->numlines[b - 1] + gdl->numlines[b] + gdl->numlines[b + 1] - 1)); + k = (int) a; + if (k > last_tab_entry) + k = last_tab_entry; + mask_idx[b] = k; + } + else { + mask_idx[b] = 0; + } + } + assert(b > 0); + assert(b == gdl->npart - 1); + + a = avg[b - 1] + avg[b]; + assert(a >= 0); + if (a > 0.0f) { + m = max[b - 1]; + if (m < max[b]) + m = max[b]; + assert((gdl->numlines[b - 1] + gdl->numlines[b] - 1) > 0); + a = 20.0f * (m * 2.0f - a) + / (a * (gdl->numlines[b - 1] + gdl->numlines[b] - 1)); + k = (int) a; + if (k > last_tab_entry) + k = last_tab_entry; + mask_idx[b] = k; + } + else { + mask_idx[b] = 0; + } + assert(b == (gdl->npart - 1)); +} + + +static void +vbrpsy_compute_fft_l(lame_internal_flags * gfc, const sample_t * const buffer[2], int chn, + int gr_out, FLOAT fftenergy[HBLKSIZE], FLOAT(*wsamp_l)[BLKSIZE]) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + PsyStateVar_t *psv = &gfc->sv_psy; + plotting_data *plt = cfg->analysis ? gfc->pinfo : 0; + int j; + + if (chn < 2) { + fft_long(gfc, *wsamp_l, chn, buffer); + } + else if (chn == 2) { + FLOAT const sqrt2_half = SQRT2 * 0.5f; + /* FFT data for mid and side channel is derived from L & R */ + for (j = BLKSIZE - 1; j >= 0; --j) { + FLOAT const l = wsamp_l[0][j]; + FLOAT const r = wsamp_l[1][j]; + wsamp_l[0][j] = (l + r) * sqrt2_half; + wsamp_l[1][j] = (l - r) * sqrt2_half; + } + } + + /********************************************************************* + * compute energies + *********************************************************************/ + fftenergy[0] = wsamp_l[0][0]; + fftenergy[0] *= fftenergy[0]; + + for (j = BLKSIZE / 2 - 1; j >= 0; --j) { + FLOAT const re = (*wsamp_l)[BLKSIZE / 2 - j]; + FLOAT const im = (*wsamp_l)[BLKSIZE / 2 + j]; + fftenergy[BLKSIZE / 2 - j] = (re * re + im * im) * 0.5f; + } + /* total energy */ + { + FLOAT totalenergy = 0.0f; + for (j = 11; j < HBLKSIZE; j++) + totalenergy += fftenergy[j]; + + psv->tot_ener[chn] = totalenergy; + } + + if (plt) { + for (j = 0; j < HBLKSIZE; j++) { + plt->energy[gr_out][chn][j] = plt->energy_save[chn][j]; + plt->energy_save[chn][j] = fftenergy[j]; + } + } +} + + +static void +vbrpsy_compute_fft_s(lame_internal_flags const *gfc, const sample_t * const buffer[2], int chn, + int sblock, FLOAT(*fftenergy_s)[HBLKSIZE_s], FLOAT(*wsamp_s)[3][BLKSIZE_s]) +{ + int j; + + if (sblock == 0 && chn < 2) { + fft_short(gfc, *wsamp_s, chn, buffer); + } + if (chn == 2) { + FLOAT const sqrt2_half = SQRT2 * 0.5f; + /* FFT data for mid and side channel is derived from L & R */ + for (j = BLKSIZE_s - 1; j >= 0; --j) { + FLOAT const l = wsamp_s[0][sblock][j]; + FLOAT const r = wsamp_s[1][sblock][j]; + wsamp_s[0][sblock][j] = (l + r) * sqrt2_half; + wsamp_s[1][sblock][j] = (l - r) * sqrt2_half; + } + } + + /********************************************************************* + * compute energies + *********************************************************************/ + fftenergy_s[sblock][0] = (*wsamp_s)[sblock][0]; + fftenergy_s[sblock][0] *= fftenergy_s[sblock][0]; + for (j = BLKSIZE_s / 2 - 1; j >= 0; --j) { + FLOAT const re = (*wsamp_s)[sblock][BLKSIZE_s / 2 - j]; + FLOAT const im = (*wsamp_s)[sblock][BLKSIZE_s / 2 + j]; + fftenergy_s[sblock][BLKSIZE_s / 2 - j] = (re * re + im * im) * 0.5f; + } +} + + + /********************************************************************* + * compute loudness approximation (used for ATH auto-level adjustment) + *********************************************************************/ +static void +vbrpsy_compute_loudness_approximation_l(lame_internal_flags * gfc, int gr_out, int chn, + const FLOAT fftenergy[HBLKSIZE]) +{ + PsyStateVar_t *psv = &gfc->sv_psy; + if (chn < 2) { /*no loudness for mid/side ch */ + gfc->ov_psy.loudness_sq[gr_out][chn] = psv->loudness_sq_save[chn]; + psv->loudness_sq_save[chn] = psycho_loudness_approx(fftenergy, gfc->ATH->eql_w); + } +} + + + /********************************************************************** + * Apply HPF of fs/4 to the input signal. + * This is used for attack detection / handling. + **********************************************************************/ +static void +vbrpsy_attack_detection(lame_internal_flags * gfc, const sample_t * const buffer[2], int gr_out, + III_psy_ratio masking_ratio[2][2], III_psy_ratio masking_MS_ratio[2][2], + FLOAT energy[4], FLOAT sub_short_factor[4][3], int ns_attacks[4][4], + int uselongblock[2]) +{ + FLOAT ns_hpfsmpl[2][576]; + SessionConfig_t const *const cfg = &gfc->cfg; + PsyStateVar_t *const psv = &gfc->sv_psy; + plotting_data *plt = cfg->analysis ? gfc->pinfo : 0; + int const n_chn_out = cfg->channels_out; + /* chn=2 and 3 = Mid and Side channels */ + int const n_chn_psy = (cfg->mode == JOINT_STEREO) ? 4 : n_chn_out; + int chn, i, j; + + memset(&ns_hpfsmpl[0][0], 0, sizeof(ns_hpfsmpl)); + /* Don't copy the input buffer into a temporary buffer */ + /* unroll the loop 2 times */ + for (chn = 0; chn < n_chn_out; chn++) { + static const FLOAT fircoef[] = { + -8.65163e-18 * 2, -0.00851586 * 2, -6.74764e-18 * 2, 0.0209036 * 2, + -3.36639e-17 * 2, -0.0438162 * 2, -1.54175e-17 * 2, 0.0931738 * 2, + -5.52212e-17 * 2, -0.313819 * 2 + }; + /* apply high pass filter of fs/4 */ + const sample_t *const firbuf = &buffer[chn][576 - 350 - NSFIRLEN + 192]; + assert(dimension_of(fircoef) == ((NSFIRLEN - 1) / 2)); + for (i = 0; i < 576; i++) { + FLOAT sum1, sum2; + sum1 = firbuf[i + 10]; + sum2 = 0.0; + for (j = 0; j < ((NSFIRLEN - 1) / 2) - 1; j += 2) { + sum1 += fircoef[j] * (firbuf[i + j] + firbuf[i + NSFIRLEN - j]); + sum2 += fircoef[j + 1] * (firbuf[i + j + 1] + firbuf[i + NSFIRLEN - j - 1]); + } + ns_hpfsmpl[chn][i] = sum1 + sum2; + } + masking_ratio[gr_out][chn].en = psv->en[chn]; + masking_ratio[gr_out][chn].thm = psv->thm[chn]; + if (n_chn_psy > 2) { + /* MS maskings */ + /*percep_MS_entropy [chn-2] = gfc -> pe [chn]; */ + masking_MS_ratio[gr_out][chn].en = psv->en[chn + 2]; + masking_MS_ratio[gr_out][chn].thm = psv->thm[chn + 2]; + } + } + for (chn = 0; chn < n_chn_psy; chn++) { + FLOAT attack_intensity[12]; + FLOAT en_subshort[12]; + FLOAT en_short[4] = { 0, 0, 0, 0 }; + FLOAT const *pf = ns_hpfsmpl[chn & 1]; + int ns_uselongblock = 1; + + if (chn == 2) { + for (i = 0, j = 576; j > 0; ++i, --j) { + FLOAT const l = ns_hpfsmpl[0][i]; + FLOAT const r = ns_hpfsmpl[1][i]; + ns_hpfsmpl[0][i] = l + r; + ns_hpfsmpl[1][i] = l - r; + } + } + /*************************************************************** + * determine the block type (window type) + ***************************************************************/ + /* calculate energies of each sub-shortblocks */ + for (i = 0; i < 3; i++) { + en_subshort[i] = psv->last_en_subshort[chn][i + 6]; + assert(psv->last_en_subshort[chn][i + 4] > 0); + attack_intensity[i] = en_subshort[i] / psv->last_en_subshort[chn][i + 4]; + en_short[0] += en_subshort[i]; + } + + for (i = 0; i < 9; i++) { + FLOAT const *const pfe = pf + 576 / 9; + FLOAT p = 1.; + for (; pf < pfe; pf++) + if (p < fabs(*pf)) + p = fabs(*pf); + psv->last_en_subshort[chn][i] = en_subshort[i + 3] = p; + en_short[1 + i / 3] += p; + if (p > en_subshort[i + 3 - 2]) { + assert(en_subshort[i + 3 - 2] > 0); + p = p / en_subshort[i + 3 - 2]; + } + else if (en_subshort[i + 3 - 2] > p * 10.0f) { + assert(p > 0); + p = en_subshort[i + 3 - 2] / (p * 10.0f); + } + else { + p = 0.0; + } + attack_intensity[i + 3] = p; + } + + /* pulse like signal detection for fatboy.wav and so on */ + for (i = 0; i < 3; ++i) { + FLOAT const enn = + en_subshort[i * 3 + 3] + en_subshort[i * 3 + 4] + en_subshort[i * 3 + 5]; + FLOAT factor = 1.f; + if (en_subshort[i * 3 + 5] * 6 < enn) { + factor *= 0.5f; + if (en_subshort[i * 3 + 4] * 6 < enn) { + factor *= 0.5f; + } + } + sub_short_factor[chn][i] = factor; + } + + if (plt) { + FLOAT x = attack_intensity[0]; + for (i = 1; i < 12; i++) { + if (x < attack_intensity[i]) { + x = attack_intensity[i]; + } + } + plt->ers[gr_out][chn] = plt->ers_save[chn]; + plt->ers_save[chn] = x; + } + + /* compare energies between sub-shortblocks */ + { + FLOAT x = gfc->cd_psy->attack_threshold[chn]; + for (i = 0; i < 12; i++) { + if (ns_attacks[chn][i / 3] == 0) { + if (attack_intensity[i] > x) { + ns_attacks[chn][i / 3] = (i % 3) + 1; + } + } + } + } + /* should have energy change between short blocks, in order to avoid periodic signals */ + /* Good samples to show the effect are Trumpet test songs */ + /* GB: tuned (1) to avoid too many short blocks for test sample TRUMPET */ + /* RH: tuned (2) to let enough short blocks through for test sample FSOL and SNAPS */ + for (i = 1; i < 4; i++) { + FLOAT const u = en_short[i - 1]; + FLOAT const v = en_short[i]; + FLOAT const m = Max(u, v); + if (m < 40000) { /* (2) */ + if (u < 1.7f * v && v < 1.7f * u) { /* (1) */ + if (i == 1 && ns_attacks[chn][0] <= ns_attacks[chn][i]) { + ns_attacks[chn][0] = 0; + } + ns_attacks[chn][i] = 0; + } + } + } + + if (ns_attacks[chn][0] <= psv->last_attacks[chn]) { + ns_attacks[chn][0] = 0; + } + + if (psv->last_attacks[chn] == 3 || + ns_attacks[chn][0] + ns_attacks[chn][1] + ns_attacks[chn][2] + ns_attacks[chn][3]) { + ns_uselongblock = 0; + + if (ns_attacks[chn][1] && ns_attacks[chn][0]) { + ns_attacks[chn][1] = 0; + } + if (ns_attacks[chn][2] && ns_attacks[chn][1]) { + ns_attacks[chn][2] = 0; + } + if (ns_attacks[chn][3] && ns_attacks[chn][2]) { + ns_attacks[chn][3] = 0; + } + } + + if (chn < 2) { + uselongblock[chn] = ns_uselongblock; + } + else { + if (ns_uselongblock == 0) { + uselongblock[0] = uselongblock[1] = 0; + } + } + + /* there is a one granule delay. Copy maskings computed last call + * into masking_ratio to return to calling program. + */ + energy[chn] = psv->tot_ener[chn]; + } +} + + +static void +vbrpsy_skip_masking_s(lame_internal_flags * gfc, int chn, int sblock) +{ + if (sblock == 0) { + FLOAT *nbs2 = &gfc->sv_psy.nb_s2[chn][0]; + FLOAT *nbs1 = &gfc->sv_psy.nb_s1[chn][0]; + int const n = gfc->cd_psy->s.npart; + int b; + for (b = 0; b < n; b++) { + nbs2[b] = nbs1[b]; + } + } +} + + +static void +vbrpsy_calc_mask_index_s(lame_internal_flags const *gfc, FLOAT const *max, + FLOAT const *avg, unsigned char *mask_idx) +{ + PsyConst_CB2SB_t const *const gds = &gfc->cd_psy->s; + FLOAT m, a; + int b, k; + int const last_tab_entry = dimension_of(tab) - 1; + b = 0; + a = avg[b] + avg[b + 1]; + assert(a >= 0); + if (a > 0.0f) { + m = max[b]; + if (m < max[b + 1]) + m = max[b + 1]; + assert((gds->numlines[b] + gds->numlines[b + 1] - 1) > 0); + a = 20.0f * (m * 2.0f - a) + / (a * (gds->numlines[b] + gds->numlines[b + 1] - 1)); + k = (int) a; + if (k > last_tab_entry) + k = last_tab_entry; + mask_idx[b] = k; + } + else { + mask_idx[b] = 0; + } + + for (b = 1; b < gds->npart - 1; b++) { + a = avg[b - 1] + avg[b] + avg[b + 1]; + assert(b + 1 < gds->npart); + assert(a >= 0); + if (a > 0.0) { + m = max[b - 1]; + if (m < max[b]) + m = max[b]; + if (m < max[b + 1]) + m = max[b + 1]; + assert((gds->numlines[b - 1] + gds->numlines[b] + gds->numlines[b + 1] - 1) > 0); + a = 20.0f * (m * 3.0f - a) + / (a * (gds->numlines[b - 1] + gds->numlines[b] + gds->numlines[b + 1] - 1)); + k = (int) a; + if (k > last_tab_entry) + k = last_tab_entry; + mask_idx[b] = k; + } + else { + mask_idx[b] = 0; + } + } + assert(b > 0); + assert(b == gds->npart - 1); + + a = avg[b - 1] + avg[b]; + assert(a >= 0); + if (a > 0.0f) { + m = max[b - 1]; + if (m < max[b]) + m = max[b]; + assert((gds->numlines[b - 1] + gds->numlines[b] - 1) > 0); + a = 20.0f * (m * 2.0f - a) + / (a * (gds->numlines[b - 1] + gds->numlines[b] - 1)); + k = (int) a; + if (k > last_tab_entry) + k = last_tab_entry; + mask_idx[b] = k; + } + else { + mask_idx[b] = 0; + } + assert(b == (gds->npart - 1)); +} + + +static void +vbrpsy_compute_masking_s(lame_internal_flags * gfc, const FLOAT(*fftenergy_s)[HBLKSIZE_s], + FLOAT * eb, FLOAT * thr, int chn, int sblock) +{ + PsyStateVar_t *const psv = &gfc->sv_psy; + PsyConst_CB2SB_t const *const gds = &gfc->cd_psy->s; + FLOAT max[CBANDS], avg[CBANDS]; + int i, j, b; + unsigned char mask_idx_s[CBANDS]; + + memset(max, 0, sizeof(max)); + memset(avg, 0, sizeof(avg)); + + for (b = j = 0; b < gds->npart; ++b) { + FLOAT ebb = 0, m = 0; + int const n = gds->numlines[b]; + for (i = 0; i < n; ++i, ++j) { + FLOAT const el = fftenergy_s[sblock][j]; + ebb += el; + if (m < el) + m = el; + } + eb[b] = ebb; + assert(ebb >= 0); + max[b] = m; + assert(n > 0); + avg[b] = ebb * gds->rnumlines[b]; + assert(avg[b] >= 0); + } + assert(b == gds->npart); + assert(j == 129); + vbrpsy_calc_mask_index_s(gfc, max, avg, mask_idx_s); + for (j = b = 0; b < gds->npart; b++) { + int kk = gds->s3ind[b][0]; + int const last = gds->s3ind[b][1]; + int const delta = mask_add_delta(mask_idx_s[b]); + int dd, dd_n; + FLOAT x, ecb, avg_mask; + FLOAT const masking_lower = gds->masking_lower[b] * gfc->sv_qnt.masking_lower; + + dd = mask_idx_s[kk]; + dd_n = 1; + ecb = gds->s3[j] * eb[kk] * tab[mask_idx_s[kk]]; + ++j, ++kk; + while (kk <= last) { + dd += mask_idx_s[kk]; + dd_n += 1; + x = gds->s3[j] * eb[kk] * tab[mask_idx_s[kk]]; + ecb = vbrpsy_mask_add(ecb, x, kk - b, delta); + ++j, ++kk; + } + dd = (1 + 2 * dd) / (2 * dd_n); + avg_mask = tab[dd] * 0.5f; + ecb *= avg_mask; +#if 0 /* we can do PRE ECHO control now here, or do it later */ + if (psv->blocktype_old[chn & 0x01] == SHORT_TYPE) { + /* limit calculated threshold by even older granule */ + FLOAT const t1 = rpelev_s * psv->nb_s1[chn][b]; + FLOAT const t2 = rpelev2_s * psv->nb_s2[chn][b]; + FLOAT const tm = (t2 > 0) ? Min(ecb, t2) : ecb; + thr[b] = (t1 > 0) ? NS_INTERP(Min(tm, t1), ecb, 0.6) : ecb; + } + else { + /* limit calculated threshold by older granule */ + FLOAT const t1 = rpelev_s * psv->nb_s1[chn][b]; + thr[b] = (t1 > 0) ? NS_INTERP(Min(ecb, t1), ecb, 0.6) : ecb; + } +#else /* we do it later */ + thr[b] = ecb; +#endif + psv->nb_s2[chn][b] = psv->nb_s1[chn][b]; + psv->nb_s1[chn][b] = ecb; + { + /* if THR exceeds EB, the quantization routines will take the difference + * from other bands. in case of strong tonal samples (tonaltest.wav) + * this leads to heavy distortions. that's why we limit THR here. + */ + x = max[b]; + x *= gds->minval[b]; + x *= avg_mask; + if (thr[b] > x) { + thr[b] = x; + } + } + if (masking_lower > 1) { + thr[b] *= masking_lower; + } + if (thr[b] > eb[b]) { + thr[b] = eb[b]; + } + if (masking_lower < 1) { + thr[b] *= masking_lower; + } + + assert(thr[b] >= 0); + } + for (; b < CBANDS; ++b) { + eb[b] = 0; + thr[b] = 0; + } +} + + +static void +vbrpsy_compute_masking_l(lame_internal_flags * gfc, const FLOAT fftenergy[HBLKSIZE], + FLOAT eb_l[CBANDS], FLOAT thr[CBANDS], int chn) +{ + PsyStateVar_t *const psv = &gfc->sv_psy; + PsyConst_CB2SB_t const *const gdl = &gfc->cd_psy->l; + FLOAT max[CBANDS], avg[CBANDS]; + unsigned char mask_idx_l[CBANDS + 2]; + int k, b; + + /********************************************************************* + * Calculate the energy and the tonality of each partition. + *********************************************************************/ + calc_energy(gdl, fftenergy, eb_l, max, avg); + calc_mask_index_l(gfc, max, avg, mask_idx_l); + + /********************************************************************* + * convolve the partitioned energy and unpredictability + * with the spreading function, s3_l[b][k] + ********************************************************************/ + k = 0; + for (b = 0; b < gdl->npart; b++) { + FLOAT x, ecb, avg_mask, t; + FLOAT const masking_lower = gdl->masking_lower[b] * gfc->sv_qnt.masking_lower; + /* convolve the partitioned energy with the spreading function */ + int kk = gdl->s3ind[b][0]; + int const last = gdl->s3ind[b][1]; + int const delta = mask_add_delta(mask_idx_l[b]); + int dd = 0, dd_n = 0; + + dd = mask_idx_l[kk]; + dd_n += 1; + ecb = gdl->s3[k] * eb_l[kk] * tab[mask_idx_l[kk]]; + ++k, ++kk; + while (kk <= last) { + dd += mask_idx_l[kk]; + dd_n += 1; + x = gdl->s3[k] * eb_l[kk] * tab[mask_idx_l[kk]]; + t = vbrpsy_mask_add(ecb, x, kk - b, delta); +#if 0 + ecb += eb_l[kk]; + if (ecb > t) { + ecb = t; + } +#else + ecb = t; +#endif + ++k, ++kk; + } + dd = (1 + 2 * dd) / (2 * dd_n); + avg_mask = tab[dd] * 0.5f; + ecb *= avg_mask; + + /**** long block pre-echo control ****/ + /* dont use long block pre-echo control if previous granule was + * a short block. This is to avoid the situation: + * frame0: quiet (very low masking) + * frame1: surge (triggers short blocks) + * frame2: regular frame. looks like pre-echo when compared to + * frame0, but all pre-echo was in frame1. + */ + /* chn=0,1 L and R channels + chn=2,3 S and M channels. + */ + if (psv->blocktype_old[chn & 0x01] == SHORT_TYPE) { + FLOAT const ecb_limit = rpelev * psv->nb_l1[chn][b]; + if (ecb_limit > 0) { + thr[b] = Min(ecb, ecb_limit); + } + else { + /* Robert 071209: + Because we don't calculate long block psy when we know a granule + should be of short blocks, we don't have any clue how the granule + before would have looked like as a long block. So we have to guess + a little bit for this END_TYPE block. + Most of the time we get away with this sloppyness. (fingers crossed :) + The speed increase is worth it. + */ + thr[b] = Min(ecb, eb_l[b] * NS_PREECHO_ATT2); + } + } + else { + FLOAT ecb_limit_2 = rpelev2 * psv->nb_l2[chn][b]; + FLOAT ecb_limit_1 = rpelev * psv->nb_l1[chn][b]; + FLOAT ecb_limit; + if (ecb_limit_2 <= 0) { + ecb_limit_2 = ecb; + } + if (ecb_limit_1 <= 0) { + ecb_limit_1 = ecb; + } + if (psv->blocktype_old[chn & 0x01] == NORM_TYPE) { + ecb_limit = Min(ecb_limit_1, ecb_limit_2); + } + else { + ecb_limit = ecb_limit_1; + } + thr[b] = Min(ecb, ecb_limit); + } + psv->nb_l2[chn][b] = psv->nb_l1[chn][b]; + psv->nb_l1[chn][b] = ecb; + { + /* if THR exceeds EB, the quantization routines will take the difference + * from other bands. in case of strong tonal samples (tonaltest.wav) + * this leads to heavy distortions. that's why we limit THR here. + */ + x = max[b]; + x *= gdl->minval[b]; + x *= avg_mask; + if (thr[b] > x) { + thr[b] = x; + } + } + if (masking_lower > 1) { + thr[b] *= masking_lower; + } + if (thr[b] > eb_l[b]) { + thr[b] = eb_l[b]; + } + if (masking_lower < 1) { + thr[b] *= masking_lower; + } + assert(thr[b] >= 0); + } + for (; b < CBANDS; ++b) { + eb_l[b] = 0; + thr[b] = 0; + } +} + + +static void +vbrpsy_compute_block_type(SessionConfig_t const *cfg, int *uselongblock) +{ + int chn; + + if (cfg->short_blocks == short_block_coupled + /* force both channels to use the same block type */ + /* this is necessary if the frame is to be encoded in ms_stereo. */ + /* But even without ms_stereo, FhG does this */ + && !(uselongblock[0] && uselongblock[1])) + uselongblock[0] = uselongblock[1] = 0; + + for (chn = 0; chn < cfg->channels_out; chn++) { + /* disable short blocks */ + if (cfg->short_blocks == short_block_dispensed) { + uselongblock[chn] = 1; + } + if (cfg->short_blocks == short_block_forced) { + uselongblock[chn] = 0; + } + } +} + + +static void +vbrpsy_apply_block_type(PsyStateVar_t * psv, int nch, int const *uselongblock, int *blocktype_d) +{ + int chn; + + /* update the blocktype of the previous granule, since it depends on what + * happend in this granule */ + for (chn = 0; chn < nch; chn++) { + int blocktype = NORM_TYPE; + /* disable short blocks */ + + if (uselongblock[chn]) { + /* no attack : use long blocks */ + assert(psv->blocktype_old[chn] != START_TYPE); + if (psv->blocktype_old[chn] == SHORT_TYPE) + blocktype = STOP_TYPE; + } + else { + /* attack : use short blocks */ + blocktype = SHORT_TYPE; + if (psv->blocktype_old[chn] == NORM_TYPE) { + psv->blocktype_old[chn] = START_TYPE; + } + if (psv->blocktype_old[chn] == STOP_TYPE) + psv->blocktype_old[chn] = SHORT_TYPE; + } + + blocktype_d[chn] = psv->blocktype_old[chn]; /* value returned to calling program */ + psv->blocktype_old[chn] = blocktype; /* save for next call to l3psy_anal */ + } +} + + +/*************************************************************** + * compute M/S thresholds from Johnston & Ferreira 1992 ICASSP paper + ***************************************************************/ + +static void +vbrpsy_compute_MS_thresholds(const FLOAT eb[4][CBANDS], FLOAT thr[4][CBANDS], + const FLOAT cb_mld[CBANDS], const FLOAT ath_cb[CBANDS], FLOAT athlower, + FLOAT msfix, int n) +{ + FLOAT const msfix2 = msfix * 2.f; + FLOAT rside, rmid; + int b; + for (b = 0; b < n; ++b) { + FLOAT const ebM = eb[2][b]; + FLOAT const ebS = eb[3][b]; + FLOAT const thmL = thr[0][b]; + FLOAT const thmR = thr[1][b]; + FLOAT thmM = thr[2][b]; + FLOAT thmS = thr[3][b]; + + /* use this fix if L & R masking differs by 2db or less */ + /* if db = 10*log10(x2/x1) < 2 */ + /* if (x2 < 1.58*x1) { */ + if (thmL <= 1.58f * thmR && thmR <= 1.58f * thmL) { + FLOAT const mld_m = cb_mld[b] * ebS; + FLOAT const mld_s = cb_mld[b] * ebM; + FLOAT const tmp_m = Min(thmS, mld_m); + FLOAT const tmp_s = Min(thmM, mld_s); + rmid = Max(thmM, tmp_m); + rside = Max(thmS, tmp_s); + } + else { + rmid = thmM; + rside = thmS; + } + if (msfix > 0.f) { + /***************************************************************/ + /* Adjust M/S maskings if user set "msfix" */ + /***************************************************************/ + /* Naoki Shibata 2000 */ + FLOAT thmLR, thmMS; + FLOAT const ath = ath_cb[b] * athlower; + FLOAT const tmp_l = Max(thmL, ath); + FLOAT const tmp_r = Max(thmR, ath); + thmLR = Min(tmp_l, tmp_r); + thmM = Max(rmid, ath); + thmS = Max(rside, ath); + thmMS = thmM + thmS; + if (thmMS > 0.f && (thmLR * msfix2) < thmMS) { + FLOAT const f = thmLR * msfix2 / thmMS; + thmM *= f; + thmS *= f; + assert(thmMS > 0.f); + } + rmid = Min(thmM, rmid); + rside = Min(thmS, rside); + } + if (rmid > ebM) { + rmid = ebM; + } + if (rside > ebS) { + rside = ebS; + } + thr[2][b] = rmid; + thr[3][b] = rside; + } +} + + +/* + * NOTE: the bitrate reduction from the inter-channel masking effect is low + * compared to the chance of getting annyoing artefacts. L3psycho_anal_vbr does + * not use this feature. (Robert 071216) +*/ + +int +L3psycho_anal_vbr(lame_internal_flags * gfc, + const sample_t * const buffer[2], int gr_out, + III_psy_ratio masking_ratio[2][2], + III_psy_ratio masking_MS_ratio[2][2], + FLOAT percep_entropy[2], FLOAT percep_MS_entropy[2], + FLOAT energy[4], int blocktype_d[2]) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + PsyStateVar_t *const psv = &gfc->sv_psy; + PsyConst_CB2SB_t const *const gdl = &gfc->cd_psy->l; + PsyConst_CB2SB_t const *const gds = &gfc->cd_psy->s; + plotting_data *plt = cfg->analysis ? gfc->pinfo : 0; + + III_psy_xmin last_thm[4]; + + /* fft and energy calculation */ + FLOAT(*wsamp_l)[BLKSIZE]; + FLOAT(*wsamp_s)[3][BLKSIZE_s]; + FLOAT fftenergy[HBLKSIZE]; + FLOAT fftenergy_s[3][HBLKSIZE_s]; + FLOAT wsamp_L[2][BLKSIZE]; + FLOAT wsamp_S[2][3][BLKSIZE_s]; + FLOAT eb[4][CBANDS], thr[4][CBANDS]; + + FLOAT sub_short_factor[4][3]; + FLOAT thmm; + FLOAT const pcfact = 0.6f; + FLOAT const ath_factor = + (cfg->msfix > 0.f) ? (cfg->ATH_offset_factor * gfc->ATH->adjust_factor) : 1.f; + + const FLOAT(*const_eb)[CBANDS] = (const FLOAT(*)[CBANDS]) eb; + const FLOAT(*const_fftenergy_s)[HBLKSIZE_s] = (const FLOAT(*)[HBLKSIZE_s]) fftenergy_s; + + /* block type */ + int ns_attacks[4][4] = { {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0} }; + int uselongblock[2]; + + /* usual variables like loop indices, etc.. */ + int chn, sb, sblock; + + /* chn=2 and 3 = Mid and Side channels */ + int const n_chn_psy = (cfg->mode == JOINT_STEREO) ? 4 : cfg->channels_out; + + memcpy(&last_thm[0], &psv->thm[0], sizeof(last_thm)); + + vbrpsy_attack_detection(gfc, buffer, gr_out, masking_ratio, masking_MS_ratio, energy, + sub_short_factor, ns_attacks, uselongblock); + + vbrpsy_compute_block_type(cfg, uselongblock); + + /* LONG BLOCK CASE */ + { + for (chn = 0; chn < n_chn_psy; chn++) { + int const ch01 = chn & 0x01; + + wsamp_l = wsamp_L + ch01; + vbrpsy_compute_fft_l(gfc, buffer, chn, gr_out, fftenergy, wsamp_l); + vbrpsy_compute_loudness_approximation_l(gfc, gr_out, chn, fftenergy); + vbrpsy_compute_masking_l(gfc, fftenergy, eb[chn], thr[chn], chn); + } + if (cfg->mode == JOINT_STEREO) { + if ((uselongblock[0] + uselongblock[1]) == 2) { + vbrpsy_compute_MS_thresholds(const_eb, thr, gdl->mld_cb, gfc->ATH->cb_l, + ath_factor, cfg->msfix, gdl->npart); + } + } + /* TODO: apply adaptive ATH masking here ?? */ + for (chn = 0; chn < n_chn_psy; chn++) { + convert_partition2scalefac_l(gfc, eb[chn], thr[chn], chn); + convert_partition2scalefac_l_to_s(gfc, eb[chn], thr[chn], chn); + } + } + /* SHORT BLOCKS CASE */ + { + int const force_short_block_calc = gfc->cd_psy->force_short_block_calc; + for (sblock = 0; sblock < 3; sblock++) { + for (chn = 0; chn < n_chn_psy; ++chn) { + int const ch01 = chn & 0x01; + if (uselongblock[ch01] && !force_short_block_calc) { + vbrpsy_skip_masking_s(gfc, chn, sblock); + } + else { + /* compute masking thresholds for short blocks */ + wsamp_s = wsamp_S + ch01; + vbrpsy_compute_fft_s(gfc, buffer, chn, sblock, fftenergy_s, wsamp_s); + vbrpsy_compute_masking_s(gfc, const_fftenergy_s, eb[chn], thr[chn], chn, + sblock); + } + } + if (cfg->mode == JOINT_STEREO) { + if ((uselongblock[0] + uselongblock[1]) == 0) { + vbrpsy_compute_MS_thresholds(const_eb, thr, gds->mld_cb, gfc->ATH->cb_s, + ath_factor, cfg->msfix, gds->npart); + } + } + /* TODO: apply adaptive ATH masking here ?? */ + for (chn = 0; chn < n_chn_psy; ++chn) { + int const ch01 = chn & 0x01; + if (!uselongblock[ch01] || force_short_block_calc) { + convert_partition2scalefac_s(gfc, eb[chn], thr[chn], chn, sblock); + } + } + } + + /**** short block pre-echo control ****/ + for (chn = 0; chn < n_chn_psy; chn++) { + for (sb = 0; sb < SBMAX_s; sb++) { + FLOAT new_thmm[3], prev_thm, t1, t2; + for (sblock = 0; sblock < 3; sblock++) { + thmm = psv->thm[chn].s[sb][sblock]; + thmm *= NS_PREECHO_ATT0; + + t1 = t2 = thmm; + + if (sblock > 0) { + prev_thm = new_thmm[sblock - 1]; + } + else { + prev_thm = last_thm[chn].s[sb][2]; + } + if (ns_attacks[chn][sblock] >= 2 || ns_attacks[chn][sblock + 1] == 1) { + t1 = NS_INTERP(prev_thm, thmm, NS_PREECHO_ATT1 * pcfact); + } + thmm = Min(t1, thmm); + if (ns_attacks[chn][sblock] == 1) { + t2 = NS_INTERP(prev_thm, thmm, NS_PREECHO_ATT2 * pcfact); + } + else if ((sblock == 0 && psv->last_attacks[chn] == 3) + || (sblock > 0 && ns_attacks[chn][sblock - 1] == 3)) { /* 2nd preceeding block */ + switch (sblock) { + case 0: + prev_thm = last_thm[chn].s[sb][1]; + break; + case 1: + prev_thm = last_thm[chn].s[sb][2]; + break; + case 2: + prev_thm = new_thmm[0]; + break; + } + t2 = NS_INTERP(prev_thm, thmm, NS_PREECHO_ATT2 * pcfact); + } + + thmm = Min(t1, thmm); + thmm = Min(t2, thmm); + + /* pulse like signal detection for fatboy.wav and so on */ + thmm *= sub_short_factor[chn][sblock]; + + new_thmm[sblock] = thmm; + } + for (sblock = 0; sblock < 3; sblock++) { + psv->thm[chn].s[sb][sblock] = new_thmm[sblock]; + } + } + } + } + for (chn = 0; chn < n_chn_psy; chn++) { + psv->last_attacks[chn] = ns_attacks[chn][2]; + } + + + /*************************************************************** + * determine final block type + ***************************************************************/ + vbrpsy_apply_block_type(psv, cfg->channels_out, uselongblock, blocktype_d); + + /********************************************************************* + * compute the value of PE to return ... no delay and advance + *********************************************************************/ + for (chn = 0; chn < n_chn_psy; chn++) { + FLOAT *ppe; + int type; + III_psy_ratio const *mr; + + if (chn > 1) { + ppe = percep_MS_entropy - 2; + type = NORM_TYPE; + if (blocktype_d[0] == SHORT_TYPE || blocktype_d[1] == SHORT_TYPE) + type = SHORT_TYPE; + mr = &masking_MS_ratio[gr_out][chn - 2]; + } + else { + ppe = percep_entropy; + type = blocktype_d[chn]; + mr = &masking_ratio[gr_out][chn]; + } + if (type == SHORT_TYPE) { + ppe[chn] = pecalc_s(mr, gfc->sv_qnt.masking_lower); + } + else { + ppe[chn] = pecalc_l(mr, gfc->sv_qnt.masking_lower); + } + + if (plt) { + plt->pe[gr_out][chn] = ppe[chn]; + } + } + return 0; +} + + + + +/* + * The spreading function. Values returned in units of energy + */ +static FLOAT +s3_func(FLOAT bark) +{ + FLOAT tempx, x, tempy, temp; + tempx = bark; + if (tempx >= 0) + tempx *= 3; + else + tempx *= 1.5; + + if (tempx >= 0.5 && tempx <= 2.5) { + temp = tempx - 0.5; + x = 8.0 * (temp * temp - 2.0 * temp); + } + else + x = 0.0; + tempx += 0.474; + tempy = 15.811389 + 7.5 * tempx - 17.5 * sqrt(1.0 + tempx * tempx); + + if (tempy <= -60.0) + return 0.0; + + tempx = exp((x + tempy) * LN_TO_LOG10); + + /* Normalization. The spreading function should be normalized so that: + +inf + / + | s3 [ bark ] d(bark) = 1 + / + -inf + */ + tempx /= .6609193; + return tempx; +} + +#if 0 +static FLOAT +norm_s3_func(void) +{ + double lim_a = 0, lim_b = 0; + double x = 0, l, h; + for (x = 0; s3_func(x) > 1e-20; x -= 1); + l = x; + h = 0; + while (fabs(h - l) > 1e-12) { + x = (h + l) / 2; + if (s3_func(x) > 0) { + h = x; + } + else { + l = x; + } + } + lim_a = l; + for (x = 0; s3_func(x) > 1e-20; x += 1); + l = 0; + h = x; + while (fabs(h - l) > 1e-12) { + x = (h + l) / 2; + if (s3_func(x) > 0) { + l = x; + } + else { + h = x; + } + } + lim_b = h; + { + double sum = 0; + int const m = 1000; + int i; + for (i = 0; i <= m; ++i) { + double x = lim_a + i * (lim_b - lim_a) / m; + double y = s3_func(x); + sum += y; + } + { + double norm = (m + 1) / (sum * (lim_b - lim_a)); + /*printf( "norm = %lf\n",norm); */ + return norm; + } + } +} +#endif + +static FLOAT +stereo_demask(double f) +{ + /* setup stereo demasking thresholds */ + /* formula reverse enginerred from plot in paper */ + double arg = freq2bark(f); + arg = (Min(arg, 15.5) / 15.5); + + return pow(10.0, 1.25 * (1 - cos(PI * arg)) - 2.5); +} + +static void +init_numline(PsyConst_CB2SB_t * gd, FLOAT sfreq, int fft_size, + int mdct_size, int sbmax, int const *scalepos) +{ + FLOAT b_frq[CBANDS + 1]; + FLOAT const mdct_freq_frac = sfreq / (2.0f * mdct_size); + FLOAT const deltafreq = fft_size / (2.0f * mdct_size); + int partition[HBLKSIZE] = { 0 }; + int i, j, ni; + int sfb; + sfreq /= fft_size; + j = 0; + ni = 0; + /* compute numlines, the number of spectral lines in each partition band */ + /* each partition band should be about DELBARK wide. */ + for (i = 0; i < CBANDS; i++) { + FLOAT bark1; + int j2, nl; + bark1 = freq2bark(sfreq * j); + + b_frq[i] = sfreq * j; + + for (j2 = j; freq2bark(sfreq * j2) - bark1 < DELBARK && j2 <= fft_size / 2; j2++); + + nl = j2 - j; + gd->numlines[i] = nl; + gd->rnumlines[i] = (nl > 0) ? (1.0f / nl) : 0; + + ni = i + 1; + + while (j < j2) { + assert(j < HBLKSIZE); + partition[j++] = i; + } + if (j > fft_size / 2) { + j = fft_size / 2; + ++i; + break; + } + } + assert(i < CBANDS); + b_frq[i] = sfreq * j; + + gd->n_sb = sbmax; + gd->npart = ni; + + { + j = 0; + for (i = 0; i < gd->npart; i++) { + int const nl = gd->numlines[i]; + FLOAT const freq = sfreq * (j + nl / 2); + gd->mld_cb[i] = stereo_demask(freq); + j += nl; + } + for (; i < CBANDS; ++i) { + gd->mld_cb[i] = 1; + } + } + for (sfb = 0; sfb < sbmax; sfb++) { + int i1, i2, bo; + int start = scalepos[sfb]; + int end = scalepos[sfb + 1]; + + i1 = floor(.5 + deltafreq * (start - .5)); + if (i1 < 0) + i1 = 0; + i2 = floor(.5 + deltafreq * (end - .5)); + + if (i2 > fft_size / 2) + i2 = fft_size / 2; + + bo = partition[i2]; + gd->bm[sfb] = (partition[i1] + partition[i2]) / 2; + gd->bo[sfb] = bo; + + /* calculate how much of this band belongs to current scalefactor band */ + { + FLOAT const f_tmp = mdct_freq_frac * end; + FLOAT bo_w = (f_tmp - b_frq[bo]) / (b_frq[bo + 1] - b_frq[bo]); + if (bo_w < 0) { + bo_w = 0; + } + else { + if (bo_w > 1) { + bo_w = 1; + } + } + gd->bo_weight[sfb] = bo_w; + } + gd->mld[sfb] = stereo_demask(mdct_freq_frac * start); + } +} + +static void +compute_bark_values(PsyConst_CB2SB_t const *gd, FLOAT sfreq, int fft_size, + FLOAT * bval, FLOAT * bval_width) +{ + /* compute bark values of each critical band */ + int k, j = 0, ni = gd->npart; + sfreq /= fft_size; + for (k = 0; k < ni; k++) { + int const w = gd->numlines[k]; + FLOAT bark1, bark2; + + bark1 = freq2bark(sfreq * (j)); + bark2 = freq2bark(sfreq * (j + w - 1)); + bval[k] = .5 * (bark1 + bark2); + + bark1 = freq2bark(sfreq * (j - .5)); + bark2 = freq2bark(sfreq * (j + w - .5)); + bval_width[k] = bark2 - bark1; + j += w; + } +} + +static int +init_s3_values(FLOAT ** p, int (*s3ind)[2], int npart, + FLOAT const *bval, FLOAT const *bval_width, FLOAT const *norm) +{ + FLOAT s3[CBANDS][CBANDS]; + /* The s3 array is not linear in the bark scale. + * bval[x] should be used to get the bark value. + */ + int i, j, k; + int numberOfNoneZero = 0; + + memset(&s3[0][0], 0, sizeof(s3)); + + /* s[i][j], the value of the spreading function, + * centered at band j (masker), for band i (maskee) + * + * i.e.: sum over j to spread into signal barkval=i + * NOTE: i and j are used opposite as in the ISO docs + */ + for (i = 0; i < npart; i++) { + for (j = 0; j < npart; j++) { + FLOAT v = s3_func(bval[i] - bval[j]) * bval_width[j]; + s3[i][j] = v * norm[i]; + } + } + for (i = 0; i < npart; i++) { + for (j = 0; j < npart; j++) { + if (s3[i][j] > 0.0f) + break; + } + s3ind[i][0] = j; + + for (j = npart - 1; j > 0; j--) { + if (s3[i][j] > 0.0f) + break; + } + s3ind[i][1] = j; + numberOfNoneZero += (s3ind[i][1] - s3ind[i][0] + 1); + } + *p = lame_calloc(FLOAT, numberOfNoneZero); + if (!*p) + return -1; + + k = 0; + for (i = 0; i < npart; i++) + for (j = s3ind[i][0]; j <= s3ind[i][1]; j++) + (*p)[k++] = s3[i][j]; + + return 0; +} + +int +psymodel_init(lame_global_flags const *gfp) +{ + lame_internal_flags *const gfc = gfp->internal_flags; + SessionConfig_t *const cfg = &gfc->cfg; + PsyStateVar_t *const psv = &gfc->sv_psy; + PsyConst_t *gd; + int i, j, b, sb, k; + FLOAT bvl_a = 13, bvl_b = 24; + FLOAT snr_l_a = 0, snr_l_b = 0; + FLOAT snr_s_a = -8.25, snr_s_b = -4.5; + + FLOAT bval[CBANDS]; + FLOAT bval_width[CBANDS]; + FLOAT norm[CBANDS]; + FLOAT const sfreq = cfg->samplerate_out; + + FLOAT xav = 10, xbv = 12; + FLOAT const minval_low = (0.f - cfg->minval); + + if (gfc->cd_psy != 0) { + return 0; + } + memset(norm, 0, sizeof(norm)); + + gd = lame_calloc(PsyConst_t, 1); + gfc->cd_psy = gd; + + gd->force_short_block_calc = gfp->experimentalZ; + + psv->blocktype_old[0] = psv->blocktype_old[1] = NORM_TYPE; /* the vbr header is long blocks */ + + for (i = 0; i < 4; ++i) { + for (j = 0; j < CBANDS; ++j) { + psv->nb_l1[i][j] = 1e20; + psv->nb_l2[i][j] = 1e20; + psv->nb_s1[i][j] = psv->nb_s2[i][j] = 1.0; + } + for (sb = 0; sb < SBMAX_l; sb++) { + psv->en[i].l[sb] = 1e20; + psv->thm[i].l[sb] = 1e20; + } + for (j = 0; j < 3; ++j) { + for (sb = 0; sb < SBMAX_s; sb++) { + psv->en[i].s[sb][j] = 1e20; + psv->thm[i].s[sb][j] = 1e20; + } + psv->last_attacks[i] = 0; + } + for (j = 0; j < 9; j++) + psv->last_en_subshort[i][j] = 10.; + } + + + /* init. for loudness approx. -jd 2001 mar 27 */ + psv->loudness_sq_save[0] = psv->loudness_sq_save[1] = 0.0; + + + + /************************************************************************* + * now compute the psychoacoustic model specific constants + ************************************************************************/ + /* compute numlines, bo, bm, bval, bval_width, mld */ + init_numline(&gd->l, sfreq, BLKSIZE, 576, SBMAX_l, gfc->scalefac_band.l); + assert(gd->l.npart < CBANDS); + compute_bark_values(&gd->l, sfreq, BLKSIZE, bval, bval_width); + + /* compute the spreading function */ + for (i = 0; i < gd->l.npart; i++) { + double snr = snr_l_a; + if (bval[i] >= bvl_a) { + snr = snr_l_b * (bval[i] - bvl_a) / (bvl_b - bvl_a) + + snr_l_a * (bvl_b - bval[i]) / (bvl_b - bvl_a); + } + norm[i] = pow(10.0, snr / 10.0); + } + i = init_s3_values(&gd->l.s3, gd->l.s3ind, gd->l.npart, bval, bval_width, norm); + if (i) + return i; + + /* compute long block specific values, ATH and MINVAL */ + j = 0; + for (i = 0; i < gd->l.npart; i++) { + double x; + + /* ATH */ + x = FLOAT_MAX; + for (k = 0; k < gd->l.numlines[i]; k++, j++) { + FLOAT const freq = sfreq * j / (1000.0 * BLKSIZE); + FLOAT level; + /* freq = Min(.1,freq); *//* ATH below 100 Hz constant, not further climbing */ + level = ATHformula(cfg, freq * 1000) - 20; /* scale to FFT units; returned value is in dB */ + level = pow(10., 0.1 * level); /* convert from dB -> energy */ + level *= gd->l.numlines[i]; + if (x > level) + x = level; + } + gfc->ATH->cb_l[i] = x; + + /* MINVAL. + For low freq, the strength of the masking is limited by minval + this is an ISO MPEG1 thing, dont know if it is really needed */ + /* FIXME: it does work to reduce low-freq problems in S53-Wind-Sax + and lead-voice samples, but introduces some 3 kbps bit bloat too. + TODO: Further refinement of the shape of this hack. + */ + x = 20.0 * (bval[i] / xav - 1.0); + if (x > 6) { + x = 30; + } + if (x < minval_low) { + x = minval_low; + } + if (cfg->samplerate_out < 44000) { + x = 30; + } + x -= 8.; + gd->l.minval[i] = pow(10.0, x / 10.) * gd->l.numlines[i]; + } + + /************************************************************************ + * do the same things for short blocks + ************************************************************************/ + init_numline(&gd->s, sfreq, BLKSIZE_s, 192, SBMAX_s, gfc->scalefac_band.s); + assert(gd->s.npart < CBANDS); + compute_bark_values(&gd->s, sfreq, BLKSIZE_s, bval, bval_width); + + /* SNR formula. short block is normalized by SNR. is it still right ? */ + j = 0; + for (i = 0; i < gd->s.npart; i++) { + double x; + double snr = snr_s_a; + if (bval[i] >= bvl_a) { + snr = snr_s_b * (bval[i] - bvl_a) / (bvl_b - bvl_a) + + snr_s_a * (bvl_b - bval[i]) / (bvl_b - bvl_a); + } + norm[i] = pow(10.0, snr / 10.0); + + /* ATH */ + x = FLOAT_MAX; + for (k = 0; k < gd->s.numlines[i]; k++, j++) { + FLOAT const freq = sfreq * j / (1000.0 * BLKSIZE_s); + FLOAT level; + /* freq = Min(.1,freq); *//* ATH below 100 Hz constant, not further climbing */ + level = ATHformula(cfg, freq * 1000) - 20; /* scale to FFT units; returned value is in dB */ + level = pow(10., 0.1 * level); /* convert from dB -> energy */ + level *= gd->s.numlines[i]; + if (x > level) + x = level; + } + gfc->ATH->cb_s[i] = x; + + /* MINVAL. + For low freq, the strength of the masking is limited by minval + this is an ISO MPEG1 thing, dont know if it is really needed */ + x = 7.0 * (bval[i] / xbv - 1.0); + if (bval[i] > xbv) { + x *= 1 + log(1 + x) * 3.1; + } + if (bval[i] < xbv) { + x *= 1 + log(1 - x) * 2.3; + } + if (x > 6) { + x = 30; + } + if (x < minval_low) { + x = minval_low; + } + if (cfg->samplerate_out < 44000) { + x = 30; + } + x -= 8; + gd->s.minval[i] = pow(10.0, x / 10) * gd->s.numlines[i]; + } + + i = init_s3_values(&gd->s.s3, gd->s.s3ind, gd->s.npart, bval, bval_width, norm); + if (i) + return i; + + + init_mask_add_max_values(); + init_fft(gfc); + + /* setup temporal masking */ + gd->decay = exp(-1.0 * LOG10 / (temporalmask_sustain_sec * sfreq / 192.0)); + + { + FLOAT msfix; + msfix = NS_MSFIX; + if (cfg->use_safe_joint_stereo) + msfix = 1.0; + if (fabs(cfg->msfix) > 0.0) + msfix = cfg->msfix; + cfg->msfix = msfix; + + /* spread only from npart_l bands. Normally, we use the spreading + * function to convolve from npart_l down to npart_l bands + */ + for (b = 0; b < gd->l.npart; b++) + if (gd->l.s3ind[b][1] > gd->l.npart - 1) + gd->l.s3ind[b][1] = gd->l.npart - 1; + } + + /* prepare for ATH auto adjustment: + * we want to decrease the ATH by 12 dB per second + */ +#define frame_duration (576. * cfg->mode_gr / sfreq) + gfc->ATH->decay = pow(10., -12. / 10. * frame_duration); + gfc->ATH->adjust_factor = 0.01; /* minimum, for leading low loudness */ + gfc->ATH->adjust_limit = 1.0; /* on lead, allow adjust up to maximum */ +#undef frame_duration + + assert(gd->l.bo[SBMAX_l - 1] <= gd->l.npart); + assert(gd->s.bo[SBMAX_s - 1] <= gd->s.npart); + + if (cfg->ATHtype != -1) { + /* compute equal loudness weights (eql_w) */ + FLOAT freq; + FLOAT const freq_inc = (FLOAT) cfg->samplerate_out / (FLOAT) (BLKSIZE); + FLOAT eql_balance = 0.0; + freq = 0.0; + for (i = 0; i < BLKSIZE / 2; ++i) { + /* convert ATH dB to relative power (not dB) */ + /* to determine eql_w */ + freq += freq_inc; + gfc->ATH->eql_w[i] = 1. / pow(10, ATHformula(cfg, freq) / 10); + eql_balance += gfc->ATH->eql_w[i]; + } + eql_balance = 1.0 / eql_balance; + for (i = BLKSIZE / 2; --i >= 0;) { /* scale weights */ + gfc->ATH->eql_w[i] *= eql_balance; + } + } + { + for (b = j = 0; b < gd->s.npart; ++b) { + for (i = 0; i < gd->s.numlines[b]; ++i) { + ++j; + } + } + assert(j == 129); + for (b = j = 0; b < gd->l.npart; ++b) { + for (i = 0; i < gd->l.numlines[b]; ++i) { + ++j; + } + } + assert(j == 513); + } + /* short block attack threshold */ + { + float x = gfp->attackthre; + float y = gfp->attackthre_s; + if (x < 0) { + x = NSATTACKTHRE; + } + if (y < 0) { + y = NSATTACKTHRE_S; + } + gd->attack_threshold[0] = gd->attack_threshold[1] = gd->attack_threshold[2] = x; + gd->attack_threshold[3] = y; + } + { + float sk_s = -10.f, sk_l = -4.7f; + static float const sk[] = + { -7.4, -7.4, -7.4, -9.5, -7.4, -6.1, -5.5, -4.7, -4.7, -4.7, -4.7 }; + if (gfp->VBR_q < 4) { + sk_l = sk_s = sk[0]; + } + else { + sk_l = sk_s = sk[gfp->VBR_q] + gfp->VBR_q_frac * (sk[gfp->VBR_q] - sk[gfp->VBR_q + 1]); + } + b = 0; + for (; b < gd->s.npart; b++) { + float m = (float) (gd->s.npart - b) / gd->s.npart; + gd->s.masking_lower[b] = powf(10.f, sk_s * m * 0.1f); + } + for (; b < CBANDS; ++b) { + gd->s.masking_lower[b] = 1.f; + } + b = 0; + for (; b < gd->l.npart; b++) { + float m = (float) (gd->l.npart - b) / gd->l.npart; + gd->l.masking_lower[b] = powf(10.f, sk_l * m * 0.1f); + } + for (; b < CBANDS; ++b) { + gd->l.masking_lower[b] = 1.f; + } + } + memcpy(&gd->l_to_s, &gd->l, sizeof(gd->l_to_s)); + init_numline(&gd->l_to_s, sfreq, BLKSIZE, 192, SBMAX_s, gfc->scalefac_band.s); + return 0; +} diff --git a/pkg/lame/clame/psymodel.h b/pkg/lame/clame/psymodel.h new file mode 100644 index 0000000..f46083c --- /dev/null +++ b/pkg/lame/clame/psymodel.h @@ -0,0 +1,64 @@ +/* + * psymodel.h + * + * Copyright (c) 1999 Mark Taylor + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef LAME_PSYMODEL_H +#define LAME_PSYMODEL_H + + +int L3psycho_anal_ns(lame_internal_flags * gfc, + const sample_t *const buffer[2], int gr, + III_psy_ratio ratio[2][2], + III_psy_ratio MS_ratio[2][2], + FLOAT pe[2], FLOAT pe_MS[2], FLOAT ener[2], int blocktype_d[2]); + +int L3psycho_anal_vbr(lame_internal_flags * gfc, + const sample_t *const buffer[2], int gr, + III_psy_ratio ratio[2][2], + III_psy_ratio MS_ratio[2][2], + FLOAT pe[2], FLOAT pe_MS[2], FLOAT ener[2], int blocktype_d[2]); + + +int psymodel_init(lame_global_flags const* gfp); + + +#define rpelev 2 +#define rpelev2 16 +#define rpelev_s 2 +#define rpelev2_s 16 + +/* size of each partition band, in barks: */ +#define DELBARK .34 + + +/* tuned for output level (sensitive to energy scale) */ +#define VO_SCALE (1./( 14752*14752 )/(BLKSIZE/2)) + +#define temporalmask_sustain_sec 0.01 + +#define NS_PREECHO_ATT0 0.8 +#define NS_PREECHO_ATT1 0.6 +#define NS_PREECHO_ATT2 0.3 + +#define NS_MSFIX 3.5 +#define NSATTACKTHRE 4.4 +#define NSATTACKTHRE_S 25 + +#endif /* LAME_PSYMODEL_H */ diff --git a/pkg/lame/clame/quantize.c b/pkg/lame/clame/quantize.c new file mode 100644 index 0000000..9ba9c16 --- /dev/null +++ b/pkg/lame/clame/quantize.c @@ -0,0 +1,2050 @@ +/* + * MP3 quantization + * + * Copyright (c) 1999-2000 Mark Taylor + * Copyright (c) 1999-2003 Takehiro Tominaga + * Copyright (c) 2000-2011 Robert Hegemann + * Copyright (c) 2001-2005 Gabriel Bouvigne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* $Id: quantize.c,v 1.219 2017/08/02 19:48:05 robert Exp $ */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "lame.h" +#include "machine.h" +#include "encoder.h" +#include "util.h" +#include "quantize_pvt.h" +#include "reservoir.h" +#include "bitstream.h" +#include "vbrquantize.h" +#include "quantize.h" +#ifdef HAVE_XMMINTRIN_H +#include "vector/lame_intrin.h" +#endif + + + + +/* convert from L/R <-> Mid/Side */ +static void +ms_convert(III_side_info_t * l3_side, int gr) +{ + int i; + for (i = 0; i < 576; ++i) { + FLOAT l, r; + l = l3_side->tt[gr][0].xr[i]; + r = l3_side->tt[gr][1].xr[i]; + l3_side->tt[gr][0].xr[i] = (l + r) * (FLOAT) (SQRT2 * 0.5); + l3_side->tt[gr][1].xr[i] = (l - r) * (FLOAT) (SQRT2 * 0.5); + } +} + +/************************************************************************ + * + * init_outer_loop() + * mt 6/99 + * + * initializes cod_info, scalefac and xrpow + * + * returns 0 if all energies in xr are zero, else 1 + * + ************************************************************************/ + +static void +init_xrpow_core_c(gr_info * const cod_info, FLOAT xrpow[576], int upper, FLOAT * sum) +{ + int i; + FLOAT tmp; + *sum = 0; + for (i = 0; i <= upper; ++i) { + tmp = fabs(cod_info->xr[i]); + *sum += tmp; + xrpow[i] = sqrt(tmp * sqrt(tmp)); + + if (xrpow[i] > cod_info->xrpow_max) + cod_info->xrpow_max = xrpow[i]; + } +} + + + + + +void +init_xrpow_core_init(lame_internal_flags * const gfc) +{ + gfc->init_xrpow_core = init_xrpow_core_c; + +#if defined(HAVE_XMMINTRIN_H) + if (gfc->CPU_features.SSE) + gfc->init_xrpow_core = init_xrpow_core_sse; +#endif +#ifndef HAVE_NASM +#ifdef MIN_ARCH_SSE + gfc->init_xrpow_core = init_xrpow_core_sse; +#endif +#endif +} + + + +static int +init_xrpow(lame_internal_flags * gfc, gr_info * const cod_info, FLOAT xrpow[576]) +{ + FLOAT sum = 0; + int i; + int const upper = cod_info->max_nonzero_coeff; + + assert(xrpow != NULL); + cod_info->xrpow_max = 0; + + /* check if there is some energy we have to quantize + * and calculate xrpow matching our fresh scalefactors + */ + assert(0 <= upper && upper <= 575); + memset(&(xrpow[upper]), 0, (576 - upper) * sizeof(xrpow[0])); + + + gfc->init_xrpow_core(cod_info, xrpow, upper, &sum); + + /* return 1 if we have something to quantize, else 0 + */ + if (sum > (FLOAT) 1E-20) { + int j = 0; + if (gfc->sv_qnt.substep_shaping & 2) + j = 1; + + for (i = 0; i < cod_info->psymax; i++) + gfc->sv_qnt.pseudohalf[i] = j; + + return 1; + } + + memset(&cod_info->l3_enc[0], 0, sizeof(int) * 576); + return 0; +} + + + + + +/* +Gabriel Bouvigne feb/apr 2003 +Analog silence detection in partitionned sfb21 +or sfb12 for short blocks + +From top to bottom of sfb, changes to 0 +coeffs which are below ath. It stops on the first +coeff higher than ath. +*/ +static void +psfb21_analogsilence(lame_internal_flags const *gfc, gr_info * const cod_info) +{ + ATH_t const *const ATH = gfc->ATH; + FLOAT *const xr = cod_info->xr; + + if (cod_info->block_type != SHORT_TYPE) { /* NORM, START or STOP type, but not SHORT blocks */ + int gsfb; + int stop = 0; + for (gsfb = PSFB21 - 1; gsfb >= 0 && !stop; gsfb--) { + int const start = gfc->scalefac_band.psfb21[gsfb]; + int const end = gfc->scalefac_band.psfb21[gsfb + 1]; + int j; + FLOAT ath21; + ath21 = athAdjust(ATH->adjust_factor, ATH->psfb21[gsfb], ATH->floor, 0); + + if (gfc->sv_qnt.longfact[21] > 1e-12f) + ath21 *= gfc->sv_qnt.longfact[21]; + + for (j = end - 1; j >= start; j--) { + if (fabs(xr[j]) < ath21) + xr[j] = 0; + else { + stop = 1; + break; + } + } + } + } + else { + /*note: short blocks coeffs are reordered */ + int block; + for (block = 0; block < 3; block++) { + + int gsfb; + int stop = 0; + for (gsfb = PSFB12 - 1; gsfb >= 0 && !stop; gsfb--) { + int const start = gfc->scalefac_band.s[12] * 3 + + (gfc->scalefac_band.s[13] - gfc->scalefac_band.s[12]) * block + + (gfc->scalefac_band.psfb12[gsfb] - gfc->scalefac_band.psfb12[0]); + int const end = + start + (gfc->scalefac_band.psfb12[gsfb + 1] - gfc->scalefac_band.psfb12[gsfb]); + int j; + FLOAT ath12; + ath12 = athAdjust(ATH->adjust_factor, ATH->psfb12[gsfb], ATH->floor, 0); + + if (gfc->sv_qnt.shortfact[12] > 1e-12f) + ath12 *= gfc->sv_qnt.shortfact[12]; + + for (j = end - 1; j >= start; j--) { + if (fabs(xr[j]) < ath12) + xr[j] = 0; + else { + stop = 1; + break; + } + } + } + } + } + +} + + + + + +static void +init_outer_loop(lame_internal_flags const *gfc, gr_info * const cod_info) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + int sfb, j; + /* initialize fresh cod_info + */ + cod_info->part2_3_length = 0; + cod_info->big_values = 0; + cod_info->count1 = 0; + cod_info->global_gain = 210; + cod_info->scalefac_compress = 0; + /* mixed_block_flag, block_type was set in psymodel.c */ + cod_info->table_select[0] = 0; + cod_info->table_select[1] = 0; + cod_info->table_select[2] = 0; + cod_info->subblock_gain[0] = 0; + cod_info->subblock_gain[1] = 0; + cod_info->subblock_gain[2] = 0; + cod_info->subblock_gain[3] = 0; /* this one is always 0 */ + cod_info->region0_count = 0; + cod_info->region1_count = 0; + cod_info->preflag = 0; + cod_info->scalefac_scale = 0; + cod_info->count1table_select = 0; + cod_info->part2_length = 0; + if (cfg->samplerate_out <= 8000) { + cod_info->sfb_lmax = 17; + cod_info->sfb_smin = 9; + cod_info->psy_lmax = 17; + } + else { + cod_info->sfb_lmax = SBPSY_l; + cod_info->sfb_smin = SBPSY_s; + cod_info->psy_lmax = gfc->sv_qnt.sfb21_extra ? SBMAX_l : SBPSY_l; + } + cod_info->psymax = cod_info->psy_lmax; + cod_info->sfbmax = cod_info->sfb_lmax; + cod_info->sfbdivide = 11; + for (sfb = 0; sfb < SBMAX_l; sfb++) { + cod_info->width[sfb] + = gfc->scalefac_band.l[sfb + 1] - gfc->scalefac_band.l[sfb]; + cod_info->window[sfb] = 3; /* which is always 0. */ + } + if (cod_info->block_type == SHORT_TYPE) { + FLOAT ixwork[576]; + FLOAT *ix; + + cod_info->sfb_smin = 0; + cod_info->sfb_lmax = 0; + if (cod_info->mixed_block_flag) { + /* + * MPEG-1: sfbs 0-7 long block, 3-12 short blocks + * MPEG-2(.5): sfbs 0-5 long block, 3-12 short blocks + */ + cod_info->sfb_smin = 3; + cod_info->sfb_lmax = cfg->mode_gr * 2 + 4; + } + if (cfg->samplerate_out <= 8000) { + cod_info->psymax + = cod_info->sfb_lmax + + 3 * (9 - cod_info->sfb_smin); + cod_info->sfbmax = cod_info->sfb_lmax + 3 * (9 - cod_info->sfb_smin); + } + else { + cod_info->psymax + = cod_info->sfb_lmax + + 3 * ((gfc->sv_qnt.sfb21_extra ? SBMAX_s : SBPSY_s) - cod_info->sfb_smin); + cod_info->sfbmax = cod_info->sfb_lmax + 3 * (SBPSY_s - cod_info->sfb_smin); + } + cod_info->sfbdivide = cod_info->sfbmax - 18; + cod_info->psy_lmax = cod_info->sfb_lmax; + /* re-order the short blocks, for more efficient encoding below */ + /* By Takehiro TOMINAGA */ + /* + Within each scalefactor band, data is given for successive + time windows, beginning with window 0 and ending with window 2. + Within each window, the quantized values are then arranged in + order of increasing frequency... + */ + ix = &cod_info->xr[gfc->scalefac_band.l[cod_info->sfb_lmax]]; + memcpy(ixwork, cod_info->xr, 576 * sizeof(FLOAT)); + for (sfb = cod_info->sfb_smin; sfb < SBMAX_s; sfb++) { + int const start = gfc->scalefac_band.s[sfb]; + int const end = gfc->scalefac_band.s[sfb + 1]; + int window, l; + for (window = 0; window < 3; window++) { + for (l = start; l < end; l++) { + *ix++ = ixwork[3 * l + window]; + } + } + } + + j = cod_info->sfb_lmax; + for (sfb = cod_info->sfb_smin; sfb < SBMAX_s; sfb++) { + cod_info->width[j] = cod_info->width[j + 1] = cod_info->width[j + 2] + = gfc->scalefac_band.s[sfb + 1] - gfc->scalefac_band.s[sfb]; + cod_info->window[j] = 0; + cod_info->window[j + 1] = 1; + cod_info->window[j + 2] = 2; + j += 3; + } + } + + cod_info->count1bits = 0; + cod_info->sfb_partition_table = nr_of_sfb_block[0][0]; + cod_info->slen[0] = 0; + cod_info->slen[1] = 0; + cod_info->slen[2] = 0; + cod_info->slen[3] = 0; + + cod_info->max_nonzero_coeff = 575; + + /* fresh scalefactors are all zero + */ + memset(cod_info->scalefac, 0, sizeof(cod_info->scalefac)); + + if (cfg->vbr != vbr_mt && cfg->vbr != vbr_mtrh && cfg->vbr != vbr_abr && cfg->vbr != vbr_off) { + psfb21_analogsilence(gfc, cod_info); + } +} + + + +/************************************************************************ + * + * bin_search_StepSize() + * + * author/date?? + * + * binary step size search + * used by outer_loop to get a quantizer step size to start with + * + ************************************************************************/ + +typedef enum { + BINSEARCH_NONE, + BINSEARCH_UP, + BINSEARCH_DOWN +} binsearchDirection_t; + +static int +bin_search_StepSize(lame_internal_flags * const gfc, gr_info * const cod_info, + int desired_rate, const int ch, const FLOAT xrpow[576]) +{ + int nBits; + int CurrentStep = gfc->sv_qnt.CurrentStep[ch]; + int flag_GoneOver = 0; + int const start = gfc->sv_qnt.OldValue[ch]; + binsearchDirection_t Direction = BINSEARCH_NONE; + cod_info->global_gain = start; + desired_rate -= cod_info->part2_length; + + assert(CurrentStep); + for (;;) { + int step; + nBits = count_bits(gfc, xrpow, cod_info, 0); + + if (CurrentStep == 1 || nBits == desired_rate) + break; /* nothing to adjust anymore */ + + if (nBits > desired_rate) { + /* increase Quantize_StepSize */ + if (Direction == BINSEARCH_DOWN) + flag_GoneOver = 1; + + if (flag_GoneOver) + CurrentStep /= 2; + Direction = BINSEARCH_UP; + step = CurrentStep; + } + else { + /* decrease Quantize_StepSize */ + if (Direction == BINSEARCH_UP) + flag_GoneOver = 1; + + if (flag_GoneOver) + CurrentStep /= 2; + Direction = BINSEARCH_DOWN; + step = -CurrentStep; + } + cod_info->global_gain += step; + if (cod_info->global_gain < 0) { + cod_info->global_gain = 0; + flag_GoneOver = 1; + } + if (cod_info->global_gain > 255) { + cod_info->global_gain = 255; + flag_GoneOver = 1; + } + } + + assert(cod_info->global_gain >= 0); + assert(cod_info->global_gain < 256); + + while (nBits > desired_rate && cod_info->global_gain < 255) { + cod_info->global_gain++; + nBits = count_bits(gfc, xrpow, cod_info, 0); + } + gfc->sv_qnt.CurrentStep[ch] = (start - cod_info->global_gain >= 4) ? 4 : 2; + gfc->sv_qnt.OldValue[ch] = cod_info->global_gain; + cod_info->part2_3_length = nBits; + return nBits; +} + + + + +/************************************************************************ + * + * trancate_smallspectrums() + * + * Takehiro TOMINAGA 2002-07-21 + * + * trancate smaller nubmers into 0 as long as the noise threshold is allowed. + * + ************************************************************************/ +static int +floatcompare(const void *v1, const void *v2) +{ + const FLOAT *const a = v1, *const b = v2; + if (*a > *b) + return 1; + if (*a < *b) + return -1; + return 0; +} + +static void +trancate_smallspectrums(lame_internal_flags const *gfc, + gr_info * const gi, const FLOAT * const l3_xmin, FLOAT * const work) +{ + int sfb, j, width; + FLOAT distort[SFBMAX]; + calc_noise_result dummy; + + if ((!(gfc->sv_qnt.substep_shaping & 4) && gi->block_type == SHORT_TYPE) + || gfc->sv_qnt.substep_shaping & 0x80) + return; + (void) calc_noise(gi, l3_xmin, distort, &dummy, 0); + for (j = 0; j < 576; j++) { + FLOAT xr = 0.0; + if (gi->l3_enc[j] != 0) + xr = fabs(gi->xr[j]); + work[j] = xr; + } + + j = 0; + sfb = 8; + if (gi->block_type == SHORT_TYPE) + sfb = 6; + do { + FLOAT allowedNoise, trancateThreshold; + int nsame, start; + + width = gi->width[sfb]; + j += width; + if (distort[sfb] >= 1.0) + continue; + + qsort(&work[j - width], width, sizeof(FLOAT), floatcompare); + if (EQ(work[j - 1], 0.0)) + continue; /* all zero sfb */ + + allowedNoise = (1.0 - distort[sfb]) * l3_xmin[sfb]; + trancateThreshold = 0.0; + start = 0; + do { + FLOAT noise; + for (nsame = 1; start + nsame < width; nsame++) + if (NEQ(work[start + j - width], work[start + j + nsame - width])) + break; + + noise = work[start + j - width] * work[start + j - width] * nsame; + if (allowedNoise < noise) { + if (start != 0) + trancateThreshold = work[start + j - width - 1]; + break; + } + allowedNoise -= noise; + start += nsame; + } while (start < width); + if (EQ(trancateThreshold, 0.0)) + continue; + +/* printf("%e %e %e\n", */ +/* trancateThreshold/l3_xmin[sfb], */ +/* trancateThreshold/(l3_xmin[sfb]*start), */ +/* trancateThreshold/(l3_xmin[sfb]*(start+width)) */ +/* ); */ +/* if (trancateThreshold > 1000*l3_xmin[sfb]*start) */ +/* trancateThreshold = 1000*l3_xmin[sfb]*start; */ + + do { + if (fabs(gi->xr[j - width]) <= trancateThreshold) + gi->l3_enc[j - width] = 0; + } while (--width > 0); + } while (++sfb < gi->psymax); + + gi->part2_3_length = noquant_count_bits(gfc, gi, 0); +} + + +/************************************************************************* + * + * loop_break() + * + * author/date?? + * + * Function: Returns zero if there is a scalefac which has not been + * amplified. Otherwise it returns one. + * + *************************************************************************/ + +inline static int +loop_break(const gr_info * const cod_info) +{ + int sfb; + + for (sfb = 0; sfb < cod_info->sfbmax; sfb++) + if (cod_info->scalefac[sfb] + + cod_info->subblock_gain[cod_info->window[sfb]] == 0) + return 0; + + return 1; +} + + + + +/* mt 5/99: Function: Improved calc_noise for a single channel */ + +/************************************************************************* + * + * quant_compare() + * + * author/date?? + * + * several different codes to decide which quantization is better + * + *************************************************************************/ + +static double +penalties(double noise) +{ + return FAST_LOG10(0.368 + 0.632 * noise * noise * noise); +} + +static double +get_klemm_noise(const FLOAT * distort, const gr_info * const gi) +{ + int sfb; + double klemm_noise = 1E-37; + for (sfb = 0; sfb < gi->psymax; sfb++) + klemm_noise += penalties(distort[sfb]); + + return Max(1e-20, klemm_noise); +} + +inline static int +quant_compare(const int quant_comp, + const calc_noise_result * const best, + calc_noise_result * const calc, const gr_info * const gi, const FLOAT * distort) +{ + /* + noise is given in decibels (dB) relative to masking thesholds. + + over_noise: ??? (the previous comment is fully wrong) + tot_noise: ??? (the previous comment is fully wrong) + max_noise: max quantization noise + + */ + int better; + + switch (quant_comp) { + default: + case 9:{ + if (best->over_count > 0) { + /* there are distorted sfb */ + better = calc->over_SSD <= best->over_SSD; + if (calc->over_SSD == best->over_SSD) + better = calc->bits < best->bits; + } + else { + /* no distorted sfb */ + better = ((calc->max_noise < 0) && + ((calc->max_noise * 10 + calc->bits) <= + (best->max_noise * 10 + best->bits))); + } + break; + } + + case 0: + better = calc->over_count < best->over_count + || (calc->over_count == best->over_count && calc->over_noise < best->over_noise) + || (calc->over_count == best->over_count && + EQ(calc->over_noise, best->over_noise) && calc->tot_noise < best->tot_noise); + break; + + case 8: + calc->max_noise = get_klemm_noise(distort, gi); + /*lint --fallthrough */ + case 1: + better = calc->max_noise < best->max_noise; + break; + case 2: + better = calc->tot_noise < best->tot_noise; + break; + case 3: + better = (calc->tot_noise < best->tot_noise) + && (calc->max_noise < best->max_noise); + break; + case 4: + better = (calc->max_noise <= 0.0 && best->max_noise > 0.2) + || (calc->max_noise <= 0.0 && + best->max_noise < 0.0 && + best->max_noise > calc->max_noise - 0.2 && calc->tot_noise < best->tot_noise) + || (calc->max_noise <= 0.0 && + best->max_noise > 0.0 && + best->max_noise > calc->max_noise - 0.2 && + calc->tot_noise < best->tot_noise + best->over_noise) + || (calc->max_noise > 0.0 && + best->max_noise > -0.05 && + best->max_noise > calc->max_noise - 0.1 && + calc->tot_noise + calc->over_noise < best->tot_noise + best->over_noise) + || (calc->max_noise > 0.0 && + best->max_noise > -0.1 && + best->max_noise > calc->max_noise - 0.15 && + calc->tot_noise + calc->over_noise + calc->over_noise < + best->tot_noise + best->over_noise + best->over_noise); + break; + case 5: + better = calc->over_noise < best->over_noise + || (EQ(calc->over_noise, best->over_noise) && calc->tot_noise < best->tot_noise); + break; + case 6: + better = calc->over_noise < best->over_noise + || (EQ(calc->over_noise, best->over_noise) && + (calc->max_noise < best->max_noise + || (EQ(calc->max_noise, best->max_noise) && calc->tot_noise <= best->tot_noise) + )); + break; + case 7: + better = calc->over_count < best->over_count || calc->over_noise < best->over_noise; + break; + } + + + if (best->over_count == 0) { + /* + If no distorted bands, only use this quantization + if it is better, and if it uses less bits. + Unfortunately, part2_3_length is sometimes a poor + estimator of the final size at low bitrates. + */ + better = better && calc->bits < best->bits; + } + + + return better; +} + + + +/************************************************************************* + * + * amp_scalefac_bands() + * + * author/date?? + * + * Amplify the scalefactor bands that violate the masking threshold. + * See ISO 11172-3 Section C.1.5.4.3.5 + * + * distort[] = noise/masking + * distort[] > 1 ==> noise is not masked + * distort[] < 1 ==> noise is masked + * max_dist = maximum value of distort[] + * + * Three algorithms: + * noise_shaping_amp + * 0 Amplify all bands with distort[]>1. + * + * 1 Amplify all bands with distort[] >= max_dist^(.5); + * ( 50% in the db scale) + * + * 2 Amplify first band with distort[] >= max_dist; + * + * + * For algorithms 0 and 1, if max_dist < 1, then amplify all bands + * with distort[] >= .95*max_dist. This is to make sure we always + * amplify at least one band. + * + * + *************************************************************************/ +static void +amp_scalefac_bands(lame_internal_flags * gfc, + gr_info * const cod_info, FLOAT const *distort, FLOAT xrpow[576], int bRefine) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + int j, sfb; + FLOAT ifqstep34, trigger; + int noise_shaping_amp; + + if (cod_info->scalefac_scale == 0) { + ifqstep34 = 1.29683955465100964055; /* 2**(.75*.5) */ + } + else { + ifqstep34 = 1.68179283050742922612; /* 2**(.75*1) */ + } + + /* compute maximum value of distort[] */ + trigger = 0; + for (sfb = 0; sfb < cod_info->sfbmax; sfb++) { + if (trigger < distort[sfb]) + trigger = distort[sfb]; + } + + noise_shaping_amp = cfg->noise_shaping_amp; + if (noise_shaping_amp == 3) { + if (bRefine == 1) + noise_shaping_amp = 2; + else + noise_shaping_amp = 1; + } + switch (noise_shaping_amp) { + case 2: + /* amplify exactly 1 band */ + break; + + case 1: + /* amplify bands within 50% of max (on db scale) */ + if (trigger > 1.0) + trigger = pow(trigger, .5); + else + trigger *= .95; + break; + + case 0: + default: + /* ISO algorithm. amplify all bands with distort>1 */ + if (trigger > 1.0) + trigger = 1.0; + else + trigger *= .95; + break; + } + + j = 0; + for (sfb = 0; sfb < cod_info->sfbmax; sfb++) { + int const width = cod_info->width[sfb]; + int l; + j += width; + if (distort[sfb] < trigger) + continue; + + if (gfc->sv_qnt.substep_shaping & 2) { + gfc->sv_qnt.pseudohalf[sfb] = !gfc->sv_qnt.pseudohalf[sfb]; + if (!gfc->sv_qnt.pseudohalf[sfb] && cfg->noise_shaping_amp == 2) + return; + } + cod_info->scalefac[sfb]++; + for (l = -width; l < 0; l++) { + xrpow[j + l] *= ifqstep34; + if (xrpow[j + l] > cod_info->xrpow_max) + cod_info->xrpow_max = xrpow[j + l]; + } + + if (cfg->noise_shaping_amp == 2) + return; + } +} + +/************************************************************************* + * + * inc_scalefac_scale() + * + * Takehiro Tominaga 2000-xx-xx + * + * turns on scalefac scale and adjusts scalefactors + * + *************************************************************************/ + +static void +inc_scalefac_scale(gr_info * const cod_info, FLOAT xrpow[576]) +{ + int l, j, sfb; + const FLOAT ifqstep34 = 1.29683955465100964055; + + j = 0; + for (sfb = 0; sfb < cod_info->sfbmax; sfb++) { + int const width = cod_info->width[sfb]; + int s = cod_info->scalefac[sfb]; + if (cod_info->preflag) + s += pretab[sfb]; + j += width; + if (s & 1) { + s++; + for (l = -width; l < 0; l++) { + xrpow[j + l] *= ifqstep34; + if (xrpow[j + l] > cod_info->xrpow_max) + cod_info->xrpow_max = xrpow[j + l]; + } + } + cod_info->scalefac[sfb] = s >> 1; + } + cod_info->preflag = 0; + cod_info->scalefac_scale = 1; +} + + + +/************************************************************************* + * + * inc_subblock_gain() + * + * Takehiro Tominaga 2000-xx-xx + * + * increases the subblock gain and adjusts scalefactors + * + *************************************************************************/ + +static int +inc_subblock_gain(const lame_internal_flags * const gfc, gr_info * const cod_info, FLOAT xrpow[576]) +{ + int sfb, window; + int *const scalefac = cod_info->scalefac; + + /* subbloc_gain can't do anything in the long block region */ + for (sfb = 0; sfb < cod_info->sfb_lmax; sfb++) { + if (scalefac[sfb] >= 16) + return 1; + } + + for (window = 0; window < 3; window++) { + int s1, s2, l, j; + s1 = s2 = 0; + + for (sfb = cod_info->sfb_lmax + window; sfb < cod_info->sfbdivide; sfb += 3) { + if (s1 < scalefac[sfb]) + s1 = scalefac[sfb]; + } + for (; sfb < cod_info->sfbmax; sfb += 3) { + if (s2 < scalefac[sfb]) + s2 = scalefac[sfb]; + } + + if (s1 < 16 && s2 < 8) + continue; + + if (cod_info->subblock_gain[window] >= 7) + return 1; + + /* even though there is no scalefactor for sfb12 + * subblock gain affects upper frequencies too, that's why + * we have to go up to SBMAX_s + */ + cod_info->subblock_gain[window]++; + j = gfc->scalefac_band.l[cod_info->sfb_lmax]; + for (sfb = cod_info->sfb_lmax + window; sfb < cod_info->sfbmax; sfb += 3) { + FLOAT amp; + int const width = cod_info->width[sfb]; + int s = scalefac[sfb]; + assert(s >= 0); + s = s - (4 >> cod_info->scalefac_scale); + if (s >= 0) { + scalefac[sfb] = s; + j += width * 3; + continue; + } + + scalefac[sfb] = 0; + { + int const gain = 210 + (s << (cod_info->scalefac_scale + 1)); + amp = IPOW20(gain); + } + j += width * (window + 1); + for (l = -width; l < 0; l++) { + xrpow[j + l] *= amp; + if (xrpow[j + l] > cod_info->xrpow_max) + cod_info->xrpow_max = xrpow[j + l]; + } + j += width * (3 - window - 1); + } + + { + FLOAT const amp = IPOW20(202); + j += cod_info->width[sfb] * (window + 1); + for (l = -cod_info->width[sfb]; l < 0; l++) { + xrpow[j + l] *= amp; + if (xrpow[j + l] > cod_info->xrpow_max) + cod_info->xrpow_max = xrpow[j + l]; + } + } + } + return 0; +} + + + +/******************************************************************** + * + * balance_noise() + * + * Takehiro Tominaga /date?? + * Robert Hegemann 2000-09-06: made a function of it + * + * amplifies scalefactor bands, + * - if all are already amplified returns 0 + * - if some bands are amplified too much: + * * try to increase scalefac_scale + * * if already scalefac_scale was set + * try on short blocks to increase subblock gain + * + ********************************************************************/ +inline static int +balance_noise(lame_internal_flags * gfc, + gr_info * const cod_info, FLOAT const *distort, FLOAT xrpow[576], int bRefine) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + int status; + + amp_scalefac_bands(gfc, cod_info, distort, xrpow, bRefine); + + /* check to make sure we have not amplified too much + * loop_break returns 0 if there is an unamplified scalefac + * scale_bitcount returns 0 if no scalefactors are too large + */ + + status = loop_break(cod_info); + + if (status) + return 0; /* all bands amplified */ + + /* not all scalefactors have been amplified. so these + * scalefacs are possibly valid. encode them: + */ + status = scale_bitcount(gfc, cod_info); + + if (!status) + return 1; /* amplified some bands not exceeding limits */ + + /* some scalefactors are too large. + * lets try setting scalefac_scale=1 + */ + if (cfg->noise_shaping > 1) { + memset(&gfc->sv_qnt.pseudohalf[0], 0, sizeof(gfc->sv_qnt.pseudohalf)); + if (!cod_info->scalefac_scale) { + inc_scalefac_scale(cod_info, xrpow); + status = 0; + } + else { + if (cod_info->block_type == SHORT_TYPE && cfg->subblock_gain > 0) { + status = inc_subblock_gain(gfc, cod_info, xrpow) + || loop_break(cod_info); + } + } + } + + if (!status) { + status = scale_bitcount(gfc, cod_info); + } + return !status; +} + + + +/************************************************************************ + * + * outer_loop () + * + * Function: The outer iteration loop controls the masking conditions + * of all scalefactorbands. It computes the best scalefac and + * global gain. This module calls the inner iteration loop + * + * mt 5/99 completely rewritten to allow for bit reservoir control, + * mid/side channels with L/R or mid/side masking thresholds, + * and chooses best quantization instead of last quantization when + * no distortion free quantization can be found. + * + * added VBR support mt 5/99 + * + * some code shuffle rh 9/00 + ************************************************************************/ + +static int +outer_loop(lame_internal_flags * gfc, gr_info * const cod_info, const FLOAT * const l3_xmin, /* allowed distortion */ + FLOAT xrpow[576], /* coloured magnitudes of spectral */ + const int ch, const int targ_bits) +{ /* maximum allowed bits */ + SessionConfig_t const *const cfg = &gfc->cfg; + gr_info cod_info_w; + FLOAT save_xrpow[576]; + FLOAT distort[SFBMAX]; + calc_noise_result best_noise_info; + int huff_bits; + int better; + int age; + calc_noise_data prev_noise; + int best_part2_3_length = 9999999; + int bEndOfSearch = 0; + int bRefine = 0; + int best_ggain_pass1 = 0; + + (void) bin_search_StepSize(gfc, cod_info, targ_bits, ch, xrpow); + + if (!cfg->noise_shaping) + /* fast mode, no noise shaping, we are ready */ + return 100; /* default noise_info.over_count */ + + memset(&prev_noise, 0, sizeof(calc_noise_data)); + + + /* compute the distortion in this quantization */ + /* coefficients and thresholds both l/r (or both mid/side) */ + (void) calc_noise(cod_info, l3_xmin, distort, &best_noise_info, &prev_noise); + best_noise_info.bits = cod_info->part2_3_length; + + cod_info_w = *cod_info; + age = 0; + /* if (cfg->vbr == vbr_rh || cfg->vbr == vbr_mtrh) */ + memcpy(save_xrpow, xrpow, sizeof(FLOAT) * 576); + + while (!bEndOfSearch) { + /* BEGIN MAIN LOOP */ + do { + calc_noise_result noise_info; + int search_limit; + int maxggain = 255; + + /* When quantization with no distorted bands is found, + * allow up to X new unsuccesful tries in serial. This + * gives us more possibilities for different quant_compare modes. + * Much more than 3 makes not a big difference, it is only slower. + */ + + if (gfc->sv_qnt.substep_shaping & 2) { + search_limit = 20; + } + else { + search_limit = 3; + } + + + + /* Check if the last scalefactor band is distorted. + * in VBR mode we can't get rid of the distortion, so quit now + * and VBR mode will try again with more bits. + * (makes a 10% speed increase, the files I tested were + * binary identical, 2000/05/20 Robert Hegemann) + * distort[] > 1 means noise > allowed noise + */ + if (gfc->sv_qnt.sfb21_extra) { + if (distort[cod_info_w.sfbmax] > 1.0) + break; + if (cod_info_w.block_type == SHORT_TYPE + && (distort[cod_info_w.sfbmax + 1] > 1.0 + || distort[cod_info_w.sfbmax + 2] > 1.0)) + break; + } + + /* try a new scalefactor conbination on cod_info_w */ + if (balance_noise(gfc, &cod_info_w, distort, xrpow, bRefine) == 0) + break; + if (cod_info_w.scalefac_scale) + maxggain = 254; + + /* inner_loop starts with the initial quantization step computed above + * and slowly increases until the bits < huff_bits. + * Thus it is important not to start with too large of an inital + * quantization step. Too small is ok, but inner_loop will take longer + */ + huff_bits = targ_bits - cod_info_w.part2_length; + if (huff_bits <= 0) + break; + + /* increase quantizer stepsize until needed bits are below maximum + */ + while ((cod_info_w.part2_3_length + = count_bits(gfc, xrpow, &cod_info_w, &prev_noise)) > huff_bits + && cod_info_w.global_gain <= maxggain) + cod_info_w.global_gain++; + + if (cod_info_w.global_gain > maxggain) + break; + + if (best_noise_info.over_count == 0) { + + while ((cod_info_w.part2_3_length + = count_bits(gfc, xrpow, &cod_info_w, &prev_noise)) > best_part2_3_length + && cod_info_w.global_gain <= maxggain) + cod_info_w.global_gain++; + + if (cod_info_w.global_gain > maxggain) + break; + } + + /* compute the distortion in this quantization */ + (void) calc_noise(&cod_info_w, l3_xmin, distort, &noise_info, &prev_noise); + noise_info.bits = cod_info_w.part2_3_length; + + /* check if this quantization is better + * than our saved quantization */ + if (cod_info->block_type != SHORT_TYPE) /* NORM, START or STOP type */ + better = cfg->quant_comp; + else + better = cfg->quant_comp_short; + + + better = quant_compare(better, &best_noise_info, &noise_info, &cod_info_w, distort); + + + /* save data so we can restore this quantization later */ + if (better) { + best_part2_3_length = cod_info->part2_3_length; + best_noise_info = noise_info; + *cod_info = cod_info_w; + age = 0; + /* save data so we can restore this quantization later */ + /*if (cfg->vbr == vbr_rh || cfg->vbr == vbr_mtrh) */ { + /* store for later reuse */ + memcpy(save_xrpow, xrpow, sizeof(FLOAT) * 576); + } + } + else { + /* early stop? */ + if (cfg->full_outer_loop == 0) { + if (++age > search_limit && best_noise_info.over_count == 0) + break; + if ((cfg->noise_shaping_amp == 3) && bRefine && age > 30) + break; + if ((cfg->noise_shaping_amp == 3) && bRefine && + (cod_info_w.global_gain - best_ggain_pass1) > 15) + break; + } + } + } + while ((cod_info_w.global_gain + cod_info_w.scalefac_scale) < 255); + + if (cfg->noise_shaping_amp == 3) { + if (!bRefine) { + /* refine search */ + cod_info_w = *cod_info; + memcpy(xrpow, save_xrpow, sizeof(FLOAT) * 576); + age = 0; + best_ggain_pass1 = cod_info_w.global_gain; + + bRefine = 1; + } + else { + /* search already refined, stop */ + bEndOfSearch = 1; + } + + } + else { + bEndOfSearch = 1; + } + } + + assert((cod_info->global_gain + cod_info->scalefac_scale) <= 255); + /* finish up + */ + if (cfg->vbr == vbr_rh || cfg->vbr == vbr_mtrh || cfg->vbr == vbr_mt) + /* restore for reuse on next try */ + memcpy(xrpow, save_xrpow, sizeof(FLOAT) * 576); + /* do the 'substep shaping' + */ + else if (gfc->sv_qnt.substep_shaping & 1) + trancate_smallspectrums(gfc, cod_info, l3_xmin, xrpow); + + return best_noise_info.over_count; +} + + + + + +/************************************************************************ + * + * iteration_finish_one() + * + * Robert Hegemann 2000-09-06 + * + * update reservoir status after FINAL quantization/bitrate + * + ************************************************************************/ + +static void +iteration_finish_one(lame_internal_flags * gfc, int gr, int ch) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + III_side_info_t *const l3_side = &gfc->l3_side; + gr_info *const cod_info = &l3_side->tt[gr][ch]; + + /* try some better scalefac storage + */ + best_scalefac_store(gfc, gr, ch, l3_side); + + /* best huffman_divide may save some bits too + */ + if (cfg->use_best_huffman == 1) + best_huffman_divide(gfc, cod_info); + + /* update reservoir status after FINAL quantization/bitrate + */ + ResvAdjust(gfc, cod_info); +} + + + +/********************************************************************* + * + * VBR_encode_granule() + * + * 2000-09-04 Robert Hegemann + * + *********************************************************************/ + +static void +VBR_encode_granule(lame_internal_flags * gfc, gr_info * const cod_info, const FLOAT * const l3_xmin, /* allowed distortion of the scalefactor */ + FLOAT xrpow[576], /* coloured magnitudes of spectral values */ + const int ch, int min_bits, int max_bits) +{ + gr_info bst_cod_info; + FLOAT bst_xrpow[576]; + int const Max_bits = max_bits; + int real_bits = max_bits + 1; + int this_bits = (max_bits + min_bits) / 2; + int dbits, over, found = 0; + int const sfb21_extra = gfc->sv_qnt.sfb21_extra; + + assert(Max_bits <= MAX_BITS_PER_CHANNEL); + memset(bst_cod_info.l3_enc, 0, sizeof(bst_cod_info.l3_enc)); + + /* search within round about 40 bits of optimal + */ + do { + assert(this_bits >= min_bits); + assert(this_bits <= max_bits); + assert(min_bits <= max_bits); + + if (this_bits > Max_bits - 42) + gfc->sv_qnt.sfb21_extra = 0; + else + gfc->sv_qnt.sfb21_extra = sfb21_extra; + + over = outer_loop(gfc, cod_info, l3_xmin, xrpow, ch, this_bits); + + /* is quantization as good as we are looking for ? + * in this case: is no scalefactor band distorted? + */ + if (over <= 0) { + found = 1; + /* now we know it can be done with "real_bits" + * and maybe we can skip some iterations + */ + real_bits = cod_info->part2_3_length; + + /* store best quantization so far + */ + bst_cod_info = *cod_info; + memcpy(bst_xrpow, xrpow, sizeof(FLOAT) * 576); + + /* try with fewer bits + */ + max_bits = real_bits - 32; + dbits = max_bits - min_bits; + this_bits = (max_bits + min_bits) / 2; + } + else { + /* try with more bits + */ + min_bits = this_bits + 32; + dbits = max_bits - min_bits; + this_bits = (max_bits + min_bits) / 2; + + if (found) { + found = 2; + /* start again with best quantization so far + */ + *cod_info = bst_cod_info; + memcpy(xrpow, bst_xrpow, sizeof(FLOAT) * 576); + } + } + } while (dbits > 12); + + gfc->sv_qnt.sfb21_extra = sfb21_extra; + + /* found=0 => nothing found, use last one + * found=1 => we just found the best and left the loop + * found=2 => we restored a good one and have now l3_enc to restore too + */ + if (found == 2) { + memcpy(cod_info->l3_enc, bst_cod_info.l3_enc, sizeof(int) * 576); + } + assert(cod_info->part2_3_length <= Max_bits); + +} + + + +/************************************************************************ + * + * get_framebits() + * + * Robert Hegemann 2000-09-05 + * + * calculates + * * how many bits are available for analog silent granules + * * how many bits to use for the lowest allowed bitrate + * * how many bits each bitrate would provide + * + ************************************************************************/ + +static void +get_framebits(lame_internal_flags * gfc, int frameBits[15]) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncResult_t *const eov = &gfc->ov_enc; + int bitsPerFrame, i; + + /* always use at least this many bits per granule per channel + * unless we detect analog silence, see below + */ + eov->bitrate_index = cfg->vbr_min_bitrate_index; + bitsPerFrame = getframebits(gfc); + + /* bits for analog silence + */ + eov->bitrate_index = 1; + bitsPerFrame = getframebits(gfc); + + for (i = 1; i <= cfg->vbr_max_bitrate_index; i++) { + eov->bitrate_index = i; + frameBits[i] = ResvFrameBegin(gfc, &bitsPerFrame); + } +} + + + +/********************************************************************* + * + * VBR_prepare() + * + * 2000-09-04 Robert Hegemann + * + * * converts LR to MS coding when necessary + * * calculates allowed/adjusted quantization noise amounts + * * detects analog silent frames + * + * some remarks: + * - lower masking depending on Quality setting + * - quality control together with adjusted ATH MDCT scaling + * on lower quality setting allocate more noise from + * ATH masking, and on higher quality setting allocate + * less noise from ATH masking. + * - experiments show that going more than 2dB over GPSYCHO's + * limits ends up in very annoying artefacts + * + *********************************************************************/ + +/* RH: this one needs to be overhauled sometime */ + +static int +VBR_old_prepare(lame_internal_flags * gfc, + const FLOAT pe[2][2], FLOAT const ms_ener_ratio[2], + const III_psy_ratio ratio[2][2], + FLOAT l3_xmin[2][2][SFBMAX], + int frameBits[16], int min_bits[2][2], int max_bits[2][2], int bands[2][2]) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncResult_t *const eov = &gfc->ov_enc; + + FLOAT masking_lower_db, adjust = 0.0; + int gr, ch; + int analog_silence = 1; + int avg, mxb, bits = 0; + + eov->bitrate_index = cfg->vbr_max_bitrate_index; + avg = ResvFrameBegin(gfc, &avg) / cfg->mode_gr; + + get_framebits(gfc, frameBits); + + for (gr = 0; gr < cfg->mode_gr; gr++) { + mxb = on_pe(gfc, pe, max_bits[gr], avg, gr, 0); + if (gfc->ov_enc.mode_ext == MPG_MD_MS_LR) { + ms_convert(&gfc->l3_side, gr); + reduce_side(max_bits[gr], ms_ener_ratio[gr], avg, mxb); + } + for (ch = 0; ch < cfg->channels_out; ++ch) { + gr_info *const cod_info = &gfc->l3_side.tt[gr][ch]; + + if (cod_info->block_type != SHORT_TYPE) { /* NORM, START or STOP type */ + adjust = 1.28 / (1 + exp(3.5 - pe[gr][ch] / 300.)) - 0.05; + masking_lower_db = gfc->sv_qnt.mask_adjust - adjust; + } + else { + adjust = 2.56 / (1 + exp(3.5 - pe[gr][ch] / 300.)) - 0.14; + masking_lower_db = gfc->sv_qnt.mask_adjust_short - adjust; + } + gfc->sv_qnt.masking_lower = pow(10.0, masking_lower_db * 0.1); + + init_outer_loop(gfc, cod_info); + bands[gr][ch] = calc_xmin(gfc, &ratio[gr][ch], cod_info, l3_xmin[gr][ch]); + if (bands[gr][ch]) + analog_silence = 0; + + min_bits[gr][ch] = 126; + + bits += max_bits[gr][ch]; + } + } + for (gr = 0; gr < cfg->mode_gr; gr++) { + for (ch = 0; ch < cfg->channels_out; ch++) { + if (bits > frameBits[cfg->vbr_max_bitrate_index] && bits > 0) { + max_bits[gr][ch] *= frameBits[cfg->vbr_max_bitrate_index]; + max_bits[gr][ch] /= bits; + } + if (min_bits[gr][ch] > max_bits[gr][ch]) + min_bits[gr][ch] = max_bits[gr][ch]; + + } /* for ch */ + } /* for gr */ + + return analog_silence; +} + +static void +bitpressure_strategy(lame_internal_flags const *gfc, + FLOAT l3_xmin[2][2][SFBMAX], const int min_bits[2][2], int max_bits[2][2]) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + int gr, ch, sfb; + for (gr = 0; gr < cfg->mode_gr; gr++) { + for (ch = 0; ch < cfg->channels_out; ch++) { + gr_info const *const gi = &gfc->l3_side.tt[gr][ch]; + FLOAT *pxmin = l3_xmin[gr][ch]; + for (sfb = 0; sfb < gi->psy_lmax; sfb++) + *pxmin++ *= 1. + .029 * sfb * sfb / SBMAX_l / SBMAX_l; + + if (gi->block_type == SHORT_TYPE) { + for (sfb = gi->sfb_smin; sfb < SBMAX_s; sfb++) { + *pxmin++ *= 1. + .029 * sfb * sfb / SBMAX_s / SBMAX_s; + *pxmin++ *= 1. + .029 * sfb * sfb / SBMAX_s / SBMAX_s; + *pxmin++ *= 1. + .029 * sfb * sfb / SBMAX_s / SBMAX_s; + } + } + max_bits[gr][ch] = Max(min_bits[gr][ch], 0.9 * max_bits[gr][ch]); + } + } +} + +/************************************************************************ + * + * VBR_iteration_loop() + * + * tries to find out how many bits are needed for each granule and channel + * to get an acceptable quantization. An appropriate bitrate will then be + * choosed for quantization. rh 8/99 + * + * Robert Hegemann 2000-09-06 rewrite + * + ************************************************************************/ + +void +VBR_old_iteration_loop(lame_internal_flags * gfc, const FLOAT pe[2][2], + const FLOAT ms_ener_ratio[2], const III_psy_ratio ratio[2][2]) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncResult_t *const eov = &gfc->ov_enc; + FLOAT l3_xmin[2][2][SFBMAX]; + + FLOAT xrpow[576]; + int bands[2][2]; + int frameBits[15]; + int used_bits; + int bits; + int min_bits[2][2], max_bits[2][2]; + int mean_bits; + int ch, gr, analog_silence; + III_side_info_t *const l3_side = &gfc->l3_side; + + analog_silence = VBR_old_prepare(gfc, pe, ms_ener_ratio, ratio, + l3_xmin, frameBits, min_bits, max_bits, bands); + + /*---------------------------------*/ + for (;;) { + + /* quantize granules with lowest possible number of bits + */ + + used_bits = 0; + + for (gr = 0; gr < cfg->mode_gr; gr++) { + for (ch = 0; ch < cfg->channels_out; ch++) { + int ret; + gr_info *const cod_info = &l3_side->tt[gr][ch]; + + /* init_outer_loop sets up cod_info, scalefac and xrpow + */ + ret = init_xrpow(gfc, cod_info, xrpow); + if (ret == 0 || max_bits[gr][ch] == 0) { + /* xr contains no energy + * l3_enc, our encoding data, will be quantized to zero + */ + continue; /* with next channel */ + } + + VBR_encode_granule(gfc, cod_info, l3_xmin[gr][ch], xrpow, + ch, min_bits[gr][ch], max_bits[gr][ch]); + + /* do the 'substep shaping' + */ + if (gfc->sv_qnt.substep_shaping & 1) { + trancate_smallspectrums(gfc, &l3_side->tt[gr][ch], l3_xmin[gr][ch], xrpow); + } + + ret = cod_info->part2_3_length + cod_info->part2_length; + used_bits += ret; + } /* for ch */ + } /* for gr */ + + /* find lowest bitrate able to hold used bits + */ + if (analog_silence && !cfg->enforce_min_bitrate) + /* we detected analog silence and the user did not specify + * any hard framesize limit, so start with smallest possible frame + */ + eov->bitrate_index = 1; + else + eov->bitrate_index = cfg->vbr_min_bitrate_index; + + for (; eov->bitrate_index < cfg->vbr_max_bitrate_index; eov->bitrate_index++) { + if (used_bits <= frameBits[eov->bitrate_index]) + break; + } + bits = ResvFrameBegin(gfc, &mean_bits); + + if (used_bits <= bits) + break; + + bitpressure_strategy(gfc, l3_xmin, (const int (*)[2])min_bits, max_bits); + + } /* breaks adjusted */ + /*--------------------------------------*/ + + for (gr = 0; gr < cfg->mode_gr; gr++) { + for (ch = 0; ch < cfg->channels_out; ch++) { + iteration_finish_one(gfc, gr, ch); + } /* for ch */ + } /* for gr */ + ResvFrameEnd(gfc, mean_bits); +} + + + +static int +VBR_new_prepare(lame_internal_flags * gfc, + const FLOAT pe[2][2], const III_psy_ratio ratio[2][2], + FLOAT l3_xmin[2][2][SFBMAX], int frameBits[16], int max_bits[2][2], + int* max_resv) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncResult_t *const eov = &gfc->ov_enc; + + int gr, ch; + int analog_silence = 1; + int avg, bits = 0; + int maximum_framebits; + + if (!cfg->free_format) { + eov->bitrate_index = cfg->vbr_max_bitrate_index; + (void) ResvFrameBegin(gfc, &avg); + *max_resv = gfc->sv_enc.ResvMax; + + get_framebits(gfc, frameBits); + maximum_framebits = frameBits[cfg->vbr_max_bitrate_index]; + } + else { + eov->bitrate_index = 0; + maximum_framebits = ResvFrameBegin(gfc, &avg); + frameBits[0] = maximum_framebits; + *max_resv = gfc->sv_enc.ResvMax; + } + + for (gr = 0; gr < cfg->mode_gr; gr++) { + (void) on_pe(gfc, pe, max_bits[gr], avg, gr, 0); + if (gfc->ov_enc.mode_ext == MPG_MD_MS_LR) { + ms_convert(&gfc->l3_side, gr); + } + for (ch = 0; ch < cfg->channels_out; ++ch) { + gr_info *const cod_info = &gfc->l3_side.tt[gr][ch]; + + gfc->sv_qnt.masking_lower = pow(10.0, gfc->sv_qnt.mask_adjust * 0.1); + + init_outer_loop(gfc, cod_info); + if (0 != calc_xmin(gfc, &ratio[gr][ch], cod_info, l3_xmin[gr][ch])) + analog_silence = 0; + + bits += max_bits[gr][ch]; + } + } + for (gr = 0; gr < cfg->mode_gr; gr++) { + for (ch = 0; ch < cfg->channels_out; ch++) { + if (bits > maximum_framebits && bits > 0) { + max_bits[gr][ch] *= maximum_framebits; + max_bits[gr][ch] /= bits; + } + + } /* for ch */ + } /* for gr */ + if (analog_silence) { + *max_resv = 0; + } + return analog_silence; +} + + + +void +VBR_new_iteration_loop(lame_internal_flags * gfc, const FLOAT pe[2][2], + const FLOAT ms_ener_ratio[2], const III_psy_ratio ratio[2][2]) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncResult_t *const eov = &gfc->ov_enc; + FLOAT l3_xmin[2][2][SFBMAX]; + + FLOAT xrpow[2][2][576]; + int frameBits[15]; + int used_bits; + int max_bits[2][2]; + int ch, gr, analog_silence, pad; + III_side_info_t *const l3_side = &gfc->l3_side; + + const FLOAT (*const_l3_xmin)[2][SFBMAX] = (const FLOAT (*)[2][SFBMAX])l3_xmin; + const FLOAT (*const_xrpow)[2][576] = (const FLOAT (*)[2][576])xrpow; + const int (*const_max_bits)[2] = (const int (*)[2])max_bits; + + (void) ms_ener_ratio; /* not used */ + + memset(xrpow, 0, sizeof(xrpow)); + + analog_silence = VBR_new_prepare(gfc, pe, ratio, l3_xmin, frameBits, max_bits, &pad); + + for (gr = 0; gr < cfg->mode_gr; gr++) { + for (ch = 0; ch < cfg->channels_out; ch++) { + gr_info *const cod_info = &l3_side->tt[gr][ch]; + + /* init_outer_loop sets up cod_info, scalefac and xrpow + */ + if (0 == init_xrpow(gfc, cod_info, xrpow[gr][ch])) { + max_bits[gr][ch] = 0; /* silent granule needs no bits */ + } + } /* for ch */ + } /* for gr */ + + /* quantize granules with lowest possible number of bits + */ + + used_bits = VBR_encode_frame(gfc, const_xrpow, const_l3_xmin, const_max_bits); + + if (!cfg->free_format) { + int i, j; + + /* find lowest bitrate able to hold used bits + */ + if (analog_silence && !cfg->enforce_min_bitrate) { + /* we detected analog silence and the user did not specify + * any hard framesize limit, so start with smallest possible frame + */ + i = 1; + } + else { + i = cfg->vbr_min_bitrate_index; + } + + for (; i < cfg->vbr_max_bitrate_index; i++) { + if (used_bits <= frameBits[i]) + break; + } + if (i > cfg->vbr_max_bitrate_index) { + i = cfg->vbr_max_bitrate_index; + } + if (pad > 0) { + for (j = cfg->vbr_max_bitrate_index; j > i; --j) { + int const unused = frameBits[j] - used_bits; + if (unused <= pad) + break; + } + eov->bitrate_index = j; + } + else { + eov->bitrate_index = i; + } + } + else { +#if 0 + static int mmm = 0; + int fff = getFramesize_kbps(gfc, used_bits); + int hhh = getFramesize_kbps(gfc, MAX_BITS_PER_GRANULE * cfg->mode_gr); + if (mmm < fff) + mmm = fff; + printf("demand=%3d kbps max=%3d kbps limit=%3d kbps\n", fff, mmm, hhh); +#endif + eov->bitrate_index = 0; + } + if (used_bits <= frameBits[eov->bitrate_index]) { + /* update Reservoire status */ + int mean_bits, fullframebits; + fullframebits = ResvFrameBegin(gfc, &mean_bits); + assert(used_bits <= fullframebits); + for (gr = 0; gr < cfg->mode_gr; gr++) { + for (ch = 0; ch < cfg->channels_out; ch++) { + gr_info const *const cod_info = &l3_side->tt[gr][ch]; + ResvAdjust(gfc, cod_info); + } + } + ResvFrameEnd(gfc, mean_bits); + } + else { + /* SHOULD NOT HAPPEN INTERNAL ERROR + */ + ERRORF(gfc, "INTERNAL ERROR IN VBR NEW CODE, please send bug report\n"); + exit(-1); + } +} + + + + + +/******************************************************************** + * + * calc_target_bits() + * + * calculates target bits for ABR encoding + * + * mt 2000/05/31 + * + ********************************************************************/ + +static void +calc_target_bits(lame_internal_flags * gfc, + const FLOAT pe[2][2], + FLOAT const ms_ener_ratio[2], + int targ_bits[2][2], int *analog_silence_bits, int *max_frame_bits) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncResult_t *const eov = &gfc->ov_enc; + III_side_info_t const *const l3_side = &gfc->l3_side; + FLOAT res_factor; + int gr, ch, totbits, mean_bits; + int framesize = 576 * cfg->mode_gr; + + eov->bitrate_index = cfg->vbr_max_bitrate_index; + *max_frame_bits = ResvFrameBegin(gfc, &mean_bits); + + eov->bitrate_index = 1; + mean_bits = getframebits(gfc) - cfg->sideinfo_len * 8; + *analog_silence_bits = mean_bits / (cfg->mode_gr * cfg->channels_out); + + mean_bits = cfg->vbr_avg_bitrate_kbps * framesize * 1000; + if (gfc->sv_qnt.substep_shaping & 1) + mean_bits *= 1.09; + mean_bits /= cfg->samplerate_out; + mean_bits -= cfg->sideinfo_len * 8; + mean_bits /= (cfg->mode_gr * cfg->channels_out); + + /* + res_factor is the percentage of the target bitrate that should + be used on average. the remaining bits are added to the + bitreservoir and used for difficult to encode frames. + + Since we are tracking the average bitrate, we should adjust + res_factor "on the fly", increasing it if the average bitrate + is greater than the requested bitrate, and decreasing it + otherwise. Reasonable ranges are from .9 to 1.0 + + Until we get the above suggestion working, we use the following + tuning: + compression ratio res_factor + 5.5 (256kbps) 1.0 no need for bitreservoir + 11 (128kbps) .93 7% held for reservoir + + with linear interpolation for other values. + + */ + res_factor = .93 + .07 * (11.0 - cfg->compression_ratio) / (11.0 - 5.5); + if (res_factor < .90) + res_factor = .90; + if (res_factor > 1.00) + res_factor = 1.00; + + for (gr = 0; gr < cfg->mode_gr; gr++) { + int sum = 0; + for (ch = 0; ch < cfg->channels_out; ch++) { + targ_bits[gr][ch] = res_factor * mean_bits; + + if (pe[gr][ch] > 700) { + int add_bits = (pe[gr][ch] - 700) / 1.4; + + gr_info const *const cod_info = &l3_side->tt[gr][ch]; + targ_bits[gr][ch] = res_factor * mean_bits; + + /* short blocks use a little extra, no matter what the pe */ + if (cod_info->block_type == SHORT_TYPE) { + if (add_bits < mean_bits / 2) + add_bits = mean_bits / 2; + } + /* at most increase bits by 1.5*average */ + if (add_bits > mean_bits * 3 / 2) + add_bits = mean_bits * 3 / 2; + else if (add_bits < 0) + add_bits = 0; + + targ_bits[gr][ch] += add_bits; + } + if (targ_bits[gr][ch] > MAX_BITS_PER_CHANNEL) { + targ_bits[gr][ch] = MAX_BITS_PER_CHANNEL; + } + sum += targ_bits[gr][ch]; + } /* for ch */ + if (sum > MAX_BITS_PER_GRANULE) { + for (ch = 0; ch < cfg->channels_out; ++ch) { + targ_bits[gr][ch] *= MAX_BITS_PER_GRANULE; + targ_bits[gr][ch] /= sum; + } + } + } /* for gr */ + + if (gfc->ov_enc.mode_ext == MPG_MD_MS_LR) + for (gr = 0; gr < cfg->mode_gr; gr++) { + reduce_side(targ_bits[gr], ms_ener_ratio[gr], mean_bits * cfg->channels_out, + MAX_BITS_PER_GRANULE); + } + + /* sum target bits + */ + totbits = 0; + for (gr = 0; gr < cfg->mode_gr; gr++) { + for (ch = 0; ch < cfg->channels_out; ch++) { + if (targ_bits[gr][ch] > MAX_BITS_PER_CHANNEL) + targ_bits[gr][ch] = MAX_BITS_PER_CHANNEL; + totbits += targ_bits[gr][ch]; + } + } + + /* repartion target bits if needed + */ + if (totbits > *max_frame_bits && totbits > 0) { + for (gr = 0; gr < cfg->mode_gr; gr++) { + for (ch = 0; ch < cfg->channels_out; ch++) { + targ_bits[gr][ch] *= *max_frame_bits; + targ_bits[gr][ch] /= totbits; + } + } + } +} + + + + + + +/******************************************************************** + * + * ABR_iteration_loop() + * + * encode a frame with a disired average bitrate + * + * mt 2000/05/31 + * + ********************************************************************/ + +void +ABR_iteration_loop(lame_internal_flags * gfc, const FLOAT pe[2][2], + const FLOAT ms_ener_ratio[2], const III_psy_ratio ratio[2][2]) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncResult_t *const eov = &gfc->ov_enc; + FLOAT l3_xmin[SFBMAX]; + FLOAT xrpow[576]; + int targ_bits[2][2]; + int mean_bits, max_frame_bits; + int ch, gr, ath_over; + int analog_silence_bits; + gr_info *cod_info; + III_side_info_t *const l3_side = &gfc->l3_side; + + mean_bits = 0; + + calc_target_bits(gfc, pe, ms_ener_ratio, targ_bits, &analog_silence_bits, &max_frame_bits); + + /* encode granules + */ + for (gr = 0; gr < cfg->mode_gr; gr++) { + + if (gfc->ov_enc.mode_ext == MPG_MD_MS_LR) { + ms_convert(&gfc->l3_side, gr); + } + for (ch = 0; ch < cfg->channels_out; ch++) { + FLOAT adjust, masking_lower_db; + cod_info = &l3_side->tt[gr][ch]; + + if (cod_info->block_type != SHORT_TYPE) { /* NORM, START or STOP type */ + /* adjust = 1.28/(1+exp(3.5-pe[gr][ch]/300.))-0.05; */ + adjust = 0; + masking_lower_db = gfc->sv_qnt.mask_adjust - adjust; + } + else { + /* adjust = 2.56/(1+exp(3.5-pe[gr][ch]/300.))-0.14; */ + adjust = 0; + masking_lower_db = gfc->sv_qnt.mask_adjust_short - adjust; + } + gfc->sv_qnt.masking_lower = pow(10.0, masking_lower_db * 0.1); + + + /* cod_info, scalefac and xrpow get initialized in init_outer_loop + */ + init_outer_loop(gfc, cod_info); + if (init_xrpow(gfc, cod_info, xrpow)) { + /* xr contains energy we will have to encode + * calculate the masking abilities + * find some good quantization in outer_loop + */ + ath_over = calc_xmin(gfc, &ratio[gr][ch], cod_info, l3_xmin); + if (0 == ath_over) /* analog silence */ + targ_bits[gr][ch] = analog_silence_bits; + + (void) outer_loop(gfc, cod_info, l3_xmin, xrpow, ch, targ_bits[gr][ch]); + } + iteration_finish_one(gfc, gr, ch); + } /* ch */ + } /* gr */ + + /* find a bitrate which can refill the resevoir to positive size. + */ + for (eov->bitrate_index = cfg->vbr_min_bitrate_index; + eov->bitrate_index <= cfg->vbr_max_bitrate_index; eov->bitrate_index++) { + if (ResvFrameBegin(gfc, &mean_bits) >= 0) + break; + } + assert(eov->bitrate_index <= cfg->vbr_max_bitrate_index); + + ResvFrameEnd(gfc, mean_bits); +} + + + + + + +/************************************************************************ + * + * CBR_iteration_loop() + * + * author/date?? + * + * encodes one frame of MP3 data with constant bitrate + * + ************************************************************************/ + +void +CBR_iteration_loop(lame_internal_flags * gfc, const FLOAT pe[2][2], + const FLOAT ms_ener_ratio[2], const III_psy_ratio ratio[2][2]) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + FLOAT l3_xmin[SFBMAX]; + FLOAT xrpow[576]; + int targ_bits[2]; + int mean_bits, max_bits; + int gr, ch; + III_side_info_t *const l3_side = &gfc->l3_side; + gr_info *cod_info; + + (void) ResvFrameBegin(gfc, &mean_bits); + + /* quantize! */ + for (gr = 0; gr < cfg->mode_gr; gr++) { + + /* calculate needed bits + */ + max_bits = on_pe(gfc, pe, targ_bits, mean_bits, gr, gr); + + if (gfc->ov_enc.mode_ext == MPG_MD_MS_LR) { + ms_convert(&gfc->l3_side, gr); + reduce_side(targ_bits, ms_ener_ratio[gr], mean_bits, max_bits); + } + + for (ch = 0; ch < cfg->channels_out; ch++) { + FLOAT adjust, masking_lower_db; + cod_info = &l3_side->tt[gr][ch]; + + if (cod_info->block_type != SHORT_TYPE) { /* NORM, START or STOP type */ + /* adjust = 1.28/(1+exp(3.5-pe[gr][ch]/300.))-0.05; */ + adjust = 0; + masking_lower_db = gfc->sv_qnt.mask_adjust - adjust; + } + else { + /* adjust = 2.56/(1+exp(3.5-pe[gr][ch]/300.))-0.14; */ + adjust = 0; + masking_lower_db = gfc->sv_qnt.mask_adjust_short - adjust; + } + gfc->sv_qnt.masking_lower = pow(10.0, masking_lower_db * 0.1); + + /* init_outer_loop sets up cod_info, scalefac and xrpow + */ + init_outer_loop(gfc, cod_info); + if (init_xrpow(gfc, cod_info, xrpow)) { + /* xr contains energy we will have to encode + * calculate the masking abilities + * find some good quantization in outer_loop + */ + (void) calc_xmin(gfc, &ratio[gr][ch], cod_info, l3_xmin); + (void) outer_loop(gfc, cod_info, l3_xmin, xrpow, ch, targ_bits[ch]); + } + + iteration_finish_one(gfc, gr, ch); + assert(cod_info->part2_3_length <= MAX_BITS_PER_CHANNEL); + assert(cod_info->part2_3_length <= targ_bits[ch]); + } /* for ch */ + } /* for gr */ + + ResvFrameEnd(gfc, mean_bits); +} diff --git a/pkg/lame/clame/quantize.h b/pkg/lame/clame/quantize.h new file mode 100644 index 0000000..56edcc7 --- /dev/null +++ b/pkg/lame/clame/quantize.h @@ -0,0 +1,38 @@ +/* + * MP3 quantization + * + * Copyright (c) 1999 Mark Taylor + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef LAME_QUANTIZE_H +#define LAME_QUANTIZE_H + +void CBR_iteration_loop(lame_internal_flags * gfc, const FLOAT pe[2][2], + const FLOAT ms_ratio[2], const III_psy_ratio ratio[2][2]); + +void VBR_old_iteration_loop(lame_internal_flags * gfc, const FLOAT pe[2][2], + const FLOAT ms_ratio[2], const III_psy_ratio ratio[2][2]); + +void VBR_new_iteration_loop(lame_internal_flags * gfc, const FLOAT pe[2][2], + const FLOAT ms_ratio[2], const III_psy_ratio ratio[2][2]); + +void ABR_iteration_loop(lame_internal_flags * gfc, const FLOAT pe[2][2], + const FLOAT ms_ratio[2], const III_psy_ratio ratio[2][2]); + + +#endif /* LAME_QUANTIZE_H */ diff --git a/pkg/lame/clame/quantize_pvt.c b/pkg/lame/clame/quantize_pvt.c new file mode 100644 index 0000000..d8d6447 --- /dev/null +++ b/pkg/lame/clame/quantize_pvt.c @@ -0,0 +1,1074 @@ +/* + * quantize_pvt source file + * + * Copyright (c) 1999-2002 Takehiro Tominaga + * Copyright (c) 2000-2012 Robert Hegemann + * Copyright (c) 2001 Naoki Shibata + * Copyright (c) 2002-2005 Gabriel Bouvigne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* $Id: quantize_pvt.c,v 1.175 2017/09/06 15:07:30 robert Exp $ */ +#ifdef HAVE_CONFIG_H +# include +#endif + + +#include "lame.h" +#include "machine.h" +#include "encoder.h" +#include "util.h" +#include "quantize_pvt.h" +#include "reservoir.h" +#include "lame-analysis.h" +#include + + +#define NSATHSCALE 100 /* Assuming dynamic range=96dB, this value should be 92 */ + +/* + The following table is used to implement the scalefactor + partitioning for MPEG2 as described in section + 2.4.3.2 of the IS. The indexing corresponds to the + way the tables are presented in the IS: + + [table_number][row_in_table][column of nr_of_sfb] +*/ +const int nr_of_sfb_block[6][3][4] = { + { + {6, 5, 5, 5}, + {9, 9, 9, 9}, + {6, 9, 9, 9} + }, + { + {6, 5, 7, 3}, + {9, 9, 12, 6}, + {6, 9, 12, 6} + }, + { + {11, 10, 0, 0}, + {18, 18, 0, 0}, + {15, 18, 0, 0} + }, + { + {7, 7, 7, 0}, + {12, 12, 12, 0}, + {6, 15, 12, 0} + }, + { + {6, 6, 6, 3}, + {12, 9, 9, 6}, + {6, 12, 9, 6} + }, + { + {8, 8, 5, 0}, + {15, 12, 9, 0}, + {6, 18, 9, 0} + } +}; + + +/* Table B.6: layer3 preemphasis */ +const int pretab[SBMAX_l] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 2, 2, 3, 3, 3, 2, 0 +}; + +/* + Here are MPEG1 Table B.8 and MPEG2 Table B.1 + -- Layer III scalefactor bands. + Index into this using a method such as: + idx = fr_ps->header->sampling_frequency + + (fr_ps->header->version * 3) +*/ + + +const scalefac_struct sfBandIndex[9] = { + { /* Table B.2.b: 22.05 kHz */ + {0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464, + 522, 576}, + {0, 4, 8, 12, 18, 24, 32, 42, 56, 74, 100, 132, 174, 192} + , {0, 0, 0, 0, 0, 0, 0} /* sfb21 pseudo sub bands */ + , {0, 0, 0, 0, 0, 0, 0} /* sfb12 pseudo sub bands */ + }, + { /* Table B.2.c: 24 kHz */ /* docs: 332. mpg123(broken): 330 */ + {0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 114, 136, 162, 194, 232, 278, 332, 394, 464, + 540, 576}, + {0, 4, 8, 12, 18, 26, 36, 48, 62, 80, 104, 136, 180, 192} + , {0, 0, 0, 0, 0, 0, 0} /* sfb21 pseudo sub bands */ + , {0, 0, 0, 0, 0, 0, 0} /* sfb12 pseudo sub bands */ + }, + { /* Table B.2.a: 16 kHz */ + {0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464, + 522, 576}, + {0, 4, 8, 12, 18, 26, 36, 48, 62, 80, 104, 134, 174, 192} + , {0, 0, 0, 0, 0, 0, 0} /* sfb21 pseudo sub bands */ + , {0, 0, 0, 0, 0, 0, 0} /* sfb12 pseudo sub bands */ + }, + { /* Table B.8.b: 44.1 kHz */ + {0, 4, 8, 12, 16, 20, 24, 30, 36, 44, 52, 62, 74, 90, 110, 134, 162, 196, 238, 288, 342, 418, + 576}, + {0, 4, 8, 12, 16, 22, 30, 40, 52, 66, 84, 106, 136, 192} + , {0, 0, 0, 0, 0, 0, 0} /* sfb21 pseudo sub bands */ + , {0, 0, 0, 0, 0, 0, 0} /* sfb12 pseudo sub bands */ + }, + { /* Table B.8.c: 48 kHz */ + {0, 4, 8, 12, 16, 20, 24, 30, 36, 42, 50, 60, 72, 88, 106, 128, 156, 190, 230, 276, 330, 384, + 576}, + {0, 4, 8, 12, 16, 22, 28, 38, 50, 64, 80, 100, 126, 192} + , {0, 0, 0, 0, 0, 0, 0} /* sfb21 pseudo sub bands */ + , {0, 0, 0, 0, 0, 0, 0} /* sfb12 pseudo sub bands */ + }, + { /* Table B.8.a: 32 kHz */ + {0, 4, 8, 12, 16, 20, 24, 30, 36, 44, 54, 66, 82, 102, 126, 156, 194, 240, 296, 364, 448, 550, + 576}, + {0, 4, 8, 12, 16, 22, 30, 42, 58, 78, 104, 138, 180, 192} + , {0, 0, 0, 0, 0, 0, 0} /* sfb21 pseudo sub bands */ + , {0, 0, 0, 0, 0, 0, 0} /* sfb12 pseudo sub bands */ + }, + { /* MPEG-2.5 11.025 kHz */ + {0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464, + 522, 576}, + {0 / 3, 12 / 3, 24 / 3, 36 / 3, 54 / 3, 78 / 3, 108 / 3, 144 / 3, 186 / 3, 240 / 3, 312 / 3, + 402 / 3, 522 / 3, 576 / 3} + , {0, 0, 0, 0, 0, 0, 0} /* sfb21 pseudo sub bands */ + , {0, 0, 0, 0, 0, 0, 0} /* sfb12 pseudo sub bands */ + }, + { /* MPEG-2.5 12 kHz */ + {0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 116, 140, 168, 200, 238, 284, 336, 396, 464, + 522, 576}, + {0 / 3, 12 / 3, 24 / 3, 36 / 3, 54 / 3, 78 / 3, 108 / 3, 144 / 3, 186 / 3, 240 / 3, 312 / 3, + 402 / 3, 522 / 3, 576 / 3} + , {0, 0, 0, 0, 0, 0, 0} /* sfb21 pseudo sub bands */ + , {0, 0, 0, 0, 0, 0, 0} /* sfb12 pseudo sub bands */ + }, + { /* MPEG-2.5 8 kHz */ + {0, 12, 24, 36, 48, 60, 72, 88, 108, 132, 160, 192, 232, 280, 336, 400, 476, 566, 568, 570, + 572, 574, 576}, + {0 / 3, 24 / 3, 48 / 3, 72 / 3, 108 / 3, 156 / 3, 216 / 3, 288 / 3, 372 / 3, 480 / 3, 486 / 3, + 492 / 3, 498 / 3, 576 / 3} + , {0, 0, 0, 0, 0, 0, 0} /* sfb21 pseudo sub bands */ + , {0, 0, 0, 0, 0, 0, 0} /* sfb12 pseudo sub bands */ + } +}; + + +/* FIXME: move global variables in some struct */ + +FLOAT pow20[Q_MAX + Q_MAX2 + 1]; +FLOAT ipow20[Q_MAX]; +FLOAT pow43[PRECALC_SIZE]; +/* initialized in first call to iteration_init */ +#ifdef TAKEHIRO_IEEE754_HACK +FLOAT adj43asm[PRECALC_SIZE]; +#else +FLOAT adj43[PRECALC_SIZE]; +#endif + +/* +compute the ATH for each scalefactor band +cd range: 0..96db + +Input: 3.3kHz signal 32767 amplitude (3.3kHz is where ATH is smallest = -5db) +longblocks: sfb=12 en0/bw=-11db max_en0 = 1.3db +shortblocks: sfb=5 -9db 0db + +Input: 1 1 1 1 1 1 1 -1 -1 -1 -1 -1 -1 -1 (repeated) +longblocks: amp=1 sfb=12 en0/bw=-103 db max_en0 = -92db + amp=32767 sfb=12 -12 db -1.4db + +Input: 1 1 1 1 1 1 1 -1 -1 -1 -1 -1 -1 -1 (repeated) +shortblocks: amp=1 sfb=5 en0/bw= -99 -86 + amp=32767 sfb=5 -9 db 4db + + +MAX energy of largest wave at 3.3kHz = 1db +AVE energy of largest wave at 3.3kHz = -11db +Let's take AVE: -11db = maximum signal in sfb=12. +Dynamic range of CD: 96db. Therefor energy of smallest audible wave +in sfb=12 = -11 - 96 = -107db = ATH at 3.3kHz. + +ATH formula for this wave: -5db. To adjust to LAME scaling, we need +ATH = ATH_formula - 103 (db) +ATH = ATH * 2.5e-10 (ener) + +*/ + +static FLOAT +ATHmdct(SessionConfig_t const *cfg, FLOAT f) +{ + FLOAT ath; + + ath = ATHformula(cfg, f); + + if (cfg->ATHfixpoint > 0) { + ath -= cfg->ATHfixpoint; + } + else { + ath -= NSATHSCALE; + } + ath += cfg->ATH_offset_db; + + /* modify the MDCT scaling for the ATH and convert to energy */ + ath = powf(10.0f, ath * 0.1f); + return ath; +} + +static void +compute_ath(lame_internal_flags const* gfc) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + FLOAT *const ATH_l = gfc->ATH->l; + FLOAT *const ATH_psfb21 = gfc->ATH->psfb21; + FLOAT *const ATH_s = gfc->ATH->s; + FLOAT *const ATH_psfb12 = gfc->ATH->psfb12; + int sfb, i, start, end; + FLOAT ATH_f; + FLOAT const samp_freq = cfg->samplerate_out; + + for (sfb = 0; sfb < SBMAX_l; sfb++) { + start = gfc->scalefac_band.l[sfb]; + end = gfc->scalefac_band.l[sfb + 1]; + ATH_l[sfb] = FLOAT_MAX; + for (i = start; i < end; i++) { + FLOAT const freq = i * samp_freq / (2 * 576); + ATH_f = ATHmdct(cfg, freq); /* freq in kHz */ + ATH_l[sfb] = Min(ATH_l[sfb], ATH_f); + } + } + + for (sfb = 0; sfb < PSFB21; sfb++) { + start = gfc->scalefac_band.psfb21[sfb]; + end = gfc->scalefac_band.psfb21[sfb + 1]; + ATH_psfb21[sfb] = FLOAT_MAX; + for (i = start; i < end; i++) { + FLOAT const freq = i * samp_freq / (2 * 576); + ATH_f = ATHmdct(cfg, freq); /* freq in kHz */ + ATH_psfb21[sfb] = Min(ATH_psfb21[sfb], ATH_f); + } + } + + for (sfb = 0; sfb < SBMAX_s; sfb++) { + start = gfc->scalefac_band.s[sfb]; + end = gfc->scalefac_band.s[sfb + 1]; + ATH_s[sfb] = FLOAT_MAX; + for (i = start; i < end; i++) { + FLOAT const freq = i * samp_freq / (2 * 192); + ATH_f = ATHmdct(cfg, freq); /* freq in kHz */ + ATH_s[sfb] = Min(ATH_s[sfb], ATH_f); + } + ATH_s[sfb] *= (gfc->scalefac_band.s[sfb + 1] - gfc->scalefac_band.s[sfb]); + } + + for (sfb = 0; sfb < PSFB12; sfb++) { + start = gfc->scalefac_band.psfb12[sfb]; + end = gfc->scalefac_band.psfb12[sfb + 1]; + ATH_psfb12[sfb] = FLOAT_MAX; + for (i = start; i < end; i++) { + FLOAT const freq = i * samp_freq / (2 * 192); + ATH_f = ATHmdct(cfg, freq); /* freq in kHz */ + ATH_psfb12[sfb] = Min(ATH_psfb12[sfb], ATH_f); + } + /*not sure about the following */ + ATH_psfb12[sfb] *= (gfc->scalefac_band.s[13] - gfc->scalefac_band.s[12]); + } + + + /* no-ATH mode: + * reduce ATH to -200 dB + */ + + if (cfg->noATH) { + for (sfb = 0; sfb < SBMAX_l; sfb++) { + ATH_l[sfb] = 1E-20; + } + for (sfb = 0; sfb < PSFB21; sfb++) { + ATH_psfb21[sfb] = 1E-20; + } + for (sfb = 0; sfb < SBMAX_s; sfb++) { + ATH_s[sfb] = 1E-20; + } + for (sfb = 0; sfb < PSFB12; sfb++) { + ATH_psfb12[sfb] = 1E-20; + } + } + + /* work in progress, don't rely on it too much + */ + gfc->ATH->floor = 10. * log10(ATHmdct(cfg, -1.)); + + /* + { FLOAT g=10000, t=1e30, x; + for ( f = 100; f < 10000; f++ ) { + x = ATHmdct( cfg, f ); + if ( t > x ) t = x, g = f; + } + printf("min=%g\n", g); + } */ +} + + +static float const payload_long[2][4] = +{ {-0.000f, -0.000f, -0.000f, +0.000f} +, {-0.500f, -0.250f, -0.025f, +0.500f} +}; +static float const payload_short[2][4] = +{ {-0.000f, -0.000f, -0.000f, +0.000f} +, {-2.000f, -1.000f, -0.050f, +0.500f} +}; + +/************************************************************************/ +/* initialization for iteration_loop */ +/************************************************************************/ +void +iteration_init(lame_internal_flags * gfc) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + III_side_info_t *const l3_side = &gfc->l3_side; + FLOAT adjust, db; + int i, sel; + + if (gfc->iteration_init_init == 0) { + gfc->iteration_init_init = 1; + + l3_side->main_data_begin = 0; + compute_ath(gfc); + + pow43[0] = 0.0; + for (i = 1; i < PRECALC_SIZE; i++) + pow43[i] = pow((FLOAT) i, 4.0 / 3.0); + +#ifdef TAKEHIRO_IEEE754_HACK + adj43asm[0] = 0.0; + for (i = 1; i < PRECALC_SIZE; i++) + adj43asm[i] = i - 0.5 - pow(0.5 * (pow43[i - 1] + pow43[i]), 0.75); +#else + for (i = 0; i < PRECALC_SIZE - 1; i++) + adj43[i] = (i + 1) - pow(0.5 * (pow43[i] + pow43[i + 1]), 0.75); + adj43[i] = 0.5; +#endif + for (i = 0; i < Q_MAX; i++) + ipow20[i] = pow(2.0, (double) (i - 210) * -0.1875); + for (i = 0; i <= Q_MAX + Q_MAX2; i++) + pow20[i] = pow(2.0, (double) (i - 210 - Q_MAX2) * 0.25); + + huffman_init(gfc); + init_xrpow_core_init(gfc); + + sel = 1;/* RH: all modes like vbr-new (cfg->vbr == vbr_mt || cfg->vbr == vbr_mtrh) ? 1 : 0;*/ + + /* long */ + db = cfg->adjust_bass_db + payload_long[sel][0]; + adjust = powf(10.f, db * 0.1f); + for (i = 0; i <= 6; ++i) { + gfc->sv_qnt.longfact[i] = adjust; + } + db = cfg->adjust_alto_db + payload_long[sel][1]; + adjust = powf(10.f, db * 0.1f); + for (; i <= 13; ++i) { + gfc->sv_qnt.longfact[i] = adjust; + } + db = cfg->adjust_treble_db + payload_long[sel][2]; + adjust = powf(10.f, db * 0.1f); + for (; i <= 20; ++i) { + gfc->sv_qnt.longfact[i] = adjust; + } + db = cfg->adjust_sfb21_db + payload_long[sel][3]; + adjust = powf(10.f, db * 0.1f); + for (; i < SBMAX_l; ++i) { + gfc->sv_qnt.longfact[i] = adjust; + } + + /* short */ + db = cfg->adjust_bass_db + payload_short[sel][0]; + adjust = powf(10.f, db * 0.1f); + for (i = 0; i <= 2; ++i) { + gfc->sv_qnt.shortfact[i] = adjust; + } + db = cfg->adjust_alto_db + payload_short[sel][1]; + adjust = powf(10.f, db * 0.1f); + for (; i <= 6; ++i) { + gfc->sv_qnt.shortfact[i] = adjust; + } + db = cfg->adjust_treble_db + payload_short[sel][2]; + adjust = powf(10.f, db * 0.1f); + for (; i <= 11; ++i) { + gfc->sv_qnt.shortfact[i] = adjust; + } + db = cfg->adjust_sfb21_db + payload_short[sel][3]; + adjust = powf(10.f, db * 0.1f); + for (; i < SBMAX_s; ++i) { + gfc->sv_qnt.shortfact[i] = adjust; + } + } +} + + + + + +/************************************************************************ + * allocate bits among 2 channels based on PE + * mt 6/99 + * bugfixes rh 8/01: often allocated more than the allowed 4095 bits + ************************************************************************/ +int +on_pe(lame_internal_flags * gfc, const FLOAT pe[][2], int targ_bits[2], int mean_bits, int gr, int cbr) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + int extra_bits = 0, tbits, bits; + int add_bits[2] = {0, 0}; + int max_bits; /* maximum allowed bits for this granule */ + int ch; + + /* allocate targ_bits for granule */ + ResvMaxBits(gfc, mean_bits, &tbits, &extra_bits, cbr); + max_bits = tbits + extra_bits; + if (max_bits > MAX_BITS_PER_GRANULE) /* hard limit per granule */ + max_bits = MAX_BITS_PER_GRANULE; + + for (bits = 0, ch = 0; ch < cfg->channels_out; ++ch) { + /****************************************************************** + * allocate bits for each channel + ******************************************************************/ + targ_bits[ch] = Min(MAX_BITS_PER_CHANNEL, tbits / cfg->channels_out); + + add_bits[ch] = targ_bits[ch] * pe[gr][ch] / 700.0 - targ_bits[ch]; + + /* at most increase bits by 1.5*average */ + if (add_bits[ch] > mean_bits * 3 / 4) + add_bits[ch] = mean_bits * 3 / 4; + if (add_bits[ch] < 0) + add_bits[ch] = 0; + + if (add_bits[ch] + targ_bits[ch] > MAX_BITS_PER_CHANNEL) + add_bits[ch] = Max(0, MAX_BITS_PER_CHANNEL - targ_bits[ch]); + + bits += add_bits[ch]; + } + if (bits > extra_bits && bits > 0) { + for (ch = 0; ch < cfg->channels_out; ++ch) { + add_bits[ch] = extra_bits * add_bits[ch] / bits; + } + } + + for (ch = 0; ch < cfg->channels_out; ++ch) { + targ_bits[ch] += add_bits[ch]; + extra_bits -= add_bits[ch]; + } + + for (bits = 0, ch = 0; ch < cfg->channels_out; ++ch) { + bits += targ_bits[ch]; + } + if (bits > MAX_BITS_PER_GRANULE) { + int sum = 0; + for (ch = 0; ch < cfg->channels_out; ++ch) { + targ_bits[ch] *= MAX_BITS_PER_GRANULE; + targ_bits[ch] /= bits; + sum += targ_bits[ch]; + } + assert(sum <= MAX_BITS_PER_GRANULE); + } + + return max_bits; +} + + + + +void +reduce_side(int targ_bits[2], FLOAT ms_ener_ratio, int mean_bits, int max_bits) +{ + int move_bits; + FLOAT fac; + + assert(max_bits <= MAX_BITS_PER_GRANULE); + assert(targ_bits[0] + targ_bits[1] <= MAX_BITS_PER_GRANULE); + + /* ms_ener_ratio = 0: allocate 66/33 mid/side fac=.33 + * ms_ener_ratio =.5: allocate 50/50 mid/side fac= 0 */ + /* 75/25 split is fac=.5 */ + /* float fac = .50*(.5-ms_ener_ratio[gr])/.5; */ + fac = .33 * (.5 - ms_ener_ratio) / .5; + if (fac < 0) + fac = 0; + if (fac > .5) + fac = .5; + + /* number of bits to move from side channel to mid channel */ + /* move_bits = fac*targ_bits[1]; */ + move_bits = fac * .5 * (targ_bits[0] + targ_bits[1]); + + if (move_bits > MAX_BITS_PER_CHANNEL - targ_bits[0]) { + move_bits = MAX_BITS_PER_CHANNEL - targ_bits[0]; + } + if (move_bits < 0) + move_bits = 0; + + if (targ_bits[1] >= 125) { + /* dont reduce side channel below 125 bits */ + if (targ_bits[1] - move_bits > 125) { + + /* if mid channel already has 2x more than average, dont bother */ + /* mean_bits = bits per granule (for both channels) */ + if (targ_bits[0] < mean_bits) + targ_bits[0] += move_bits; + targ_bits[1] -= move_bits; + } + else { + targ_bits[0] += targ_bits[1] - 125; + targ_bits[1] = 125; + } + } + + move_bits = targ_bits[0] + targ_bits[1]; + if (move_bits > max_bits) { + targ_bits[0] = (max_bits * targ_bits[0]) / move_bits; + targ_bits[1] = (max_bits * targ_bits[1]) / move_bits; + } + assert(targ_bits[0] <= MAX_BITS_PER_CHANNEL); + assert(targ_bits[1] <= MAX_BITS_PER_CHANNEL); + assert(targ_bits[0] + targ_bits[1] <= MAX_BITS_PER_GRANULE); +} + + +/** + * Robert Hegemann 2001-04-27: + * this adjusts the ATH, keeping the original noise floor + * affects the higher frequencies more than the lower ones + */ + +FLOAT +athAdjust(FLOAT a, FLOAT x, FLOAT athFloor, float ATHfixpoint) +{ + /* work in progress + */ + FLOAT const o = 90.30873362f; + FLOAT const p = (ATHfixpoint < 1.f) ? 94.82444863f : ATHfixpoint; + FLOAT u = FAST_LOG10_X(x, 10.0f); + FLOAT const v = a * a; + FLOAT w = 0.0f; + u -= athFloor; /* undo scaling */ + if (v > 1E-20f) + w = 1.f + FAST_LOG10_X(v, 10.0f / o); + if (w < 0) + w = 0.f; + u *= w; + u += athFloor + o - p; /* redo scaling */ + + return powf(10.f, 0.1f * u); +} + + + +/*************************************************************************/ +/* calc_xmin */ +/*************************************************************************/ + +/* + Calculate the allowed distortion for each scalefactor band, + as determined by the psychoacoustic model. + xmin(sb) = ratio(sb) * en(sb) / bw(sb) + + returns number of sfb's with energy > ATH +*/ + +int +calc_xmin(lame_internal_flags const *gfc, + III_psy_ratio const *const ratio, gr_info * const cod_info, FLOAT * pxmin) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + int sfb, gsfb, j = 0, ath_over = 0, k; + ATH_t const *const ATH = gfc->ATH; + const FLOAT *const xr = cod_info->xr; + int max_nonzero; + + for (gsfb = 0; gsfb < cod_info->psy_lmax; gsfb++) { + FLOAT en0, xmin; + FLOAT rh1, rh2, rh3; + int width, l; + + xmin = athAdjust(ATH->adjust_factor, ATH->l[gsfb], ATH->floor, cfg->ATHfixpoint); + xmin *= gfc->sv_qnt.longfact[gsfb]; + + width = cod_info->width[gsfb]; + rh1 = xmin / width; +#ifdef DBL_EPSILON + rh2 = DBL_EPSILON; +#else + rh2 = 2.2204460492503131e-016; +#endif + en0 = 0.0; + for (l = 0; l < width; ++l) { + FLOAT const xa = xr[j++]; + FLOAT const x2 = xa * xa; + en0 += x2; + rh2 += (x2 < rh1) ? x2 : rh1; + } + if (en0 > xmin) + ath_over++; + + if (en0 < xmin) { + rh3 = en0; + } + else if (rh2 < xmin) { + rh3 = xmin; + } + else { + rh3 = rh2; + } + xmin = rh3; + { + FLOAT const e = ratio->en.l[gsfb]; + if (e > 1e-12f) { + FLOAT x; + x = en0 * ratio->thm.l[gsfb] / e; + x *= gfc->sv_qnt.longfact[gsfb]; + if (xmin < x) + xmin = x; + } + } + xmin = Max(xmin, DBL_EPSILON); + cod_info->energy_above_cutoff[gsfb] = (en0 > xmin+1e-14f) ? 1 : 0; + *pxmin++ = xmin; + } /* end of long block loop */ + + + + + /*use this function to determine the highest non-zero coeff */ + max_nonzero = 0; + for (k = 575; k > 0; --k) { + if (fabs(xr[k]) > 1e-12f) { + max_nonzero = k; + break; + } + } + if (cod_info->block_type != SHORT_TYPE) { /* NORM, START or STOP type, but not SHORT */ + max_nonzero |= 1; /* only odd numbers */ + } + else { + max_nonzero /= 6; /* 3 short blocks */ + max_nonzero *= 6; + max_nonzero += 5; + } + + if (gfc->sv_qnt.sfb21_extra == 0 && cfg->samplerate_out < 44000) { + int const sfb_l = (cfg->samplerate_out <= 8000) ? 17 : 21; + int const sfb_s = (cfg->samplerate_out <= 8000) ? 9 : 12; + int limit = 575; + if (cod_info->block_type != SHORT_TYPE) { /* NORM, START or STOP type, but not SHORT */ + limit = gfc->scalefac_band.l[sfb_l]-1; + } + else { + limit = 3*gfc->scalefac_band.s[sfb_s]-1; + } + if (max_nonzero > limit) { + max_nonzero = limit; + } + } + cod_info->max_nonzero_coeff = max_nonzero; + + + + for (sfb = cod_info->sfb_smin; gsfb < cod_info->psymax; sfb++, gsfb += 3) { + int width, b, l; + FLOAT tmpATH; + + tmpATH = athAdjust(ATH->adjust_factor, ATH->s[sfb], ATH->floor, cfg->ATHfixpoint); + tmpATH *= gfc->sv_qnt.shortfact[sfb]; + + width = cod_info->width[gsfb]; + for (b = 0; b < 3; b++) { + FLOAT en0 = 0.0, xmin = tmpATH; + FLOAT rh1, rh2, rh3; + + rh1 = tmpATH / width; +#ifdef DBL_EPSILON + rh2 = DBL_EPSILON; +#else + rh2 = 2.2204460492503131e-016; +#endif + for (l = 0; l < width; ++l) { + FLOAT const xa = xr[j++]; + FLOAT const x2 = xa * xa; + en0 += x2; + rh2 += (x2 < rh1) ? x2 : rh1; + } + if (en0 > tmpATH) + ath_over++; + + if (en0 < tmpATH) { + rh3 = en0; + } + else if (rh2 < tmpATH) { + rh3 = tmpATH; + } + else { + rh3 = rh2; + } + xmin = rh3; + { + FLOAT const e = ratio->en.s[sfb][b]; + if (e > 1e-12f) { + FLOAT x; + x = en0 * ratio->thm.s[sfb][b] / e; + x *= gfc->sv_qnt.shortfact[sfb]; + if (xmin < x) + xmin = x; + } + } + xmin = Max(xmin, DBL_EPSILON); + cod_info->energy_above_cutoff[gsfb+b] = (en0 > xmin+1e-14f) ? 1 : 0; + *pxmin++ = xmin; + } /* b */ + if (cfg->use_temporal_masking_effect) { + if (pxmin[-3] > pxmin[-3 + 1]) + pxmin[-3 + 1] += (pxmin[-3] - pxmin[-3 + 1]) * gfc->cd_psy->decay; + if (pxmin[-3 + 1] > pxmin[-3 + 2]) + pxmin[-3 + 2] += (pxmin[-3 + 1] - pxmin[-3 + 2]) * gfc->cd_psy->decay; + } + } /* end of short block sfb loop */ + + return ath_over; +} + + +static FLOAT +calc_noise_core_c(const gr_info * const cod_info, int *startline, int l, FLOAT step) +{ + FLOAT noise = 0; + int j = *startline; + const int *const ix = cod_info->l3_enc; + + if (j > cod_info->count1) { + while (l--) { + FLOAT temp; + temp = cod_info->xr[j]; + j++; + noise += temp * temp; + temp = cod_info->xr[j]; + j++; + noise += temp * temp; + } + } + else if (j > cod_info->big_values) { + FLOAT ix01[2]; + ix01[0] = 0; + ix01[1] = step; + while (l--) { + FLOAT temp; + temp = fabs(cod_info->xr[j]) - ix01[ix[j]]; + j++; + noise += temp * temp; + temp = fabs(cod_info->xr[j]) - ix01[ix[j]]; + j++; + noise += temp * temp; + } + } + else { + while (l--) { + FLOAT temp; + temp = fabs(cod_info->xr[j]) - pow43[ix[j]] * step; + j++; + noise += temp * temp; + temp = fabs(cod_info->xr[j]) - pow43[ix[j]] * step; + j++; + noise += temp * temp; + } + } + + *startline = j; + return noise; +} + + +/*************************************************************************/ +/* calc_noise */ +/*************************************************************************/ + +/* -oo dB => -1.00 */ +/* - 6 dB => -0.97 */ +/* - 3 dB => -0.80 */ +/* - 2 dB => -0.64 */ +/* - 1 dB => -0.38 */ +/* 0 dB => 0.00 */ +/* + 1 dB => +0.49 */ +/* + 2 dB => +1.06 */ +/* + 3 dB => +1.68 */ +/* + 6 dB => +3.69 */ +/* +10 dB => +6.45 */ + +int +calc_noise(gr_info const *const cod_info, + FLOAT const *l3_xmin, + FLOAT * distort, calc_noise_result * const res, calc_noise_data * prev_noise) +{ + int sfb, l, over = 0; + FLOAT over_noise_db = 0; + FLOAT tot_noise_db = 0; /* 0 dB relative to masking */ + FLOAT max_noise = -20.0; /* -200 dB relative to masking */ + int j = 0; + const int *scalefac = cod_info->scalefac; + + res->over_SSD = 0; + + + for (sfb = 0; sfb < cod_info->psymax; sfb++) { + int const s = + cod_info->global_gain - (((*scalefac++) + (cod_info->preflag ? pretab[sfb] : 0)) + << (cod_info->scalefac_scale + 1)) + - cod_info->subblock_gain[cod_info->window[sfb]] * 8; + FLOAT const r_l3_xmin = 1.f / *l3_xmin++; + FLOAT distort_ = 0.0f; + FLOAT noise = 0.0f; + + if (prev_noise && (prev_noise->step[sfb] == s)) { + + /* use previously computed values */ + j += cod_info->width[sfb]; + distort_ = r_l3_xmin * prev_noise->noise[sfb]; + + noise = prev_noise->noise_log[sfb]; + + } + else { + FLOAT const step = POW20(s); + l = cod_info->width[sfb] >> 1; + + if ((j + cod_info->width[sfb]) > cod_info->max_nonzero_coeff) { + int usefullsize; + usefullsize = cod_info->max_nonzero_coeff - j + 1; + + if (usefullsize > 0) + l = usefullsize >> 1; + else + l = 0; + } + + noise = calc_noise_core_c(cod_info, &j, l, step); + + + if (prev_noise) { + /* save noise values */ + prev_noise->step[sfb] = s; + prev_noise->noise[sfb] = noise; + } + + distort_ = r_l3_xmin * noise; + + /* multiplying here is adding in dB, but can overflow */ + noise = FAST_LOG10(Max(distort_, 1E-20f)); + + if (prev_noise) { + /* save noise values */ + prev_noise->noise_log[sfb] = noise; + } + } + *distort++ = distort_; + + if (prev_noise) { + /* save noise values */ + prev_noise->global_gain = cod_info->global_gain;; + } + + + /*tot_noise *= Max(noise, 1E-20); */ + tot_noise_db += noise; + + if (noise > 0.0) { + int tmp; + + tmp = Max((int) (noise * 10 + .5), 1); + res->over_SSD += tmp * tmp; + + over++; + /* multiplying here is adding in dB -but can overflow */ + /*over_noise *= noise; */ + over_noise_db += noise; + } + max_noise = Max(max_noise, noise); + + } + + res->over_count = over; + res->tot_noise = tot_noise_db; + res->over_noise = over_noise_db; + res->max_noise = max_noise; + + return over; +} + + + + + + + + +/************************************************************************ + * + * set_pinfo() + * + * updates plotting data + * + * Mark Taylor 2000-??-?? + * + * Robert Hegemann: moved noise/distortion calc into it + * + ************************************************************************/ + +static void +set_pinfo(lame_internal_flags const *gfc, + gr_info * const cod_info, const III_psy_ratio * const ratio, const int gr, const int ch) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + int sfb, sfb2; + int j, i, l, start, end, bw; + FLOAT en0, en1; + FLOAT const ifqstep = (cod_info->scalefac_scale == 0) ? .5 : 1.0; + int const *const scalefac = cod_info->scalefac; + + FLOAT l3_xmin[SFBMAX], xfsf[SFBMAX]; + calc_noise_result noise; + + (void) calc_xmin(gfc, ratio, cod_info, l3_xmin); + (void) calc_noise(cod_info, l3_xmin, xfsf, &noise, 0); + + j = 0; + sfb2 = cod_info->sfb_lmax; + if (cod_info->block_type != SHORT_TYPE && !cod_info->mixed_block_flag) + sfb2 = 22; + for (sfb = 0; sfb < sfb2; sfb++) { + start = gfc->scalefac_band.l[sfb]; + end = gfc->scalefac_band.l[sfb + 1]; + bw = end - start; + for (en0 = 0.0; j < end; j++) + en0 += cod_info->xr[j] * cod_info->xr[j]; + en0 /= bw; + /* convert to MDCT units */ + en1 = 1e15; /* scaling so it shows up on FFT plot */ + gfc->pinfo->en[gr][ch][sfb] = en1 * en0; + gfc->pinfo->xfsf[gr][ch][sfb] = en1 * l3_xmin[sfb] * xfsf[sfb] / bw; + + if (ratio->en.l[sfb] > 0 && !cfg->ATHonly) + en0 = en0 / ratio->en.l[sfb]; + else + en0 = 0.0; + + gfc->pinfo->thr[gr][ch][sfb] = en1 * Max(en0 * ratio->thm.l[sfb], gfc->ATH->l[sfb]); + + /* there is no scalefactor bands >= SBPSY_l */ + gfc->pinfo->LAMEsfb[gr][ch][sfb] = 0; + if (cod_info->preflag && sfb >= 11) + gfc->pinfo->LAMEsfb[gr][ch][sfb] = -ifqstep * pretab[sfb]; + + if (sfb < SBPSY_l) { + assert(scalefac[sfb] >= 0); /* scfsi should be decoded by caller side */ + gfc->pinfo->LAMEsfb[gr][ch][sfb] -= ifqstep * scalefac[sfb]; + } + } /* for sfb */ + + if (cod_info->block_type == SHORT_TYPE) { + sfb2 = sfb; + for (sfb = cod_info->sfb_smin; sfb < SBMAX_s; sfb++) { + start = gfc->scalefac_band.s[sfb]; + end = gfc->scalefac_band.s[sfb + 1]; + bw = end - start; + for (i = 0; i < 3; i++) { + for (en0 = 0.0, l = start; l < end; l++) { + en0 += cod_info->xr[j] * cod_info->xr[j]; + j++; + } + en0 = Max(en0 / bw, 1e-20); + /* convert to MDCT units */ + en1 = 1e15; /* scaling so it shows up on FFT plot */ + + gfc->pinfo->en_s[gr][ch][3 * sfb + i] = en1 * en0; + gfc->pinfo->xfsf_s[gr][ch][3 * sfb + i] = en1 * l3_xmin[sfb2] * xfsf[sfb2] / bw; + if (ratio->en.s[sfb][i] > 0) + en0 = en0 / ratio->en.s[sfb][i]; + else + en0 = 0.0; + if (cfg->ATHonly || cfg->ATHshort) + en0 = 0; + + gfc->pinfo->thr_s[gr][ch][3 * sfb + i] = + en1 * Max(en0 * ratio->thm.s[sfb][i], gfc->ATH->s[sfb]); + + /* there is no scalefactor bands >= SBPSY_s */ + gfc->pinfo->LAMEsfb_s[gr][ch][3 * sfb + i] + = -2.0 * cod_info->subblock_gain[i]; + if (sfb < SBPSY_s) { + gfc->pinfo->LAMEsfb_s[gr][ch][3 * sfb + i] -= ifqstep * scalefac[sfb2]; + } + sfb2++; + } + } + } /* block type short */ + gfc->pinfo->LAMEqss[gr][ch] = cod_info->global_gain; + gfc->pinfo->LAMEmainbits[gr][ch] = cod_info->part2_3_length + cod_info->part2_length; + gfc->pinfo->LAMEsfbits[gr][ch] = cod_info->part2_length; + + gfc->pinfo->over[gr][ch] = noise.over_count; + gfc->pinfo->max_noise[gr][ch] = noise.max_noise * 10.0; + gfc->pinfo->over_noise[gr][ch] = noise.over_noise * 10.0; + gfc->pinfo->tot_noise[gr][ch] = noise.tot_noise * 10.0; + gfc->pinfo->over_SSD[gr][ch] = noise.over_SSD; +} + + +/************************************************************************ + * + * set_frame_pinfo() + * + * updates plotting data for a whole frame + * + * Robert Hegemann 2000-10-21 + * + ************************************************************************/ + +void +set_frame_pinfo(lame_internal_flags * gfc, const III_psy_ratio ratio[2][2]) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + int ch; + int gr; + + /* for every granule and channel patch l3_enc and set info + */ + for (gr = 0; gr < cfg->mode_gr; gr++) { + for (ch = 0; ch < cfg->channels_out; ch++) { + gr_info *const cod_info = &gfc->l3_side.tt[gr][ch]; + int scalefac_sav[SFBMAX]; + memcpy(scalefac_sav, cod_info->scalefac, sizeof(scalefac_sav)); + + /* reconstruct the scalefactors in case SCFSI was used + */ + if (gr == 1) { + int sfb; + for (sfb = 0; sfb < cod_info->sfb_lmax; sfb++) { + if (cod_info->scalefac[sfb] < 0) /* scfsi */ + cod_info->scalefac[sfb] = gfc->l3_side.tt[0][ch].scalefac[sfb]; + } + } + + set_pinfo(gfc, cod_info, &ratio[gr][ch], gr, ch); + memcpy(cod_info->scalefac, scalefac_sav, sizeof(scalefac_sav)); + } /* for ch */ + } /* for gr */ +} diff --git a/pkg/lame/clame/quantize_pvt.h b/pkg/lame/clame/quantize_pvt.h new file mode 100644 index 0000000..b8333e7 --- /dev/null +++ b/pkg/lame/clame/quantize_pvt.h @@ -0,0 +1,128 @@ +/* + * quantize_pvt include file + * + * Copyright (c) 1999 Takehiro TOMINAGA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef LAME_QUANTIZE_PVT_H +#define LAME_QUANTIZE_PVT_H + +#define IXMAX_VAL 8206 /* ix always <= 8191+15. see count_bits() */ + +/* buggy Winamp decoder cannot handle values > 8191 */ +/* #define IXMAX_VAL 8191 */ + +#define PRECALC_SIZE (IXMAX_VAL+2) + + +extern const int nr_of_sfb_block[6][3][4]; +extern const int pretab[SBMAX_l]; +extern const int slen1_tab[16]; +extern const int slen2_tab[16]; + +extern const scalefac_struct sfBandIndex[9]; + +extern FLOAT pow43[PRECALC_SIZE]; +#ifdef TAKEHIRO_IEEE754_HACK +extern FLOAT adj43asm[PRECALC_SIZE]; +#else +extern FLOAT adj43[PRECALC_SIZE]; +#endif + +#define Q_MAX (256+1) +#define Q_MAX2 116 /* minimum possible number of + -cod_info->global_gain + + ((scalefac[] + (cod_info->preflag ? pretab[sfb] : 0)) + << (cod_info->scalefac_scale + 1)) + + cod_info->subblock_gain[cod_info->window[sfb]] * 8; + + for long block, 0+((15+3)<<2) = 18*4 = 72 + for short block, 0+(15<<2)+7*8 = 15*4+56 = 116 + */ + +extern FLOAT pow20[Q_MAX + Q_MAX2 + 1]; +extern FLOAT ipow20[Q_MAX]; + +typedef struct calc_noise_result_t { + FLOAT over_noise; /* sum of quantization noise > masking */ + FLOAT tot_noise; /* sum of all quantization noise */ + FLOAT max_noise; /* max quantization noise */ + int over_count; /* number of quantization noise > masking */ + int over_SSD; /* SSD-like cost of distorted bands */ + int bits; +} calc_noise_result; + + +/** +* allows re-use of previously +* computed noise values +*/ +typedef struct calc_noise_data_t { + int global_gain; + int sfb_count1; + int step[39]; + FLOAT noise[39]; + FLOAT noise_log[39]; +} calc_noise_data; + + +int on_pe(lame_internal_flags * gfc, const FLOAT pe[2][2], + int targ_bits[2], int mean_bits, int gr, int cbr); + +void reduce_side(int targ_bits[2], FLOAT ms_ener_ratio, int mean_bits, int max_bits); + + +void iteration_init(lame_internal_flags * gfc); + + +int calc_xmin(lame_internal_flags const *gfc, + III_psy_ratio const *const ratio, gr_info * const cod_info, FLOAT * l3_xmin); + +int calc_noise(const gr_info * const cod_info, + const FLOAT * l3_xmin, + FLOAT * distort, calc_noise_result * const res, calc_noise_data * prev_noise); + +void set_frame_pinfo(lame_internal_flags * gfc, const III_psy_ratio ratio[2][2]); + + + + +/* takehiro.c */ + +int count_bits(lame_internal_flags const *const gfc, const FLOAT * const xr, + gr_info * const cod_info, calc_noise_data * prev_noise); +int noquant_count_bits(lame_internal_flags const *const gfc, + gr_info * const cod_info, calc_noise_data * prev_noise); + + +void best_huffman_divide(const lame_internal_flags * const gfc, gr_info * const cod_info); + +void best_scalefac_store(const lame_internal_flags * gfc, const int gr, const int ch, + III_side_info_t * const l3_side); + +int scale_bitcount(const lame_internal_flags * gfc, gr_info * cod_info); + +void huffman_init(lame_internal_flags * const gfc); + +void init_xrpow_core_init(lame_internal_flags * const gfc); + +FLOAT athAdjust(FLOAT a, FLOAT x, FLOAT athFloor, float ATHfixpoint); + +#define LARGE_BITS 100000 + +#endif /* LAME_QUANTIZE_PVT_H */ diff --git a/pkg/lame/clame/reservoir.c b/pkg/lame/clame/reservoir.c new file mode 100644 index 0000000..4fdaa8d --- /dev/null +++ b/pkg/lame/clame/reservoir.c @@ -0,0 +1,293 @@ +/* + * bit reservoir source file + * + * Copyright (c) 1999-2000 Mark Taylor + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* $Id: reservoir.c,v 1.45 2011/05/07 16:05:17 rbrito Exp $ */ + +#ifdef HAVE_CONFIG_H +# include +#endif + + +#include "lame.h" +#include "machine.h" +#include "encoder.h" +#include "util.h" +#include "reservoir.h" + +#include "bitstream.h" +#include "lame-analysis.h" +#include "lame_global_flags.h" + + +/* + ResvFrameBegin: + Called (repeatedly) at the beginning of a frame. Updates the maximum + size of the reservoir, and checks to make sure main_data_begin + was set properly by the formatter +*/ + +/* + * Background information: + * + * This is the original text from the ISO standard. Because of + * sooo many bugs and irritations correcting comments are added + * in brackets []. A '^W' means you should remove the last word. + * + * 1) The following rule can be used to calculate the maximum + * number of bits used for one granule [^W frame]: + * At the highest possible bitrate of Layer III (320 kbps + * per stereo signal [^W^W^W], 48 kHz) the frames must be of + * [^W^W^W are designed to have] constant length, i.e. + * one buffer [^W^W the frame] length is: + * + * 320 kbps * 1152/48 kHz = 7680 bit = 960 byte + * + * This value is used as the maximum buffer per channel [^W^W] at + * lower bitrates [than 320 kbps]. At 64 kbps mono or 128 kbps + * stereo the main granule length is 64 kbps * 576/48 kHz = 768 bit + * [per granule and channel] at 48 kHz sampling frequency. + * This means that there is a maximum deviation (short time buffer + * [= reservoir]) of 7680 - 2*2*768 = 4608 bits is allowed at 64 kbps. + * The actual deviation is equal to the number of bytes [with the + * meaning of octets] denoted by the main_data_end offset pointer. + * The actual maximum deviation is (2^9-1)*8 bit = 4088 bits + * [for MPEG-1 and (2^8-1)*8 bit for MPEG-2, both are hard limits]. + * ... The xchange of buffer bits between the left and right channel + * is allowed without restrictions [exception: dual channel]. + * Because of the [constructed] constraint on the buffer size + * main_data_end is always set to 0 in the case of bit_rate_index==14, + * i.e. data rate 320 kbps per stereo signal [^W^W^W]. In this case + * all data are allocated between adjacent header [^W sync] words + * [, i.e. there is no buffering at all]. + */ + +int +ResvFrameBegin(lame_internal_flags * gfc, int *mean_bits) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncStateVar_t *const esv = &gfc->sv_enc; + int fullFrameBits; + int resvLimit; + int maxmp3buf; + III_side_info_t *const l3_side = &gfc->l3_side; + int frameLength; + int meanBits; + + frameLength = getframebits(gfc); + meanBits = (frameLength - cfg->sideinfo_len * 8) / cfg->mode_gr; + +/* + * Meaning of the variables: + * resvLimit: (0, 8, ..., 8*255 (MPEG-2), 8*511 (MPEG-1)) + * Number of bits can be stored in previous frame(s) due to + * counter size constaints + * maxmp3buf: ( ??? ... 8*1951 (MPEG-1 and 2), 8*2047 (MPEG-2.5)) + * Number of bits allowed to encode one frame (you can take 8*511 bit + * from the bit reservoir and at most 8*1440 bit from the current + * frame (320 kbps, 32 kHz), so 8*1951 bit is the largest possible + * value for MPEG-1 and -2) + * + * maximum allowed granule/channel size times 4 = 8*2047 bits., + * so this is the absolute maximum supported by the format. + * + * + * fullFrameBits: maximum number of bits available for encoding + * the current frame. + * + * mean_bits: target number of bits per granule. + * + * frameLength: + * + * gfc->ResvMax: maximum allowed reservoir + * + * gfc->ResvSize: current reservoir size + * + * l3_side->resvDrain_pre: + * ancillary data to be added to previous frame: + * (only usefull in VBR modes if it is possible to have + * maxmp3buf < fullFrameBits)). Currently disabled, + * see #define NEW_DRAIN + * 2010-02-13: RH now enabled, it seems to be needed for CBR too, + * as there exists one example, where the FhG decoder + * can't decode a -b320 CBR file anymore. + * + * l3_side->resvDrain_post: + * ancillary data to be added to this frame: + * + */ + + /* main_data_begin has 9 bits in MPEG-1, 8 bits MPEG-2 */ + resvLimit = (8 * 256) * cfg->mode_gr - 8; + + /* maximum allowed frame size. dont use more than this number of + bits, even if the frame has the space for them: */ + maxmp3buf = cfg->buffer_constraint; + esv->ResvMax = maxmp3buf - frameLength; + if (esv->ResvMax > resvLimit) + esv->ResvMax = resvLimit; + if (esv->ResvMax < 0 || cfg->disable_reservoir) + esv->ResvMax = 0; + + fullFrameBits = meanBits * cfg->mode_gr + Min(esv->ResvSize, esv->ResvMax); + + if (fullFrameBits > maxmp3buf) + fullFrameBits = maxmp3buf; + + assert(0 == esv->ResvMax % 8); + assert(esv->ResvMax >= 0); + + l3_side->resvDrain_pre = 0; + + if (gfc->pinfo != NULL) { + gfc->pinfo->mean_bits = meanBits / 2; /* expected bits per channel per granule [is this also right for mono/stereo, MPEG-1/2 ?] */ + gfc->pinfo->resvsize = esv->ResvSize; + } + *mean_bits = meanBits; + return fullFrameBits; +} + + +/* + ResvMaxBits + returns targ_bits: target number of bits to use for 1 granule + extra_bits: amount extra available from reservoir + Mark Taylor 4/99 +*/ +void +ResvMaxBits(lame_internal_flags * gfc, int mean_bits, int *targ_bits, int *extra_bits, int cbr) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncStateVar_t *const esv = &gfc->sv_enc; + int add_bits, targBits, extraBits; + int ResvSize = esv->ResvSize, ResvMax = esv->ResvMax; + + /* conpensate the saved bits used in the 1st granule */ + if (cbr) + ResvSize += mean_bits; + + if (gfc->sv_qnt.substep_shaping & 1) + ResvMax *= 0.9; + + targBits = mean_bits; + + /* extra bits if the reservoir is almost full */ + if (ResvSize * 10 > ResvMax * 9) { + add_bits = ResvSize - (ResvMax * 9) / 10; + targBits += add_bits; + gfc->sv_qnt.substep_shaping |= 0x80; + } + else { + add_bits = 0; + gfc->sv_qnt.substep_shaping &= 0x7f; + /* build up reservoir. this builds the reservoir a little slower + * than FhG. It could simple be mean_bits/15, but this was rigged + * to always produce 100 (the old value) at 128kbs */ + /* *targ_bits -= (int) (mean_bits/15.2); */ + if (!cfg->disable_reservoir && !(gfc->sv_qnt.substep_shaping & 1)) + targBits -= .1 * mean_bits; + } + + + /* amount from the reservoir we are allowed to use. ISO says 6/10 */ + extraBits = (ResvSize < (esv->ResvMax * 6) / 10 ? ResvSize : (esv->ResvMax * 6) / 10); + extraBits -= add_bits; + + if (extraBits < 0) + extraBits = 0; + + *targ_bits = targBits; + *extra_bits = extraBits; +} + +/* + ResvAdjust: + Called after a granule's bit allocation. Readjusts the size of + the reservoir to reflect the granule's usage. +*/ +void +ResvAdjust(lame_internal_flags * gfc, gr_info const *gi) +{ + gfc->sv_enc.ResvSize -= gi->part2_3_length + gi->part2_length; +} + + +/* + ResvFrameEnd: + Called after all granules in a frame have been allocated. Makes sure + that the reservoir size is within limits, possibly by adding stuffing + bits. +*/ +void +ResvFrameEnd(lame_internal_flags * gfc, int mean_bits) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncStateVar_t *const esv = &gfc->sv_enc; + III_side_info_t *const l3_side = &gfc->l3_side; + int stuffingBits; + int over_bits; + + esv->ResvSize += mean_bits * cfg->mode_gr; + stuffingBits = 0; + l3_side->resvDrain_post = 0; + l3_side->resvDrain_pre = 0; + + /* we must be byte aligned */ + if ((over_bits = esv->ResvSize % 8) != 0) + stuffingBits += over_bits; + + + over_bits = (esv->ResvSize - stuffingBits) - esv->ResvMax; + if (over_bits > 0) { + assert(0 == over_bits % 8); + assert(over_bits >= 0); + stuffingBits += over_bits; + } + + + /* NOTE: enabling the NEW_DRAIN code fixes some problems with FhG decoder + shipped with MS Windows operating systems. Using this, it is even + possible to use Gabriel's lax buffer consideration again, which + assumes, any decoder should have a buffer large enough + for a 320 kbps frame at 32 kHz sample rate. + + old drain code: + lame -b320 BlackBird.wav ---> does not play with GraphEdit.exe using FhG decoder V1.5 Build 50 + + new drain code: + lame -b320 BlackBird.wav ---> plays fine with GraphEdit.exe using FhG decoder V1.5 Build 50 + + Robert Hegemann, 2010-02-13. + */ + /* drain as many bits as possible into previous frame ancillary data + * In particular, in VBR mode ResvMax may have changed, and we have + * to make sure main_data_begin does not create a reservoir bigger + * than ResvMax mt 4/00*/ + { + int mdb_bytes = Min(l3_side->main_data_begin * 8, stuffingBits) / 8; + l3_side->resvDrain_pre += 8 * mdb_bytes; + stuffingBits -= 8 * mdb_bytes; + esv->ResvSize -= 8 * mdb_bytes; + l3_side->main_data_begin -= mdb_bytes; + } + /* drain the rest into this frames ancillary data */ + l3_side->resvDrain_post += stuffingBits; + esv->ResvSize -= stuffingBits; +} diff --git a/pkg/lame/clame/reservoir.h b/pkg/lame/clame/reservoir.h new file mode 100644 index 0000000..7c58593 --- /dev/null +++ b/pkg/lame/clame/reservoir.h @@ -0,0 +1,31 @@ +/* + * bit reservoir include file + * + * Copyright (c) 1999 Mark Taylor + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef LAME_RESERVOIR_H +#define LAME_RESERVOIR_H + +int ResvFrameBegin(lame_internal_flags * gfc, int *mean_bits); +void ResvMaxBits(lame_internal_flags * gfc, int mean_bits, int *targ_bits, int *max_bits, + int cbr); +void ResvAdjust(lame_internal_flags * gfc, gr_info const *gi); +void ResvFrameEnd(lame_internal_flags * gfc, int mean_bits); + +#endif /* LAME_RESERVOIR_H */ diff --git a/pkg/lame/clame/set_get.c b/pkg/lame/clame/set_get.c new file mode 100644 index 0000000..f763900 --- /dev/null +++ b/pkg/lame/clame/set_get.c @@ -0,0 +1,2346 @@ +/* -*- mode: C; mode: fold -*- */ +/* + * set/get functions for lame_global_flags + * + * Copyright (c) 2001-2005 Alexander Leidinger + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* $Id: set_get.c,v 1.104 2017/09/06 15:07:30 robert Exp $ */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "lame.h" +#include "machine.h" +#include "encoder.h" +#include "util.h" +#include "bitstream.h" /* because of compute_flushbits */ + +#include "set_get.h" +#include "lame_global_flags.h" + +/* + * input stream description + */ + + +/* number of samples */ +/* it's unlikely for this function to return an error */ +int +lame_set_num_samples(lame_global_flags * gfp, unsigned long num_samples) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 2^32-1 */ + gfp->num_samples = num_samples; + return 0; + } + return -1; +} + +unsigned long +lame_get_num_samples(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->num_samples; + } + return 0; +} + + +/* input samplerate */ +int +lame_set_in_samplerate(lame_global_flags * gfp, int in_samplerate) +{ + if (is_lame_global_flags_valid(gfp)) { + if (in_samplerate < 1) + return -1; + /* input sample rate in Hz, default = 44100 Hz */ + gfp->samplerate_in = in_samplerate; + return 0; + } + return -1; +} + +int +lame_get_in_samplerate(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->samplerate_in; + } + return 0; +} + + +/* number of channels in input stream */ +int +lame_set_num_channels(lame_global_flags * gfp, int num_channels) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 2 */ + if (2 < num_channels || 0 >= num_channels) { + return -1; /* we don't support more than 2 channels */ + } + gfp->num_channels = num_channels; + return 0; + } + return -1; +} + +int +lame_get_num_channels(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->num_channels; + } + return 0; +} + + +/* scale the input by this amount before encoding (not used for decoding) */ +int +lame_set_scale(lame_global_flags * gfp, float scale) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 1 */ + gfp->scale = scale; + return 0; + } + return -1; +} + +float +lame_get_scale(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->scale; + } + return 0; +} + + +/* scale the channel 0 (left) input by this amount before + encoding (not used for decoding) */ +int +lame_set_scale_left(lame_global_flags * gfp, float scale) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 1 */ + gfp->scale_left = scale; + return 0; + } + return -1; +} + +float +lame_get_scale_left(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->scale_left; + } + return 0; +} + + +/* scale the channel 1 (right) input by this amount before + encoding (not used for decoding) */ +int +lame_set_scale_right(lame_global_flags * gfp, float scale) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 1 */ + gfp->scale_right = scale; + return 0; + } + return -1; +} + +float +lame_get_scale_right(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->scale_right; + } + return 0; +} + + +/* output sample rate in Hz */ +int +lame_set_out_samplerate(lame_global_flags * gfp, int out_samplerate) +{ + if (is_lame_global_flags_valid(gfp)) { + /* + * default = 0: LAME picks best value based on the amount + * of compression + * MPEG only allows: + * MPEG1 32, 44.1, 48khz + * MPEG2 16, 22.05, 24 + * MPEG2.5 8, 11.025, 12 + * + * (not used by decoding routines) + */ + if (out_samplerate != 0) { + int v=0; + if (SmpFrqIndex(out_samplerate, &v) < 0) + return -1; + } + gfp->samplerate_out = out_samplerate; + return 0; + } + return -1; +} + +int +lame_get_out_samplerate(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->samplerate_out; + } + return 0; +} + + + + +/* + * general control parameters + */ + +/* collect data for an MP3 frame analzyer */ +int +lame_set_analysis(lame_global_flags * gfp, int analysis) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 0 */ + + /* enforce disable/enable meaning, if we need more than two values + we need to switch to an enum to have an apropriate representation + of the possible meanings of the value */ + if (0 > analysis || 1 < analysis) + return -1; + gfp->analysis = analysis; + return 0; + } + return -1; +} + +int +lame_get_analysis(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + assert(0 <= gfp->analysis && 1 >= gfp->analysis); + return gfp->analysis; + } + return 0; +} + + +/* write a Xing VBR header frame */ +int +lame_set_bWriteVbrTag(lame_global_flags * gfp, int bWriteVbrTag) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 1 (on) for VBR/ABR modes, 0 (off) for CBR mode */ + + /* enforce disable/enable meaning, if we need more than two values + we need to switch to an enum to have an apropriate representation + of the possible meanings of the value */ + if (0 > bWriteVbrTag || 1 < bWriteVbrTag) + return -1; + gfp->write_lame_tag = bWriteVbrTag; + return 0; + } + return -1; +} + +int +lame_get_bWriteVbrTag(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + assert(0 <= gfp->write_lame_tag && 1 >= gfp->write_lame_tag); + return gfp->write_lame_tag; + } + return 0; +} + + + +/* decode only, use lame/mpglib to convert mp3 to wav */ +int +lame_set_decode_only(lame_global_flags * gfp, int decode_only) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 0 (disabled) */ + + /* enforce disable/enable meaning, if we need more than two values + we need to switch to an enum to have an apropriate representation + of the possible meanings of the value */ + if (0 > decode_only || 1 < decode_only) + return -1; + gfp->decode_only = decode_only; + return 0; + } + return -1; +} + +int +lame_get_decode_only(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + assert(0 <= gfp->decode_only && 1 >= gfp->decode_only); + return gfp->decode_only; + } + return 0; +} + + +#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED +/* 1=encode a Vorbis .ogg file. default=0 */ +/* DEPRECATED */ +int CDECL lame_set_ogg(lame_global_flags *, int); +int CDECL lame_get_ogg(const lame_global_flags *); +#else +#endif + +/* encode a Vorbis .ogg file */ +/* DEPRECATED */ +int +lame_set_ogg(lame_global_flags * gfp, int ogg) +{ + (void) gfp; + (void) ogg; + return -1; +} + +int +lame_get_ogg(const lame_global_flags * gfp) +{ + (void) gfp; + return 0; +} + + +/* + * Internal algorithm selection. + * True quality is determined by the bitrate but this variable will effect + * quality by selecting expensive or cheap algorithms. + * quality=0..9. 0=best (very slow). 9=worst. + * recommended: 3 near-best quality, not too slow + * 5 good quality, fast + * 7 ok quality, really fast + */ +int +lame_set_quality(lame_global_flags * gfp, int quality) +{ + if (is_lame_global_flags_valid(gfp)) { + if (quality < 0) { + gfp->quality = 0; + } + else if (quality > 9) { + gfp->quality = 9; + } + else { + gfp->quality = quality; + } + return 0; + } + return -1; +} + +int +lame_get_quality(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->quality; + } + return 0; +} + + +/* mode = STEREO, JOINT_STEREO, DUAL_CHANNEL (not supported), MONO */ +int +lame_set_mode(lame_global_flags * gfp, MPEG_mode mode) +{ + if (is_lame_global_flags_valid(gfp)) { + int mpg_mode = mode; + /* default: lame chooses based on compression ratio and input channels */ + if (mpg_mode < 0 || MAX_INDICATOR <= mpg_mode) + return -1; /* Unknown MPEG mode! */ + gfp->mode = mode; + return 0; + } + return -1; +} + +MPEG_mode +lame_get_mode(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + assert(gfp->mode < MAX_INDICATOR); + return gfp->mode; + } + return NOT_SET; +} + + +#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED +/* + mode_automs. Use a M/S mode with a switching threshold based on + compression ratio + DEPRECATED +*/ +int CDECL lame_set_mode_automs(lame_global_flags *, int); +int CDECL lame_get_mode_automs(const lame_global_flags *); +#else +#endif + +/* Us a M/S mode with a switching threshold based on compression ratio */ +/* DEPRECATED */ +int +lame_set_mode_automs(lame_global_flags * gfp, int mode_automs) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 0 (disabled) */ + + /* enforce disable/enable meaning, if we need more than two values + we need to switch to an enum to have an apropriate representation + of the possible meanings of the value */ + if (0 > mode_automs || 1 < mode_automs) + return -1; + lame_set_mode(gfp, JOINT_STEREO); + return 0; + } + return -1; +} + +int +lame_get_mode_automs(const lame_global_flags * gfp) +{ + (void) gfp; + return 1; +} + + +/* + * Force M/S for all frames. For testing only. + * Requires mode = 1. + */ +int +lame_set_force_ms(lame_global_flags * gfp, int force_ms) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 0 (disabled) */ + + /* enforce disable/enable meaning, if we need more than two values + we need to switch to an enum to have an apropriate representation + of the possible meanings of the value */ + if (0 > force_ms || 1 < force_ms) + return -1; + gfp->force_ms = force_ms; + return 0; + } + return -1; +} + +int +lame_get_force_ms(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + assert(0 <= gfp->force_ms && 1 >= gfp->force_ms); + return gfp->force_ms; + } + return 0; +} + + +/* Use free_format. */ +int +lame_set_free_format(lame_global_flags * gfp, int free_format) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 0 (disabled) */ + + /* enforce disable/enable meaning, if we need more than two values + we need to switch to an enum to have an apropriate representation + of the possible meanings of the value */ + if (0 > free_format || 1 < free_format) + return -1; + gfp->free_format = free_format; + return 0; + } + return -1; +} + +int +lame_get_free_format(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + assert(0 <= gfp->free_format && 1 >= gfp->free_format); + return gfp->free_format; + } + return 0; +} + + + +/* Perform ReplayGain analysis */ +int +lame_set_findReplayGain(lame_global_flags * gfp, int findReplayGain) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 0 (disabled) */ + + /* enforce disable/enable meaning, if we need more than two values + we need to switch to an enum to have an apropriate representation + of the possible meanings of the value */ + if (0 > findReplayGain || 1 < findReplayGain) + return -1; + gfp->findReplayGain = findReplayGain; + return 0; + } + return -1; +} + +int +lame_get_findReplayGain(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + assert(0 <= gfp->findReplayGain && 1 >= gfp->findReplayGain); + return gfp->findReplayGain; + } + return 0; +} + + +/* Decode on the fly. Find the peak sample. If ReplayGain analysis is + enabled then perform it on the decoded data. */ +int +lame_set_decode_on_the_fly(lame_global_flags * gfp, int decode_on_the_fly) +{ + if (is_lame_global_flags_valid(gfp)) { +#ifndef DECODE_ON_THE_FLY + return -1; +#else + /* default = 0 (disabled) */ + + /* enforce disable/enable meaning, if we need more than two values + we need to switch to an enum to have an apropriate representation + of the possible meanings of the value */ + if (0 > decode_on_the_fly || 1 < decode_on_the_fly) + return -1; + + gfp->decode_on_the_fly = decode_on_the_fly; + + return 0; +#endif + } + return -1; +} + +int +lame_get_decode_on_the_fly(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + assert(0 <= gfp->decode_on_the_fly && 1 >= gfp->decode_on_the_fly); + return gfp->decode_on_the_fly; + } + return 0; +} + +#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED +/* DEPRECATED: now does the same as lame_set_findReplayGain() + default = 0 (disabled) */ +int CDECL lame_set_ReplayGain_input(lame_global_flags *, int); +int CDECL lame_get_ReplayGain_input(const lame_global_flags *); + +/* DEPRECATED: now does the same as + lame_set_decode_on_the_fly() && lame_set_findReplayGain() + default = 0 (disabled) */ +int CDECL lame_set_ReplayGain_decode(lame_global_flags *, int); +int CDECL lame_get_ReplayGain_decode(const lame_global_flags *); + +/* DEPRECATED: now does the same as lame_set_decode_on_the_fly() + default = 0 (disabled) */ +int CDECL lame_set_findPeakSample(lame_global_flags *, int); +int CDECL lame_get_findPeakSample(const lame_global_flags *); +#else +#endif + +/* DEPRECATED. same as lame_set_decode_on_the_fly() */ +int +lame_set_findPeakSample(lame_global_flags * gfp, int arg) +{ + return lame_set_decode_on_the_fly(gfp, arg); +} + +int +lame_get_findPeakSample(const lame_global_flags * gfp) +{ + return lame_get_decode_on_the_fly(gfp); +} + +/* DEPRECATED. same as lame_set_findReplayGain() */ +int +lame_set_ReplayGain_input(lame_global_flags * gfp, int arg) +{ + return lame_set_findReplayGain(gfp, arg); +} + +int +lame_get_ReplayGain_input(const lame_global_flags * gfp) +{ + return lame_get_findReplayGain(gfp); +} + +/* DEPRECATED. same as lame_set_decode_on_the_fly() && + lame_set_findReplayGain() */ +int +lame_set_ReplayGain_decode(lame_global_flags * gfp, int arg) +{ + if (lame_set_decode_on_the_fly(gfp, arg) < 0 || lame_set_findReplayGain(gfp, arg) < 0) + return -1; + else + return 0; +} + +int +lame_get_ReplayGain_decode(const lame_global_flags * gfp) +{ + if (lame_get_decode_on_the_fly(gfp) > 0 && lame_get_findReplayGain(gfp) > 0) + return 1; + else + return 0; +} + + +/* set and get some gapless encoding flags */ + +int +lame_set_nogap_total(lame_global_flags * gfp, int the_nogap_total) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->nogap_total = the_nogap_total; + return 0; + } + return -1; +} + +int +lame_get_nogap_total(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->nogap_total; + } + return 0; +} + +int +lame_set_nogap_currentindex(lame_global_flags * gfp, int the_nogap_index) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->nogap_current = the_nogap_index; + return 0; + } + return -1; +} + +int +lame_get_nogap_currentindex(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->nogap_current; + } + return 0; +} + + +/* message handlers */ +int +lame_set_errorf(lame_global_flags * gfp, void (*func) (const char *, va_list)) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->report.errorf = func; + return 0; + } + return -1; +} + +int +lame_set_debugf(lame_global_flags * gfp, void (*func) (const char *, va_list)) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->report.debugf = func; + return 0; + } + return -1; +} + +int +lame_set_msgf(lame_global_flags * gfp, void (*func) (const char *, va_list)) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->report.msgf = func; + return 0; + } + return -1; +} + + +/* + * Set one of + * - brate + * - compression ratio. + * + * Default is compression ratio of 11. + */ +int +lame_set_brate(lame_global_flags * gfp, int brate) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->brate = brate; + if (brate > 320) { + gfp->disable_reservoir = 1; + } + return 0; + } + return -1; +} + +int +lame_get_brate(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->brate; + } + return 0; +} + +int +lame_set_compression_ratio(lame_global_flags * gfp, float compression_ratio) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->compression_ratio = compression_ratio; + return 0; + } + return -1; +} + +float +lame_get_compression_ratio(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->compression_ratio; + } + return 0; +} + + + + +/* + * frame parameters + */ + +/* Mark as copyright protected. */ +int +lame_set_copyright(lame_global_flags * gfp, int copyright) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 0 (disabled) */ + + /* enforce disable/enable meaning, if we need more than two values + we need to switch to an enum to have an apropriate representation + of the possible meanings of the value */ + if (0 > copyright || 1 < copyright) + return -1; + gfp->copyright = copyright; + return 0; + } + return -1; +} + +int +lame_get_copyright(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + assert(0 <= gfp->copyright && 1 >= gfp->copyright); + return gfp->copyright; + } + return 0; +} + + +/* Mark as original. */ +int +lame_set_original(lame_global_flags * gfp, int original) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 1 (enabled) */ + + /* enforce disable/enable meaning, if we need more than two values + we need to switch to an enum to have an apropriate representation + of the possible meanings of the value */ + if (0 > original || 1 < original) + return -1; + gfp->original = original; + return 0; + } + return -1; +} + +int +lame_get_original(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + assert(0 <= gfp->original && 1 >= gfp->original); + return gfp->original; + } + return 0; +} + + +/* + * error_protection. + * Use 2 bytes from each frame for CRC checksum. + */ +int +lame_set_error_protection(lame_global_flags * gfp, int error_protection) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 0 (disabled) */ + + /* enforce disable/enable meaning, if we need more than two values + we need to switch to an enum to have an apropriate representation + of the possible meanings of the value */ + if (0 > error_protection || 1 < error_protection) + return -1; + gfp->error_protection = error_protection; + return 0; + } + return -1; +} + +int +lame_get_error_protection(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + assert(0 <= gfp->error_protection && 1 >= gfp->error_protection); + return gfp->error_protection; + } + return 0; +} + + +#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED +/* padding_type. 0=pad no frames 1=pad all frames 2=adjust padding(default) */ +int CDECL lame_set_padding_type(lame_global_flags *, Padding_type); +Padding_type CDECL lame_get_padding_type(const lame_global_flags *); +#else +#endif + +/* + * padding_type. + * PAD_NO = pad no frames + * PAD_ALL = pad all frames + * PAD_ADJUST = adjust padding + */ +int +lame_set_padding_type(lame_global_flags * gfp, Padding_type padding_type) +{ + (void) gfp; + (void) padding_type; + return 0; +} + +Padding_type +lame_get_padding_type(const lame_global_flags * gfp) +{ + (void) gfp; + return PAD_ADJUST; +} + + +/* MP3 'private extension' bit. Meaningless. */ +int +lame_set_extension(lame_global_flags * gfp, int extension) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 0 (disabled) */ + /* enforce disable/enable meaning, if we need more than two values + we need to switch to an enum to have an apropriate representation + of the possible meanings of the value */ + if (0 > extension || 1 < extension) + return -1; + gfp->extension = extension; + return 0; + } + return -1; +} + +int +lame_get_extension(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + assert(0 <= gfp->extension && 1 >= gfp->extension); + return gfp->extension; + } + return 0; +} + + +/* Enforce strict ISO compliance. */ +int +lame_set_strict_ISO(lame_global_flags * gfp, int val) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 0 (disabled) */ + /* enforce disable/enable meaning, if we need more than two values + we need to switch to an enum to have an apropriate representation + of the possible meanings of the value */ + if (val < MDB_DEFAULT || MDB_MAXIMUM < val) + return -1; + gfp->strict_ISO = val; + return 0; + } + return -1; +} + +int +lame_get_strict_ISO(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->strict_ISO; + } + return 0; +} + + + + +/******************************************************************** + * quantization/noise shaping + ***********************************************************************/ + +/* Disable the bit reservoir. For testing only. */ +int +lame_set_disable_reservoir(lame_global_flags * gfp, int disable_reservoir) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 0 (disabled) */ + + /* enforce disable/enable meaning, if we need more than two values + we need to switch to an enum to have an apropriate representation + of the possible meanings of the value */ + if (0 > disable_reservoir || 1 < disable_reservoir) + return -1; + gfp->disable_reservoir = disable_reservoir; + return 0; + } + return -1; +} + +int +lame_get_disable_reservoir(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + assert(0 <= gfp->disable_reservoir && 1 >= gfp->disable_reservoir); + return gfp->disable_reservoir; + } + return 0; +} + + + + +int +lame_set_experimentalX(lame_global_flags * gfp, int experimentalX) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_set_quant_comp(gfp, experimentalX); + lame_set_quant_comp_short(gfp, experimentalX); + return 0; + } + return -1; +} + +int +lame_get_experimentalX(const lame_global_flags * gfp) +{ + return lame_get_quant_comp(gfp); +} + + +/* Select a different "best quantization" function. default = 0 */ +int +lame_set_quant_comp(lame_global_flags * gfp, int quant_type) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->quant_comp = quant_type; + return 0; + } + return -1; +} + +int +lame_get_quant_comp(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->quant_comp; + } + return 0; +} + + +/* Select a different "best quantization" function. default = 0 */ +int +lame_set_quant_comp_short(lame_global_flags * gfp, int quant_type) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->quant_comp_short = quant_type; + return 0; + } + return -1; +} + +int +lame_get_quant_comp_short(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->quant_comp_short; + } + return 0; +} + + +/* Another experimental option. For testing only. */ +int +lame_set_experimentalY(lame_global_flags * gfp, int experimentalY) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->experimentalY = experimentalY; + return 0; + } + return -1; +} + +int +lame_get_experimentalY(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->experimentalY; + } + return 0; +} + + +int +lame_set_experimentalZ(lame_global_flags * gfp, int experimentalZ) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->experimentalZ = experimentalZ; + return 0; + } + return -1; +} + +int +lame_get_experimentalZ(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->experimentalZ; + } + return 0; +} + + +/* Naoki's psycho acoustic model. */ +int +lame_set_exp_nspsytune(lame_global_flags * gfp, int exp_nspsytune) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 0 (disabled) */ + gfp->exp_nspsytune = exp_nspsytune; + return 0; + } + return -1; +} + +int +lame_get_exp_nspsytune(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->exp_nspsytune; + } + return 0; +} + + + + +/******************************************************************** + * VBR control + ***********************************************************************/ + +/* Types of VBR. default = vbr_off = CBR */ +int +lame_set_VBR(lame_global_flags * gfp, vbr_mode VBR) +{ + if (is_lame_global_flags_valid(gfp)) { + int vbr_q = VBR; + if (0 > vbr_q || vbr_max_indicator <= vbr_q) + return -1; /* Unknown VBR mode! */ + gfp->VBR = VBR; + return 0; + } + return -1; +} + +vbr_mode +lame_get_VBR(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + assert(gfp->VBR < vbr_max_indicator); + return gfp->VBR; + } + return vbr_off; +} + + +/* + * VBR quality level. + * 0 = highest + * 9 = lowest + */ +int +lame_set_VBR_q(lame_global_flags * gfp, int VBR_q) +{ + if (is_lame_global_flags_valid(gfp)) { + int ret = 0; + + if (0 > VBR_q) { + ret = -1; /* Unknown VBR quality level! */ + VBR_q = 0; + } + if (9 < VBR_q) { + ret = -1; + VBR_q = 9; + } + gfp->VBR_q = VBR_q; + gfp->VBR_q_frac = 0; + return ret; + } + return -1; +} + +int +lame_get_VBR_q(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + assert(0 <= gfp->VBR_q && 10 > gfp->VBR_q); + return gfp->VBR_q; + } + return 0; +} + +int +lame_set_VBR_quality(lame_global_flags * gfp, float VBR_q) +{ + if (is_lame_global_flags_valid(gfp)) { + int ret = 0; + + if (0 > VBR_q) { + ret = -1; /* Unknown VBR quality level! */ + VBR_q = 0; + } + if (9.999 < VBR_q) { + ret = -1; + VBR_q = 9.999; + } + + gfp->VBR_q = (int) VBR_q; + gfp->VBR_q_frac = VBR_q - gfp->VBR_q; + + return ret; + } + return -1; +} + +float +lame_get_VBR_quality(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->VBR_q + gfp->VBR_q_frac; + } + return 0; +} + + +/* Ignored except for VBR = vbr_abr (ABR mode) */ +int +lame_set_VBR_mean_bitrate_kbps(lame_global_flags * gfp, int VBR_mean_bitrate_kbps) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->VBR_mean_bitrate_kbps = VBR_mean_bitrate_kbps; + return 0; + } + return -1; +} + +int +lame_get_VBR_mean_bitrate_kbps(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->VBR_mean_bitrate_kbps; + } + return 0; +} + +int +lame_set_VBR_min_bitrate_kbps(lame_global_flags * gfp, int VBR_min_bitrate_kbps) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->VBR_min_bitrate_kbps = VBR_min_bitrate_kbps; + return 0; + } + return -1; +} + +int +lame_get_VBR_min_bitrate_kbps(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->VBR_min_bitrate_kbps; + } + return 0; +} + +int +lame_set_VBR_max_bitrate_kbps(lame_global_flags * gfp, int VBR_max_bitrate_kbps) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->VBR_max_bitrate_kbps = VBR_max_bitrate_kbps; + return 0; + } + return -1; +} + +int +lame_get_VBR_max_bitrate_kbps(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->VBR_max_bitrate_kbps; + } + return 0; +} + + +/* + * Strictly enforce VBR_min_bitrate. + * Normally it will be violated for analog silence. + */ +int +lame_set_VBR_hard_min(lame_global_flags * gfp, int VBR_hard_min) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 0 (disabled) */ + + /* enforce disable/enable meaning, if we need more than two values + we need to switch to an enum to have an apropriate representation + of the possible meanings of the value */ + if (0 > VBR_hard_min || 1 < VBR_hard_min) + return -1; + + gfp->VBR_hard_min = VBR_hard_min; + + return 0; + } + return -1; +} + +int +lame_get_VBR_hard_min(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + assert(0 <= gfp->VBR_hard_min && 1 >= gfp->VBR_hard_min); + return gfp->VBR_hard_min; + } + return 0; +} + + +/******************************************************************** + * Filtering control + ***********************************************************************/ + +/* + * Freqency in Hz to apply lowpass. + * 0 = default = lame chooses + * -1 = disabled + */ +int +lame_set_lowpassfreq(lame_global_flags * gfp, int lowpassfreq) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->lowpassfreq = lowpassfreq; + return 0; + } + return -1; +} + +int +lame_get_lowpassfreq(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->lowpassfreq; + } + return 0; +} + + +/* + * Width of transition band (in Hz). + * default = one polyphase filter band + */ +int +lame_set_lowpasswidth(lame_global_flags * gfp, int lowpasswidth) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->lowpasswidth = lowpasswidth; + return 0; + } + return -1; +} + +int +lame_get_lowpasswidth(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->lowpasswidth; + } + return 0; +} + + +/* + * Frequency in Hz to apply highpass. + * 0 = default = lame chooses + * -1 = disabled + */ +int +lame_set_highpassfreq(lame_global_flags * gfp, int highpassfreq) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->highpassfreq = highpassfreq; + return 0; + } + return -1; +} + +int +lame_get_highpassfreq(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->highpassfreq; + } + return 0; +} + + +/* + * Width of transition band (in Hz). + * default = one polyphase filter band + */ +int +lame_set_highpasswidth(lame_global_flags * gfp, int highpasswidth) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->highpasswidth = highpasswidth; + return 0; + } + return -1; +} + +int +lame_get_highpasswidth(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->highpasswidth; + } + return 0; +} + + + + +/* + * psycho acoustics and other arguments which you should not change + * unless you know what you are doing + */ + + +/* Adjust masking values. */ +int +lame_set_maskingadjust(lame_global_flags * gfp, float adjust) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->maskingadjust = adjust; + return 0; + } + return -1; +} + +float +lame_get_maskingadjust(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->maskingadjust; + } + return 0; +} + +int +lame_set_maskingadjust_short(lame_global_flags * gfp, float adjust) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->maskingadjust_short = adjust; + return 0; + } + return -1; +} + +float +lame_get_maskingadjust_short(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->maskingadjust_short; + } + return 0; +} + +/* Only use ATH for masking. */ +int +lame_set_ATHonly(lame_global_flags * gfp, int ATHonly) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->ATHonly = ATHonly; + return 0; + } + return -1; +} + +int +lame_get_ATHonly(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->ATHonly; + } + return 0; +} + + +/* Only use ATH for short blocks. */ +int +lame_set_ATHshort(lame_global_flags * gfp, int ATHshort) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->ATHshort = ATHshort; + return 0; + } + return -1; +} + +int +lame_get_ATHshort(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->ATHshort; + } + return 0; +} + + +/* Disable ATH. */ +int +lame_set_noATH(lame_global_flags * gfp, int noATH) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->noATH = noATH; + return 0; + } + return -1; +} + +int +lame_get_noATH(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->noATH; + } + return 0; +} + + +/* Select ATH formula. */ +int +lame_set_ATHtype(lame_global_flags * gfp, int ATHtype) +{ + if (is_lame_global_flags_valid(gfp)) { + /* XXX: ATHtype should be converted to an enum. */ + gfp->ATHtype = ATHtype; + return 0; + } + return -1; +} + +int +lame_get_ATHtype(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->ATHtype; + } + return 0; +} + + +/* Select ATH formula 4 shape. */ +int +lame_set_ATHcurve(lame_global_flags * gfp, float ATHcurve) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->ATHcurve = ATHcurve; + return 0; + } + return -1; +} + +float +lame_get_ATHcurve(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->ATHcurve; + } + return 0; +} + + +/* Lower ATH by this many db. */ +int +lame_set_ATHlower(lame_global_flags * gfp, float ATHlower) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->ATH_lower_db = ATHlower; + return 0; + } + return -1; +} + +float +lame_get_ATHlower(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->ATH_lower_db; + } + return 0; +} + + +/* Select ATH adaptive adjustment scheme. */ +int +lame_set_athaa_type(lame_global_flags * gfp, int athaa_type) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->athaa_type = athaa_type; + return 0; + } + return -1; +} + +int +lame_get_athaa_type(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->athaa_type; + } + return 0; +} + + +#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED +int CDECL lame_set_athaa_loudapprox(lame_global_flags * gfp, int athaa_loudapprox); +int CDECL lame_get_athaa_loudapprox(const lame_global_flags * gfp); +#else +#endif + +/* Select the loudness approximation used by the ATH adaptive auto-leveling. */ +int +lame_set_athaa_loudapprox(lame_global_flags * gfp, int athaa_loudapprox) +{ + (void) gfp; + (void) athaa_loudapprox; + return 0; +} + +int +lame_get_athaa_loudapprox(const lame_global_flags * gfp) +{ + (void) gfp; + /* obsolete, the type known under number 2 is the only survival */ + return 2; +} + + +/* Adjust (in dB) the point below which adaptive ATH level adjustment occurs. */ +int +lame_set_athaa_sensitivity(lame_global_flags * gfp, float athaa_sensitivity) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->athaa_sensitivity = athaa_sensitivity; + return 0; + } + return -1; +} + +float +lame_get_athaa_sensitivity(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->athaa_sensitivity; + } + return 0; +} + + +/* Predictability limit (ISO tonality formula) */ +int lame_set_cwlimit(lame_global_flags * gfp, int cwlimit); +int lame_get_cwlimit(const lame_global_flags * gfp); + +int +lame_set_cwlimit(lame_global_flags * gfp, int cwlimit) +{ + (void) gfp; + (void) cwlimit; + return 0; +} + +int +lame_get_cwlimit(const lame_global_flags * gfp) +{ + (void) gfp; + return 0; +} + + + +/* + * Allow blocktypes to differ between channels. + * default: + * 0 for jstereo => block types coupled + * 1 for stereo => block types may differ + */ +int +lame_set_allow_diff_short(lame_global_flags * gfp, int allow_diff_short) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->short_blocks = allow_diff_short ? short_block_allowed : short_block_coupled; + return 0; + } + return -1; +} + +int +lame_get_allow_diff_short(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + if (gfp->short_blocks == short_block_allowed) + return 1; /* short blocks allowed to differ */ + else + return 0; /* not set, dispensed, forced or coupled */ + } + return 0; +} + + +/* Use temporal masking effect */ +int +lame_set_useTemporal(lame_global_flags * gfp, int useTemporal) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 1 (enabled) */ + + /* enforce disable/enable meaning, if we need more than two values + we need to switch to an enum to have an apropriate representation + of the possible meanings of the value */ + if (0 <= useTemporal && useTemporal <= 1) { + gfp->useTemporal = useTemporal; + return 0; + } + } + return -1; +} + +int +lame_get_useTemporal(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + assert(0 <= gfp->useTemporal && 1 >= gfp->useTemporal); + return gfp->useTemporal; + } + return 0; +} + + +/* Use inter-channel masking effect */ +int +lame_set_interChRatio(lame_global_flags * gfp, float ratio) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 0.0 (no inter-channel maskin) */ + if (0 <= ratio && ratio <= 1.0) { + gfp->interChRatio = ratio; + return 0; + } + } + return -1; +} + +float +lame_get_interChRatio(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + assert((0 <= gfp->interChRatio && gfp->interChRatio <= 1.0) || EQ(gfp->interChRatio, -1)); + return gfp->interChRatio; + } + return 0; +} + + +/* Use pseudo substep shaping method */ +int +lame_set_substep(lame_global_flags * gfp, int method) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 0.0 (no substep noise shaping) */ + if (0 <= method && method <= 7) { + gfp->substep_shaping = method; + return 0; + } + } + return -1; +} + +int +lame_get_substep(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + assert(0 <= gfp->substep_shaping && gfp->substep_shaping <= 7); + return gfp->substep_shaping; + } + return 0; +} + +/* scalefactors scale */ +int +lame_set_sfscale(lame_global_flags * gfp, int val) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->noise_shaping = (val != 0) ? 2 : 1; + return 0; + } + return -1; +} + +int +lame_get_sfscale(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return (gfp->noise_shaping == 2) ? 1 : 0; + } + return 0; +} + +/* subblock gain */ +int +lame_set_subblock_gain(lame_global_flags * gfp, int sbgain) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->subblock_gain = sbgain; + return 0; + } + return -1; +} + +int +lame_get_subblock_gain(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->subblock_gain; + } + return 0; +} + + +/* Disable short blocks. */ +int +lame_set_no_short_blocks(lame_global_flags * gfp, int no_short_blocks) +{ + if (is_lame_global_flags_valid(gfp)) { + /* enforce disable/enable meaning, if we need more than two values + we need to switch to an enum to have an apropriate representation + of the possible meanings of the value */ + if (0 <= no_short_blocks && no_short_blocks <= 1) { + gfp->short_blocks = no_short_blocks ? short_block_dispensed : short_block_allowed; + return 0; + } + } + return -1; +} + +int +lame_get_no_short_blocks(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + switch (gfp->short_blocks) { + default: + case short_block_not_set: + return -1; + case short_block_dispensed: + return 1; + case short_block_allowed: + case short_block_coupled: + case short_block_forced: + return 0; + } + } + return -1; +} + + +/* Force short blocks. */ +int +lame_set_force_short_blocks(lame_global_flags * gfp, int short_blocks) +{ + if (is_lame_global_flags_valid(gfp)) { + /* enforce disable/enable meaning, if we need more than two values + we need to switch to an enum to have an apropriate representation + of the possible meanings of the value */ + if (0 > short_blocks || 1 < short_blocks) + return -1; + + if (short_blocks == 1) + gfp->short_blocks = short_block_forced; + else if (gfp->short_blocks == short_block_forced) + gfp->short_blocks = short_block_allowed; + + return 0; + } + return -1; +} + +int +lame_get_force_short_blocks(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + switch (gfp->short_blocks) { + default: + case short_block_not_set: + return -1; + case short_block_dispensed: + case short_block_allowed: + case short_block_coupled: + return 0; + case short_block_forced: + return 1; + } + } + return -1; +} + +int +lame_set_short_threshold_lrm(lame_global_flags * gfp, float lrm) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->attackthre = lrm; + return 0; + } + return -1; +} + +float +lame_get_short_threshold_lrm(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->attackthre; + } + return 0; +} + +int +lame_set_short_threshold_s(lame_global_flags * gfp, float s) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->attackthre_s = s; + return 0; + } + return -1; +} + +float +lame_get_short_threshold_s(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->attackthre_s; + } + return 0; +} + +int +lame_set_short_threshold(lame_global_flags * gfp, float lrm, float s) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_set_short_threshold_lrm(gfp, lrm); + lame_set_short_threshold_s(gfp, s); + return 0; + } + return -1; +} + + +/* + * Input PCM is emphased PCM + * (for instance from one of the rarely emphased CDs). + * + * It is STRONGLY not recommended to use this, because psycho does not + * take it into account, and last but not least many decoders + * ignore these bits + */ +int +lame_set_emphasis(lame_global_flags * gfp, int emphasis) +{ + if (is_lame_global_flags_valid(gfp)) { + /* XXX: emphasis should be converted to an enum */ + if (0 <= emphasis && emphasis < 4) { + gfp->emphasis = emphasis; + return 0; + } + } + return -1; +} + +int +lame_get_emphasis(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + assert(0 <= gfp->emphasis && gfp->emphasis < 4); + return gfp->emphasis; + } + return 0; +} + + + + +/***************************************************************/ +/* internal variables, cannot be set... */ +/* provided because they may be of use to calling application */ +/***************************************************************/ + +/* MPEG version. + * 0 = MPEG-2 + * 1 = MPEG-1 + * (2 = MPEG-2.5) + */ +int +lame_get_version(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags const *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + return gfc->cfg.version; + } + } + return 0; +} + + +/* Encoder delay. */ +int +lame_get_encoder_delay(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags const *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + return gfc->ov_enc.encoder_delay; + } + } + return 0; +} + +/* padding added to the end of the input */ +int +lame_get_encoder_padding(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags const *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + return gfc->ov_enc.encoder_padding; + } + } + return 0; +} + + +/* Size of MPEG frame. */ +int +lame_get_framesize(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags const *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + SessionConfig_t const *const cfg = &gfc->cfg; + return 576 * cfg->mode_gr; + } + } + return 0; +} + + +/* Number of frames encoded so far. */ +int +lame_get_frameNum(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags const *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + return gfc->ov_enc.frame_number; + } + } + return 0; +} + +int +lame_get_mf_samples_to_encode(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags const *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + return gfc->sv_enc.mf_samples_to_encode; + } + } + return 0; +} + +int CDECL +lame_get_size_mp3buffer(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags const *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + int size; + compute_flushbits(gfc, &size); + return size; + } + } + return 0; +} + +int +lame_get_RadioGain(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags const *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + return gfc->ov_rpg.RadioGain; + } + } + return 0; +} + +int +lame_get_AudiophileGain(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags const *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + return 0; + } + } + return 0; +} + +float +lame_get_PeakSample(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags const *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + return (float) gfc->ov_rpg.PeakSample; + } + } + return 0; +} + +int +lame_get_noclipGainChange(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags const *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + return gfc->ov_rpg.noclipGainChange; + } + } + return 0; +} + +float +lame_get_noclipScale(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags const *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + return gfc->ov_rpg.noclipScale; + } + } + return 0; +} + + +/* + * LAME's estimate of the total number of frames to be encoded. + * Only valid if calling program set num_samples. + */ +int +lame_get_totalframes(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags const *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + SessionConfig_t const *const cfg = &gfc->cfg; + unsigned long const pcm_samples_per_frame = 576 * cfg->mode_gr; + unsigned long pcm_samples_to_encode = gfp->num_samples; + unsigned long end_padding = 0; + int frames = 0; + + if (pcm_samples_to_encode == (0ul-1ul)) + return 0; /* unknown */ + + /* estimate based on user set num_samples: */ + if (cfg->samplerate_in != cfg->samplerate_out) { + /* resampling, estimate new samples_to_encode */ + double resampled_samples_to_encode = 0.0, frames_f = 0.0; + if (cfg->samplerate_in > 0) { + resampled_samples_to_encode = pcm_samples_to_encode; + resampled_samples_to_encode *= cfg->samplerate_out; + resampled_samples_to_encode /= cfg->samplerate_in; + } + if (resampled_samples_to_encode <= 0.0) + return 0; /* unlikely to happen, so what, no estimate! */ + frames_f = floor(resampled_samples_to_encode / pcm_samples_per_frame); + if (frames_f >= (INT_MAX-2)) + return 0; /* overflow, happens eventually, no estimate! */ + frames = frames_f; + resampled_samples_to_encode -= frames * pcm_samples_per_frame; + pcm_samples_to_encode = ceil(resampled_samples_to_encode); + } + else { + frames = pcm_samples_to_encode / pcm_samples_per_frame; + pcm_samples_to_encode -= frames * pcm_samples_per_frame; + } + pcm_samples_to_encode += 576ul; + end_padding = pcm_samples_per_frame - (pcm_samples_to_encode % pcm_samples_per_frame); + if (end_padding < 576ul) { + end_padding += pcm_samples_per_frame; + } + pcm_samples_to_encode += end_padding; + frames += (pcm_samples_to_encode / pcm_samples_per_frame); + /* check to see if we underestimated totalframes */ + /* if (totalframes < gfp->frameNum) */ + /* totalframes = gfp->frameNum; */ + return frames; + } + } + return 0; +} + + + + + +int +lame_set_preset(lame_global_flags * gfp, int preset) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->preset = preset; + return apply_preset(gfp, preset, 1); + } + return -1; +} + + + +int +lame_set_asm_optimizations(lame_global_flags * gfp, int optim, int mode) +{ + if (is_lame_global_flags_valid(gfp)) { + mode = (mode == 1 ? 1 : 0); + switch (optim) { + case MMX:{ + gfp->asm_optimizations.mmx = mode; + return optim; + } + case AMD_3DNOW:{ + gfp->asm_optimizations.amd3dnow = mode; + return optim; + } + case SSE:{ + gfp->asm_optimizations.sse = mode; + return optim; + } + default: + return optim; + } + } + return -1; +} + + +void +lame_set_write_id3tag_automatic(lame_global_flags * gfp, int v) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->write_id3tag_automatic = v; + } +} + + +int +lame_get_write_id3tag_automatic(lame_global_flags const *gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->write_id3tag_automatic; + } + return 1; +} + + +/* + +UNDOCUMENTED, experimental settings. These routines are not prototyped +in lame.h. You should not use them, they are experimental and may +change. + +*/ + + +/* + * just another daily changing developer switch + */ +void CDECL lame_set_tune(lame_global_flags *, float); + +void +lame_set_tune(lame_global_flags * gfp, float val) +{ + if (is_lame_global_flags_valid(gfp)) { + gfp->tune_value_a = val; + gfp->tune = 1; + } +} + +/* Custom msfix hack */ +void +lame_set_msfix(lame_global_flags * gfp, double msfix) +{ + if (is_lame_global_flags_valid(gfp)) { + /* default = 0 */ + gfp->msfix = msfix; + } +} + +float +lame_get_msfix(const lame_global_flags * gfp) +{ + if (is_lame_global_flags_valid(gfp)) { + return gfp->msfix; + } + return 0; +} + +#if DEPRECATED_OR_OBSOLETE_CODE_REMOVED +int CDECL lame_set_preset_expopts(lame_global_flags *, int); +#else +#endif + +int +lame_set_preset_expopts(lame_global_flags * gfp, int preset_expopts) +{ + (void) gfp; + (void) preset_expopts; + return 0; +} + + +int +lame_set_preset_notune(lame_global_flags * gfp, int preset_notune) +{ + (void) gfp; + (void) preset_notune; + return 0; +} + +static int +calc_maximum_input_samples_for_buffer_size(lame_internal_flags const* gfc, size_t buffer_size) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + int const pcm_samples_per_frame = 576 * cfg->mode_gr; + int frames_per_buffer = 0, input_samples_per_buffer = 0; + int kbps = 320; + + if (cfg->samplerate_out < 16000) + kbps = 64; + else if (cfg->samplerate_out < 32000) + kbps = 160; + else + kbps = 320; + if (cfg->free_format) + kbps = cfg->avg_bitrate; + else if (cfg->vbr == vbr_off) { + kbps = cfg->avg_bitrate; + } + { + int const pad = 1; + int const bpf = ((cfg->version + 1) * 72000 * kbps / cfg->samplerate_out + pad); + frames_per_buffer = buffer_size / bpf; + } + { + double ratio = (double) cfg->samplerate_in / cfg->samplerate_out; + input_samples_per_buffer = pcm_samples_per_frame * frames_per_buffer * ratio; + } + return input_samples_per_buffer; +} + +int +lame_get_maximum_number_of_samples(lame_t gfp, size_t buffer_size) +{ + if (is_lame_global_flags_valid(gfp)) { + lame_internal_flags const *const gfc = gfp->internal_flags; + if (is_lame_internal_flags_valid(gfc)) { + return calc_maximum_input_samples_for_buffer_size(gfc, buffer_size); + } + } + return LAME_GENERICERROR; +} diff --git a/pkg/lame/clame/set_get.h b/pkg/lame/clame/set_get.h new file mode 100644 index 0000000..37e4bcd --- /dev/null +++ b/pkg/lame/clame/set_get.h @@ -0,0 +1,76 @@ +/* + * set_get.h -- Internal set/get definitions + * + * Copyright (C) 2003 Gabriel Bouvigne / Lame project + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __SET_GET_H__ +#define __SET_GET_H__ + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +/* select psychoacoustic model */ + +/* manage short blocks */ + int CDECL lame_set_short_threshold(lame_global_flags *, float, float); + int CDECL lame_set_short_threshold_lrm(lame_global_flags *, float); + float CDECL lame_get_short_threshold_lrm(const lame_global_flags *); + int CDECL lame_set_short_threshold_s(lame_global_flags *, float); + float CDECL lame_get_short_threshold_s(const lame_global_flags *); + + + int CDECL lame_set_maskingadjust(lame_global_flags *, float); + float CDECL lame_get_maskingadjust(const lame_global_flags *); + + int CDECL lame_set_maskingadjust_short(lame_global_flags *, float); + float CDECL lame_get_maskingadjust_short(const lame_global_flags *); + +/* select ATH formula 4 shape */ + int CDECL lame_set_ATHcurve(lame_global_flags *, float); + float CDECL lame_get_ATHcurve(const lame_global_flags *); + + int CDECL lame_set_preset_notune(lame_global_flags *, int); + +/* substep shaping method */ + int CDECL lame_set_substep(lame_global_flags *, int); + int CDECL lame_get_substep(const lame_global_flags *); + +/* scalefactors scale */ + int CDECL lame_set_sfscale(lame_global_flags *, int); + int CDECL lame_get_sfscale(const lame_global_flags *); + +/* subblock gain */ + int CDECL lame_set_subblock_gain(lame_global_flags *, int); + int CDECL lame_get_subblock_gain(const lame_global_flags *); + + + +/*presets*/ + int apply_preset(lame_global_flags *, int preset, int enforce); + + void CDECL lame_set_tune(lame_t, float); /* FOR INTERNAL USE ONLY */ + void CDECL lame_set_msfix(lame_t gfp, double msfix); + + +#if defined(__cplusplus) +} +#endif +#endif diff --git a/pkg/lame/clame/tables.c b/pkg/lame/clame/tables.c new file mode 100644 index 0000000..a023099 --- /dev/null +++ b/pkg/lame/clame/tables.c @@ -0,0 +1,564 @@ +/* + * MPEG layer 3 tables source file + * + * Copyright (c) 1999 Albert L Faber + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* $Id: tables.c,v 1.29 2011/05/07 16:05:17 rbrito Exp $ */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "machine.h" + +#include "lame.h" +#include "tables.h" + + +static const uint16_t t1HB[] = { + 1, 1, + 1, 0 +}; + +static const uint16_t t2HB[] = { + 1, 2, 1, + 3, 1, 1, + 3, 2, 0 +}; + +static const uint16_t t3HB[] = { + 3, 2, 1, + 1, 1, 1, + 3, 2, 0 +}; + +static const uint16_t t5HB[] = { + 1, 2, 6, 5, + 3, 1, 4, 4, + 7, 5, 7, 1, + 6, 1, 1, 0 +}; + +static const uint16_t t6HB[] = { + 7, 3, 5, 1, + 6, 2, 3, 2, + 5, 4, 4, 1, + 3, 3, 2, 0 +}; + +static const uint16_t t7HB[] = { + 1, 2, 10, 19, 16, 10, + 3, 3, 7, 10, 5, 3, + 11, 4, 13, 17, 8, 4, + 12, 11, 18, 15, 11, 2, + 7, 6, 9, 14, 3, 1, + 6, 4, 5, 3, 2, 0 +}; + +static const uint16_t t8HB[] = { + 3, 4, 6, 18, 12, 5, + 5, 1, 2, 16, 9, 3, + 7, 3, 5, 14, 7, 3, + 19, 17, 15, 13, 10, 4, + 13, 5, 8, 11, 5, 1, + 12, 4, 4, 1, 1, 0 +}; + +static const uint16_t t9HB[] = { + 7, 5, 9, 14, 15, 7, + 6, 4, 5, 5, 6, 7, + 7, 6, 8, 8, 8, 5, + 15, 6, 9, 10, 5, 1, + 11, 7, 9, 6, 4, 1, + 14, 4, 6, 2, 6, 0 +}; + +static const uint16_t t10HB[] = { + 1, 2, 10, 23, 35, 30, 12, 17, + 3, 3, 8, 12, 18, 21, 12, 7, + 11, 9, 15, 21, 32, 40, 19, 6, + 14, 13, 22, 34, 46, 23, 18, 7, + 20, 19, 33, 47, 27, 22, 9, 3, + 31, 22, 41, 26, 21, 20, 5, 3, + 14, 13, 10, 11, 16, 6, 5, 1, + 9, 8, 7, 8, 4, 4, 2, 0 +}; + +static const uint16_t t11HB[] = { + 3, 4, 10, 24, 34, 33, 21, 15, + 5, 3, 4, 10, 32, 17, 11, 10, + 11, 7, 13, 18, 30, 31, 20, 5, + 25, 11, 19, 59, 27, 18, 12, 5, + 35, 33, 31, 58, 30, 16, 7, 5, + 28, 26, 32, 19, 17, 15, 8, 14, + 14, 12, 9, 13, 14, 9, 4, 1, + 11, 4, 6, 6, 6, 3, 2, 0 +}; + +static const uint16_t t12HB[] = { + 9, 6, 16, 33, 41, 39, 38, 26, + 7, 5, 6, 9, 23, 16, 26, 11, + 17, 7, 11, 14, 21, 30, 10, 7, + 17, 10, 15, 12, 18, 28, 14, 5, + 32, 13, 22, 19, 18, 16, 9, 5, + 40, 17, 31, 29, 17, 13, 4, 2, + 27, 12, 11, 15, 10, 7, 4, 1, + 27, 12, 8, 12, 6, 3, 1, 0 +}; + +static const uint16_t t13HB[] = { + 1, 5, 14, 21, 34, 51, 46, 71, 42, 52, 68, 52, 67, 44, 43, 19, + 3, 4, 12, 19, 31, 26, 44, 33, 31, 24, 32, 24, 31, 35, 22, 14, + 15, 13, 23, 36, 59, 49, 77, 65, 29, 40, 30, 40, 27, 33, 42, 16, + 22, 20, 37, 61, 56, 79, 73, 64, 43, 76, 56, 37, 26, 31, 25, 14, + 35, 16, 60, 57, 97, 75, 114, 91, 54, 73, 55, 41, 48, 53, 23, 24, + 58, 27, 50, 96, 76, 70, 93, 84, 77, 58, 79, 29, 74, 49, 41, 17, + 47, 45, 78, 74, 115, 94, 90, 79, 69, 83, 71, 50, 59, 38, 36, 15, + 72, 34, 56, 95, 92, 85, 91, 90, 86, 73, 77, 65, 51, 44, 43, 42, + 43, 20, 30, 44, 55, 78, 72, 87, 78, 61, 46, 54, 37, 30, 20, 16, + 53, 25, 41, 37, 44, 59, 54, 81, 66, 76, 57, 54, 37, 18, 39, 11, + 35, 33, 31, 57, 42, 82, 72, 80, 47, 58, 55, 21, 22, 26, 38, 22, + 53, 25, 23, 38, 70, 60, 51, 36, 55, 26, 34, 23, 27, 14, 9, 7, + 34, 32, 28, 39, 49, 75, 30, 52, 48, 40, 52, 28, 18, 17, 9, 5, + 45, 21, 34, 64, 56, 50, 49, 45, 31, 19, 12, 15, 10, 7, 6, 3, + 48, 23, 20, 39, 36, 35, 53, 21, 16, 23, 13, 10, 6, 1, 4, 2, + 16, 15, 17, 27, 25, 20, 29, 11, 17, 12, 16, 8, 1, 1, 0, 1 +}; + +static const uint16_t t15HB[] = { + 7, 12, 18, 53, 47, 76, 124, 108, 89, 123, 108, 119, 107, 81, 122, 63, + 13, 5, 16, 27, 46, 36, 61, 51, 42, 70, 52, 83, 65, 41, 59, 36, + 19, 17, 15, 24, 41, 34, 59, 48, 40, 64, 50, 78, 62, 80, 56, 33, + 29, 28, 25, 43, 39, 63, 55, 93, 76, 59, 93, 72, 54, 75, 50, 29, + 52, 22, 42, 40, 67, 57, 95, 79, 72, 57, 89, 69, 49, 66, 46, 27, + 77, 37, 35, 66, 58, 52, 91, 74, 62, 48, 79, 63, 90, 62, 40, 38, + 125, 32, 60, 56, 50, 92, 78, 65, 55, 87, 71, 51, 73, 51, 70, 30, + 109, 53, 49, 94, 88, 75, 66, 122, 91, 73, 56, 42, 64, 44, 21, 25, + 90, 43, 41, 77, 73, 63, 56, 92, 77, 66, 47, 67, 48, 53, 36, 20, + 71, 34, 67, 60, 58, 49, 88, 76, 67, 106, 71, 54, 38, 39, 23, 15, + 109, 53, 51, 47, 90, 82, 58, 57, 48, 72, 57, 41, 23, 27, 62, 9, + 86, 42, 40, 37, 70, 64, 52, 43, 70, 55, 42, 25, 29, 18, 11, 11, + 118, 68, 30, 55, 50, 46, 74, 65, 49, 39, 24, 16, 22, 13, 14, 7, + 91, 44, 39, 38, 34, 63, 52, 45, 31, 52, 28, 19, 14, 8, 9, 3, + 123, 60, 58, 53, 47, 43, 32, 22, 37, 24, 17, 12, 15, 10, 2, 1, + 71, 37, 34, 30, 28, 20, 17, 26, 21, 16, 10, 6, 8, 6, 2, 0 +}; + +static const uint16_t t16HB[] = { + 1, 5, 14, 44, 74, 63, 110, 93, 172, 149, 138, 242, 225, 195, 376, 17, + 3, 4, 12, 20, 35, 62, 53, 47, 83, 75, 68, 119, 201, 107, 207, 9, + 15, 13, 23, 38, 67, 58, 103, 90, 161, 72, 127, 117, 110, 209, 206, 16, + 45, 21, 39, 69, 64, 114, 99, 87, 158, 140, 252, 212, 199, 387, 365, 26, + 75, 36, 68, 65, 115, 101, 179, 164, 155, 264, 246, 226, 395, 382, 362, 9, + 66, 30, 59, 56, 102, 185, 173, 265, 142, 253, 232, 400, 388, 378, 445, 16, + 111, 54, 52, 100, 184, 178, 160, 133, 257, 244, 228, 217, 385, 366, 715, 10, + 98, 48, 91, 88, 165, 157, 148, 261, 248, 407, 397, 372, 380, 889, 884, 8, + 85, 84, 81, 159, 156, 143, 260, 249, 427, 401, 392, 383, 727, 713, 708, 7, + 154, 76, 73, 141, 131, 256, 245, 426, 406, 394, 384, 735, 359, 710, 352, 11, + 139, 129, 67, 125, 247, 233, 229, 219, 393, 743, 737, 720, 885, 882, 439, 4, + 243, 120, 118, 115, 227, 223, 396, 746, 742, 736, 721, 712, 706, 223, 436, 6, + 202, 224, 222, 218, 216, 389, 386, 381, 364, 888, 443, 707, 440, 437, 1728, 4, + 747, 211, 210, 208, 370, 379, 734, 723, 714, 1735, 883, 877, 876, 3459, 865, 2, + 377, 369, 102, 187, 726, 722, 358, 711, 709, 866, 1734, 871, 3458, 870, 434, 0, + 12, 10, 7, 11, 10, 17, 11, 9, 13, 12, 10, 7, 5, 3, 1, 3 +}; + +static const uint16_t t24HB[] = { + 15, 13, 46, 80, 146, 262, 248, 434, 426, 669, 653, 649, 621, 517, 1032, 88, + 14, 12, 21, 38, 71, 130, 122, 216, 209, 198, 327, 345, 319, 297, 279, 42, + 47, 22, 41, 74, 68, 128, 120, 221, 207, 194, 182, 340, 315, 295, 541, 18, + 81, 39, 75, 70, 134, 125, 116, 220, 204, 190, 178, 325, 311, 293, 271, 16, + 147, 72, 69, 135, 127, 118, 112, 210, 200, 188, 352, 323, 306, 285, 540, 14, + 263, 66, 129, 126, 119, 114, 214, 202, 192, 180, 341, 317, 301, 281, 262, 12, + 249, 123, 121, 117, 113, 215, 206, 195, 185, 347, 330, 308, 291, 272, 520, 10, + 435, 115, 111, 109, 211, 203, 196, 187, 353, 332, 313, 298, 283, 531, 381, 17, + 427, 212, 208, 205, 201, 193, 186, 177, 169, 320, 303, 286, 268, 514, 377, 16, + 335, 199, 197, 191, 189, 181, 174, 333, 321, 305, 289, 275, 521, 379, 371, 11, + 668, 184, 183, 179, 175, 344, 331, 314, 304, 290, 277, 530, 383, 373, 366, 10, + 652, 346, 171, 168, 164, 318, 309, 299, 287, 276, 263, 513, 375, 368, 362, 6, + 648, 322, 316, 312, 307, 302, 292, 284, 269, 261, 512, 376, 370, 364, 359, 4, + 620, 300, 296, 294, 288, 282, 273, 266, 515, 380, 374, 369, 365, 361, 357, 2, + 1033, 280, 278, 274, 267, 264, 259, 382, 378, 372, 367, 363, 360, 358, 356, 0, + 43, 20, 19, 17, 15, 13, 11, 9, 7, 6, 4, 7, 5, 3, 1, 3 +}; + +static const uint16_t t32HB[] = { + 1 << 0, 5 << 1, 4 << 1, 5 << 2, 6 << 1, 5 << 2, 4 << 2, 4 << 3, + 7 << 1, 3 << 2, 6 << 2, 0 << 3, 7 << 2, 2 << 3, 3 << 3, 1 << 4 +}; + +static const uint16_t t33HB[] = { + 15 << 0, 14 << 1, 13 << 1, 12 << 2, 11 << 1, 10 << 2, 9 << 2, 8 << 3, + 7 << 1, 6 << 2, 5 << 2, 4 << 3, 3 << 2, 2 << 3, 1 << 3, 0 << 4 +}; + + +const uint8_t t1l[] = { + 1, 4, + 3, 5 +}; + +static const uint8_t t2l[] = { + 1, 4, 7, + 4, 5, 7, + 6, 7, 8 +}; + +static const uint8_t t3l[] = { + 2, 3, 7, + 4, 4, 7, + 6, 7, 8 +}; + +static const uint8_t t5l[] = { + 1, 4, 7, 8, + 4, 5, 8, 9, + 7, 8, 9, 10, + 8, 8, 9, 10 +}; + +static const uint8_t t6l[] = { + 3, 4, 6, 8, + 4, 4, 6, 7, + 5, 6, 7, 8, + 7, 7, 8, 9 +}; + +static const uint8_t t7l[] = { + 1, 4, 7, 9, 9, 10, + 4, 6, 8, 9, 9, 10, + 7, 7, 9, 10, 10, 11, + 8, 9, 10, 11, 11, 11, + 8, 9, 10, 11, 11, 12, + 9, 10, 11, 12, 12, 12 +}; + +static const uint8_t t8l[] = { + 2, 4, 7, 9, 9, 10, + 4, 4, 6, 10, 10, 10, + 7, 6, 8, 10, 10, 11, + 9, 10, 10, 11, 11, 12, + 9, 9, 10, 11, 12, 12, + 10, 10, 11, 11, 13, 13 +}; + +static const uint8_t t9l[] = { + 3, 4, 6, 7, 9, 10, + 4, 5, 6, 7, 8, 10, + 5, 6, 7, 8, 9, 10, + 7, 7, 8, 9, 9, 10, + 8, 8, 9, 9, 10, 11, + 9, 9, 10, 10, 11, 11 +}; + +static const uint8_t t10l[] = { + 1, 4, 7, 9, 10, 10, 10, 11, + 4, 6, 8, 9, 10, 11, 10, 10, + 7, 8, 9, 10, 11, 12, 11, 11, + 8, 9, 10, 11, 12, 12, 11, 12, + 9, 10, 11, 12, 12, 12, 12, 12, + 10, 11, 12, 12, 13, 13, 12, 13, + 9, 10, 11, 12, 12, 12, 13, 13, + 10, 10, 11, 12, 12, 13, 13, 13 +}; + +static const uint8_t t11l[] = { + 2, 4, 6, 8, 9, 10, 9, 10, + 4, 5, 6, 8, 10, 10, 9, 10, + 6, 7, 8, 9, 10, 11, 10, 10, + 8, 8, 9, 11, 10, 12, 10, 11, + 9, 10, 10, 11, 11, 12, 11, 12, + 9, 10, 11, 12, 12, 13, 12, 13, + 9, 9, 9, 10, 11, 12, 12, 12, + 9, 9, 10, 11, 12, 12, 12, 12 +}; + +static const uint8_t t12l[] = { + 4, 4, 6, 8, 9, 10, 10, 10, + 4, 5, 6, 7, 9, 9, 10, 10, + 6, 6, 7, 8, 9, 10, 9, 10, + 7, 7, 8, 8, 9, 10, 10, 10, + 8, 8, 9, 9, 10, 10, 10, 11, + 9, 9, 10, 10, 10, 11, 10, 11, + 9, 9, 9, 10, 10, 11, 11, 12, + 10, 10, 10, 11, 11, 11, 11, 12 +}; + +static const uint8_t t13l[] = { + 1, 5, 7, 8, 9, 10, 10, 11, 10, 11, 12, 12, 13, 13, 14, 14, + 4, 6, 8, 9, 10, 10, 11, 11, 11, 11, 12, 12, 13, 14, 14, 14, + 7, 8, 9, 10, 11, 11, 12, 12, 11, 12, 12, 13, 13, 14, 15, 15, + 8, 9, 10, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 15, 15, + 9, 9, 11, 11, 12, 12, 13, 13, 12, 13, 13, 14, 14, 15, 15, 16, + 10, 10, 11, 12, 12, 12, 13, 13, 13, 13, 14, 13, 15, 15, 16, 16, + 10, 11, 12, 12, 13, 13, 13, 13, 13, 14, 14, 14, 15, 15, 16, 16, + 11, 11, 12, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 16, 18, 18, + 10, 10, 11, 12, 12, 13, 13, 14, 14, 14, 14, 15, 15, 16, 17, 17, + 11, 11, 12, 12, 13, 13, 13, 15, 14, 15, 15, 16, 16, 16, 18, 17, + 11, 12, 12, 13, 13, 14, 14, 15, 14, 15, 16, 15, 16, 17, 18, 19, + 12, 12, 12, 13, 14, 14, 14, 14, 15, 15, 15, 16, 17, 17, 17, 18, + 12, 13, 13, 14, 14, 15, 14, 15, 16, 16, 17, 17, 17, 18, 18, 18, + 13, 13, 14, 15, 15, 15, 16, 16, 16, 16, 16, 17, 18, 17, 18, 18, + 14, 14, 14, 15, 15, 15, 17, 16, 16, 19, 17, 17, 17, 19, 18, 18, + 13, 14, 15, 16, 16, 16, 17, 16, 17, 17, 18, 18, 21, 20, 21, 18 +}; + +static const uint8_t t15l[] = { + 3, 5, 6, 8, 8, 9, 10, 10, 10, 11, 11, 12, 12, 12, 13, 14, + 5, 5, 7, 8, 9, 9, 10, 10, 10, 11, 11, 12, 12, 12, 13, 13, + 6, 7, 7, 8, 9, 9, 10, 10, 10, 11, 11, 12, 12, 13, 13, 13, + 7, 8, 8, 9, 9, 10, 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, + 8, 8, 9, 9, 10, 10, 11, 11, 11, 11, 12, 12, 12, 13, 13, 13, + 9, 9, 9, 10, 10, 10, 11, 11, 11, 11, 12, 12, 13, 13, 13, 14, + 10, 9, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 13, 13, 14, 14, + 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13, 13, 14, + 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 14, 14, 14, + 10, 10, 11, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, + 11, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13, 13, 13, 14, 15, 14, + 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15, + 12, 12, 11, 12, 12, 12, 13, 13, 13, 13, 13, 13, 14, 14, 15, 15, + 12, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 14, 15, 15, + 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 14, 15, + 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 15, 15, 15, 15 +}; + +static const uint8_t t16_5l[] = { + 1, 5, 7, 9, 10, 10, 11, 11, 12, 12, 12, 13, 13, 13, 14, 11, + 4, 6, 8, 9, 10, 11, 11, 11, 12, 12, 12, 13, 14, 13, 14, 11, + 7, 8, 9, 10, 11, 11, 12, 12, 13, 12, 13, 13, 13, 14, 14, 12, + 9, 9, 10, 11, 11, 12, 12, 12, 13, 13, 14, 14, 14, 15, 15, 13, + 10, 10, 11, 11, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15, 15, 12, + 10, 10, 11, 11, 12, 13, 13, 14, 13, 14, 14, 15, 15, 15, 16, 13, + 11, 11, 11, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 16, 13, + 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 15, 15, 17, 17, 13, + 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 13, + 12, 12, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 15, 16, 15, 14, + 12, 13, 12, 13, 14, 14, 14, 14, 15, 16, 16, 16, 17, 17, 16, 13, + 13, 13, 13, 13, 14, 14, 15, 16, 16, 16, 16, 16, 16, 15, 16, 14, + 13, 14, 14, 14, 14, 15, 15, 15, 15, 17, 16, 16, 16, 16, 18, 14, + 15, 14, 14, 14, 15, 15, 16, 16, 16, 18, 17, 17, 17, 19, 17, 14, + 14, 15, 13, 14, 16, 16, 15, 16, 16, 17, 18, 17, 19, 17, 16, 14, + 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 12 +}; + +static const uint8_t t16l[] = { + 1, 5, 7, 9, 10, 10, 11, 11, 12, 12, 12, 13, 13, 13, 14, 10, + 4, 6, 8, 9, 10, 11, 11, 11, 12, 12, 12, 13, 14, 13, 14, 10, + 7, 8, 9, 10, 11, 11, 12, 12, 13, 12, 13, 13, 13, 14, 14, 11, + 9, 9, 10, 11, 11, 12, 12, 12, 13, 13, 14, 14, 14, 15, 15, 12, + 10, 10, 11, 11, 12, 12, 13, 13, 13, 14, 14, 14, 15, 15, 15, 11, + 10, 10, 11, 11, 12, 13, 13, 14, 13, 14, 14, 15, 15, 15, 16, 12, + 11, 11, 11, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 16, 12, + 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 15, 15, 17, 17, 12, + 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 12, + 12, 12, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 15, 16, 15, 13, + 12, 13, 12, 13, 14, 14, 14, 14, 15, 16, 16, 16, 17, 17, 16, 12, + 13, 13, 13, 13, 14, 14, 15, 16, 16, 16, 16, 16, 16, 15, 16, 13, + 13, 14, 14, 14, 14, 15, 15, 15, 15, 17, 16, 16, 16, 16, 18, 13, + 15, 14, 14, 14, 15, 15, 16, 16, 16, 18, 17, 17, 17, 19, 17, 13, + 14, 15, 13, 14, 16, 16, 15, 16, 16, 17, 18, 17, 19, 17, 16, 13, + 10, 10, 10, 11, 11, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 10 +}; + +static const uint8_t t24l[] = { + 4, 5, 7, 8, 9, 10, 10, 11, 11, 12, 12, 12, 12, 12, 13, 10, + 5, 6, 7, 8, 9, 10, 10, 11, 11, 11, 12, 12, 12, 12, 12, 10, + 7, 7, 8, 9, 9, 10, 10, 11, 11, 11, 11, 12, 12, 12, 13, 9, + 8, 8, 9, 9, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 9, + 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 12, 12, 12, 12, 13, 9, + 10, 9, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 12, 9, + 10, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 12, 13, 9, + 11, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13, 10, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 10, + 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13, 13, 10, + 12, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 10, + 12, 12, 11, 11, 11, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 10, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 10, + 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 10, + 13, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 10, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 6 +}; + +const uint8_t t32l[] = { + 1 + 0, 4 + 1, 4 + 1, 5 + 2, 4 + 1, 6 + 2, 5 + 2, 6 + 3, + 4 + 1, 5 + 2, 5 + 2, 6 + 3, 5 + 2, 6 + 3, 6 + 3, 6 + 4 +}; + +const uint8_t t33l[] = { + 4 + 0, 4 + 1, 4 + 1, 4 + 2, 4 + 1, 4 + 2, 4 + 2, 4 + 3, + 4 + 1, 4 + 2, 4 + 2, 4 + 3, 4 + 2, 4 + 3, 4 + 3, 4 + 4 +}; + + +const struct huffcodetab ht[HTN] = { + /* xlen, linmax, table, hlen */ + {0, 0, NULL, NULL}, + {2, 0, t1HB, t1l}, + {3, 0, t2HB, t2l}, + {3, 0, t3HB, t3l}, + {0, 0, NULL, NULL}, /* Apparently not used */ + {4, 0, t5HB, t5l}, + {4, 0, t6HB, t6l}, + {6, 0, t7HB, t7l}, + {6, 0, t8HB, t8l}, + {6, 0, t9HB, t9l}, + {8, 0, t10HB, t10l}, + {8, 0, t11HB, t11l}, + {8, 0, t12HB, t12l}, + {16, 0, t13HB, t13l}, + {0, 0, NULL, t16_5l}, /* Apparently not used */ + {16, 0, t15HB, t15l}, + + {1, 1, t16HB, t16l}, + {2, 3, t16HB, t16l}, + {3, 7, t16HB, t16l}, + {4, 15, t16HB, t16l}, + {6, 63, t16HB, t16l}, + {8, 255, t16HB, t16l}, + {10, 1023, t16HB, t16l}, + {13, 8191, t16HB, t16l}, + + {4, 15, t24HB, t24l}, + {5, 31, t24HB, t24l}, + {6, 63, t24HB, t24l}, + {7, 127, t24HB, t24l}, + {8, 255, t24HB, t24l}, + {9, 511, t24HB, t24l}, + {11, 2047, t24HB, t24l}, + {13, 8191, t24HB, t24l}, + + {0, 0, t32HB, t32l}, + {0, 0, t33HB, t33l}, +}; + + + + + +/* for (i = 0; i < 16*16; i++) { + * largetbl[i] = ((ht[16].hlen[i]) << 16) + ht[24].hlen[i]; + * } + */ +const uint32_t largetbl[16 * 16] = { + 0x010004, 0x050005, 0x070007, 0x090008, 0x0a0009, 0x0a000a, 0x0b000a, 0x0b000b, + 0x0c000b, 0x0c000c, 0x0c000c, 0x0d000c, 0x0d000c, 0x0d000c, 0x0e000d, 0x0a000a, + 0x040005, 0x060006, 0x080007, 0x090008, 0x0a0009, 0x0b000a, 0x0b000a, 0x0b000b, + 0x0c000b, 0x0c000b, 0x0c000c, 0x0d000c, 0x0e000c, 0x0d000c, 0x0e000c, 0x0a000a, + 0x070007, 0x080007, 0x090008, 0x0a0009, 0x0b0009, 0x0b000a, 0x0c000a, 0x0c000b, + 0x0d000b, 0x0c000b, 0x0d000b, 0x0d000c, 0x0d000c, 0x0e000c, 0x0e000d, 0x0b0009, + 0x090008, 0x090008, 0x0a0009, 0x0b0009, 0x0b000a, 0x0c000a, 0x0c000a, 0x0c000b, + 0x0d000b, 0x0d000b, 0x0e000b, 0x0e000c, 0x0e000c, 0x0f000c, 0x0f000c, 0x0c0009, + 0x0a0009, 0x0a0009, 0x0b0009, 0x0b000a, 0x0c000a, 0x0c000a, 0x0d000a, 0x0d000b, + 0x0d000b, 0x0e000b, 0x0e000c, 0x0e000c, 0x0f000c, 0x0f000c, 0x0f000d, 0x0b0009, + 0x0a000a, 0x0a0009, 0x0b000a, 0x0b000a, 0x0c000a, 0x0d000a, 0x0d000b, 0x0e000b, + 0x0d000b, 0x0e000b, 0x0e000c, 0x0f000c, 0x0f000c, 0x0f000c, 0x10000c, 0x0c0009, + 0x0b000a, 0x0b000a, 0x0b000a, 0x0c000a, 0x0d000a, 0x0d000b, 0x0d000b, 0x0d000b, + 0x0e000b, 0x0e000c, 0x0e000c, 0x0e000c, 0x0f000c, 0x0f000c, 0x10000d, 0x0c0009, + 0x0b000b, 0x0b000a, 0x0c000a, 0x0c000a, 0x0d000b, 0x0d000b, 0x0d000b, 0x0e000b, + 0x0e000c, 0x0f000c, 0x0f000c, 0x0f000c, 0x0f000c, 0x11000d, 0x11000d, 0x0c000a, + 0x0b000b, 0x0c000b, 0x0c000b, 0x0d000b, 0x0d000b, 0x0d000b, 0x0e000b, 0x0e000b, + 0x0f000b, 0x0f000c, 0x0f000c, 0x0f000c, 0x10000c, 0x10000d, 0x10000d, 0x0c000a, + 0x0c000b, 0x0c000b, 0x0c000b, 0x0d000b, 0x0d000b, 0x0e000b, 0x0e000b, 0x0f000c, + 0x0f000c, 0x0f000c, 0x0f000c, 0x10000c, 0x0f000d, 0x10000d, 0x0f000d, 0x0d000a, + 0x0c000c, 0x0d000b, 0x0c000b, 0x0d000b, 0x0e000b, 0x0e000c, 0x0e000c, 0x0e000c, + 0x0f000c, 0x10000c, 0x10000c, 0x10000d, 0x11000d, 0x11000d, 0x10000d, 0x0c000a, + 0x0d000c, 0x0d000c, 0x0d000b, 0x0d000b, 0x0e000b, 0x0e000c, 0x0f000c, 0x10000c, + 0x10000c, 0x10000c, 0x10000c, 0x10000d, 0x10000d, 0x0f000d, 0x10000d, 0x0d000a, + 0x0d000c, 0x0e000c, 0x0e000c, 0x0e000c, 0x0e000c, 0x0f000c, 0x0f000c, 0x0f000c, + 0x0f000c, 0x11000c, 0x10000d, 0x10000d, 0x10000d, 0x10000d, 0x12000d, 0x0d000a, + 0x0f000c, 0x0e000c, 0x0e000c, 0x0e000c, 0x0f000c, 0x0f000c, 0x10000c, 0x10000c, + 0x10000d, 0x12000d, 0x11000d, 0x11000d, 0x11000d, 0x13000d, 0x11000d, 0x0d000a, + 0x0e000d, 0x0f000c, 0x0d000c, 0x0e000c, 0x10000c, 0x10000c, 0x0f000c, 0x10000d, + 0x10000d, 0x11000d, 0x12000d, 0x11000d, 0x13000d, 0x11000d, 0x10000d, 0x0d000a, + 0x0a0009, 0x0a0009, 0x0a0009, 0x0b0009, 0x0b0009, 0x0c0009, 0x0c0009, 0x0c0009, + 0x0d0009, 0x0d0009, 0x0d0009, 0x0d000a, 0x0d000a, 0x0d000a, 0x0d000a, 0x0a0006 +}; + +/* for (i = 0; i < 3*3; i++) { + * table23[i] = ((ht[2].hlen[i]) << 16) + ht[3].hlen[i]; + * } + */ +const uint32_t table23[3 * 3] = { + 0x010002, 0x040003, 0x070007, + 0x040004, 0x050004, 0x070007, + 0x060006, 0x070007, 0x080008 +}; + +/* for (i = 0; i < 4*4; i++) { + * table56[i] = ((ht[5].hlen[i]) << 16) + ht[6].hlen[i]; + * } + */ +const uint32_t table56[4 * 4] = { + 0x010003, 0x040004, 0x070006, 0x080008, 0x040004, 0x050004, 0x080006, 0x090007, + 0x070005, 0x080006, 0x090007, 0x0a0008, 0x080007, 0x080007, 0x090008, 0x0a0009 +}; + + + +/* + * 0: MPEG-2 LSF + * 1: MPEG-1 + * 2: MPEG-2.5 LSF FhG extention (1995-07-11 shn) + */ + +typedef enum { + MPEG_2 = 0, + MPEG_1 = 1, + MPEG_25 = 2 +} MPEG_t; + +const int bitrate_table[3][16] = { + {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1}, /* MPEG 2 */ + {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, -1}, /* MPEG 1 */ + {0, 8, 16, 24, 32, 40, 48, 56, 64, -1, -1, -1, -1, -1, -1, -1}, /* MPEG 2.5 */ +}; + +const int samplerate_table[3][4] = { + {22050, 24000, 16000, -1}, /* MPEG 2 */ + {44100, 48000, 32000, -1}, /* MPEG 1 */ + {11025, 12000, 8000, -1}, /* MPEG 2.5 */ +}; + +int +lame_get_bitrate(int mpeg_version, int table_index) +{ + if (0 <= mpeg_version && mpeg_version <= 2) { + if (0 <= table_index && table_index <= 15) { + return bitrate_table[mpeg_version][table_index]; + } + } + return -1; +} + +int +lame_get_samplerate(int mpeg_version, int table_index) +{ + if (0 <= mpeg_version && mpeg_version <= 2) { + if (0 <= table_index && table_index <= 3) { + return samplerate_table[mpeg_version][table_index]; + } + } + return -1; +} + + +/* This is the scfsi_band table from 2.4.2.7 of the IS */ +const int scfsi_band[5] = { 0, 6, 11, 16, 21 }; + +/* end of tables.c */ diff --git a/pkg/lame/clame/tables.h b/pkg/lame/clame/tables.h new file mode 100644 index 0000000..0dd7deb --- /dev/null +++ b/pkg/lame/clame/tables.h @@ -0,0 +1,95 @@ +/* + * MPEG layer 3 tables include file + * + * Copyright (c) 1999 Albert L Faber + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef LAME_TABLES_H +#define LAME_TABLES_H + +#if 0 +typedef struct { + unsigned char no; + unsigned char width; + unsigned char minval_2; + float quiet_thr; + float norm; + float bark; +} type1_t; + +typedef struct { + unsigned char no; + unsigned char width; + float quiet_thr; + float norm; + float SNR; + float bark; +} type2_t; + +typedef struct { + unsigned int no:5; + unsigned int cbw:3; + unsigned int bu:6; + unsigned int bo:6; + unsigned int w1_576:10; + unsigned int w2_576:10; +} type34_t; + +typedef struct { + size_t len1; + const type1_t *const tab1; + size_t len2; + const type2_t *const tab2; + size_t len3; + const type34_t *const tab3; + size_t len4; + const type34_t *const tab4; +} type5_t; + +extern const type5_t table5[6]; + +#endif + +#define HTN 34 + +struct huffcodetab { + const unsigned int xlen; /* max. x-index+ */ + const unsigned int linmax; /* max number to be stored in linbits */ + const uint16_t *table; /* pointer to array[xlen][ylen] */ + const uint8_t *hlen; /* pointer to array[xlen][ylen] */ +}; + +extern const struct huffcodetab ht[HTN]; + /* global memory block */ + /* array of all huffcodtable headers */ + /* 0..31 Huffman code table 0..31 */ + /* 32,33 count1-tables */ + +extern const uint8_t t32l[]; +extern const uint8_t t33l[]; + +extern const uint32_t largetbl[16 * 16]; +extern const uint32_t table23[3 * 3]; +extern const uint32_t table56[4 * 4]; + +extern const int scfsi_band[5]; + +extern const int bitrate_table [3][16]; +extern const int samplerate_table [3][ 4]; + +#endif /* LAME_TABLES_H */ diff --git a/pkg/lame/clame/takehiro.c b/pkg/lame/clame/takehiro.c new file mode 100644 index 0000000..67aba1b --- /dev/null +++ b/pkg/lame/clame/takehiro.c @@ -0,0 +1,1375 @@ +/* + * MP3 huffman table selecting and bit counting + * + * Copyright (c) 1999-2005 Takehiro TOMINAGA + * Copyright (c) 2002-2005 Gabriel Bouvigne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* $Id: takehiro.c,v 1.80 2017/09/06 15:07:30 robert Exp $ */ + +#ifdef HAVE_CONFIG_H +# include +#endif + + +#include "lame.h" +#include "machine.h" +#include "encoder.h" +#include "util.h" +#include "quantize_pvt.h" +#include "tables.h" + + +static const struct { + const int region0_count; + const int region1_count; +} subdv_table[23] = { + { + 0, 0}, /* 0 bands */ + { + 0, 0}, /* 1 bands */ + { + 0, 0}, /* 2 bands */ + { + 0, 0}, /* 3 bands */ + { + 0, 0}, /* 4 bands */ + { + 0, 1}, /* 5 bands */ + { + 1, 1}, /* 6 bands */ + { + 1, 1}, /* 7 bands */ + { + 1, 2}, /* 8 bands */ + { + 2, 2}, /* 9 bands */ + { + 2, 3}, /* 10 bands */ + { + 2, 3}, /* 11 bands */ + { + 3, 4}, /* 12 bands */ + { + 3, 4}, /* 13 bands */ + { + 3, 4}, /* 14 bands */ + { + 4, 5}, /* 15 bands */ + { + 4, 5}, /* 16 bands */ + { + 4, 6}, /* 17 bands */ + { + 5, 6}, /* 18 bands */ + { + 5, 6}, /* 19 bands */ + { + 5, 7}, /* 20 bands */ + { + 6, 7}, /* 21 bands */ + { + 6, 7}, /* 22 bands */ +}; + + + + + +/********************************************************************* + * nonlinear quantization of xr + * More accurate formula than the ISO formula. Takes into account + * the fact that we are quantizing xr -> ix, but we want ix^4/3 to be + * as close as possible to x^4/3. (taking the nearest int would mean + * ix is as close as possible to xr, which is different.) + * + * From Segher Boessenkool 11/1999 + * + * 09/2000: ASM code removed in favor of IEEE754 hack by Takehiro + * Tominaga. If you need the ASM code, check CVS circa Aug 2000. + * + * 01/2004: Optimizations by Gabriel Bouvigne + *********************************************************************/ + + + + + +static void +quantize_lines_xrpow_01(unsigned int l, FLOAT istep, const FLOAT * xr, int *ix) +{ + const FLOAT compareval0 = (1.0f - 0.4054f) / istep; + unsigned int i; + + assert(l > 0); + assert(l % 2 == 0); + for (i = 0; i < l; i += 2) { + FLOAT const xr_0 = xr[i+0]; + FLOAT const xr_1 = xr[i+1]; + int const ix_0 = (compareval0 > xr_0) ? 0 : 1; + int const ix_1 = (compareval0 > xr_1) ? 0 : 1; + ix[i+0] = ix_0; + ix[i+1] = ix_1; + } +} + + + +#ifdef TAKEHIRO_IEEE754_HACK + +typedef union { + float f; + int i; +} fi_union; + +#define MAGIC_FLOAT (65536*(128)) +#define MAGIC_INT 0x4b000000 + + +static void +quantize_lines_xrpow(unsigned int l, FLOAT istep, const FLOAT * xp, int *pi) +{ + fi_union *fi; + unsigned int remaining; + + assert(l > 0); + + fi = (fi_union *) pi; + + l = l >> 1; + remaining = l % 2; + l = l >> 1; + while (l--) { + double x0 = istep * xp[0]; + double x1 = istep * xp[1]; + double x2 = istep * xp[2]; + double x3 = istep * xp[3]; + + x0 += MAGIC_FLOAT; + fi[0].f = x0; + x1 += MAGIC_FLOAT; + fi[1].f = x1; + x2 += MAGIC_FLOAT; + fi[2].f = x2; + x3 += MAGIC_FLOAT; + fi[3].f = x3; + + fi[0].f = x0 + adj43asm[fi[0].i - MAGIC_INT]; + fi[1].f = x1 + adj43asm[fi[1].i - MAGIC_INT]; + fi[2].f = x2 + adj43asm[fi[2].i - MAGIC_INT]; + fi[3].f = x3 + adj43asm[fi[3].i - MAGIC_INT]; + + fi[0].i -= MAGIC_INT; + fi[1].i -= MAGIC_INT; + fi[2].i -= MAGIC_INT; + fi[3].i -= MAGIC_INT; + fi += 4; + xp += 4; + }; + if (remaining) { + double x0 = istep * xp[0]; + double x1 = istep * xp[1]; + + x0 += MAGIC_FLOAT; + fi[0].f = x0; + x1 += MAGIC_FLOAT; + fi[1].f = x1; + + fi[0].f = x0 + adj43asm[fi[0].i - MAGIC_INT]; + fi[1].f = x1 + adj43asm[fi[1].i - MAGIC_INT]; + + fi[0].i -= MAGIC_INT; + fi[1].i -= MAGIC_INT; + } + +} + + +#else + +/********************************************************************* + * XRPOW_FTOI is a macro to convert floats to ints. + * if XRPOW_FTOI(x) = nearest_int(x), then QUANTFAC(x)=adj43asm[x] + * ROUNDFAC= -0.0946 + * + * if XRPOW_FTOI(x) = floor(x), then QUANTFAC(x)=asj43[x] + * ROUNDFAC=0.4054 + * + * Note: using floor() or (int) is extremely slow. On machines where + * the TAKEHIRO_IEEE754_HACK code above does not work, it is worthwile + * to write some ASM for XRPOW_FTOI(). + *********************************************************************/ +#define XRPOW_FTOI(src,dest) ((dest) = (int)(src)) +#define QUANTFAC(rx) adj43[rx] +#define ROUNDFAC 0.4054 + + +static void +quantize_lines_xrpow(unsigned int l, FLOAT istep, const FLOAT * xr, int *ix) +{ + unsigned int remaining; + + assert(l > 0); + + l = l >> 1; + remaining = l % 2; + l = l >> 1; + while (l--) { + FLOAT x0, x1, x2, x3; + int rx0, rx1, rx2, rx3; + + x0 = *xr++ * istep; + x1 = *xr++ * istep; + XRPOW_FTOI(x0, rx0); + x2 = *xr++ * istep; + XRPOW_FTOI(x1, rx1); + x3 = *xr++ * istep; + XRPOW_FTOI(x2, rx2); + x0 += QUANTFAC(rx0); + XRPOW_FTOI(x3, rx3); + x1 += QUANTFAC(rx1); + XRPOW_FTOI(x0, *ix++); + x2 += QUANTFAC(rx2); + XRPOW_FTOI(x1, *ix++); + x3 += QUANTFAC(rx3); + XRPOW_FTOI(x2, *ix++); + XRPOW_FTOI(x3, *ix++); + }; + if (remaining) { + FLOAT x0, x1; + int rx0, rx1; + + x0 = *xr++ * istep; + x1 = *xr++ * istep; + XRPOW_FTOI(x0, rx0); + XRPOW_FTOI(x1, rx1); + x0 += QUANTFAC(rx0); + x1 += QUANTFAC(rx1); + XRPOW_FTOI(x0, *ix++); + XRPOW_FTOI(x1, *ix++); + } + +} + + + +#endif + + + +/********************************************************************* + * Quantization function + * This function will select which lines to quantize and call the + * proper quantization function + *********************************************************************/ + +static void +quantize_xrpow(const FLOAT * xp, int *pi, FLOAT istep, gr_info const *const cod_info, + calc_noise_data const *prev_noise) +{ + /* quantize on xr^(3/4) instead of xr */ + int sfb; + int sfbmax; + int j = 0; + int prev_data_use; + int *iData; + int accumulate = 0; + int accumulate01 = 0; + int *acc_iData; + const FLOAT *acc_xp; + + iData = pi; + acc_xp = xp; + acc_iData = iData; + + + /* Reusing previously computed data does not seems to work if global gain + is changed. Finding why it behaves this way would allow to use a cache of + previously computed values (let's 10 cached values per sfb) that would + probably provide a noticeable speedup */ + prev_data_use = (prev_noise && (cod_info->global_gain == prev_noise->global_gain)); + + if (cod_info->block_type == SHORT_TYPE) + sfbmax = 38; + else + sfbmax = 21; + + for (sfb = 0; sfb <= sfbmax; sfb++) { + int step = -1; + + if (prev_data_use || cod_info->block_type == NORM_TYPE) { + step = + cod_info->global_gain + - ((cod_info->scalefac[sfb] + (cod_info->preflag ? pretab[sfb] : 0)) + << (cod_info->scalefac_scale + 1)) + - cod_info->subblock_gain[cod_info->window[sfb]] * 8; + } + assert(cod_info->width[sfb] >= 0); + if (prev_data_use && (prev_noise->step[sfb] == step)) { + /* do not recompute this part, + but compute accumulated lines */ + if (accumulate) { + quantize_lines_xrpow(accumulate, istep, acc_xp, acc_iData); + accumulate = 0; + } + if (accumulate01) { + quantize_lines_xrpow_01(accumulate01, istep, acc_xp, acc_iData); + accumulate01 = 0; + } + } + else { /*should compute this part */ + int l; + l = cod_info->width[sfb]; + + if ((j + cod_info->width[sfb]) > cod_info->max_nonzero_coeff) { + /*do not compute upper zero part */ + int usefullsize; + usefullsize = cod_info->max_nonzero_coeff - j + 1; + memset(&pi[cod_info->max_nonzero_coeff], 0, + sizeof(int) * (576 - cod_info->max_nonzero_coeff)); + l = usefullsize; + + if (l < 0) { + l = 0; + } + + /* no need to compute higher sfb values */ + sfb = sfbmax + 1; + } + + /*accumulate lines to quantize */ + if (!accumulate && !accumulate01) { + acc_iData = iData; + acc_xp = xp; + } + if (prev_noise && + prev_noise->sfb_count1 > 0 && + sfb >= prev_noise->sfb_count1 && + prev_noise->step[sfb] > 0 && step >= prev_noise->step[sfb]) { + + if (accumulate) { + quantize_lines_xrpow(accumulate, istep, acc_xp, acc_iData); + accumulate = 0; + acc_iData = iData; + acc_xp = xp; + } + accumulate01 += l; + } + else { + if (accumulate01) { + quantize_lines_xrpow_01(accumulate01, istep, acc_xp, acc_iData); + accumulate01 = 0; + acc_iData = iData; + acc_xp = xp; + } + accumulate += l; + } + + if (l <= 0) { + /* rh: 20040215 + * may happen due to "prev_data_use" optimization + */ + if (accumulate01) { + quantize_lines_xrpow_01(accumulate01, istep, acc_xp, acc_iData); + accumulate01 = 0; + } + if (accumulate) { + quantize_lines_xrpow(accumulate, istep, acc_xp, acc_iData); + accumulate = 0; + } + + break; /* ends for-loop */ + } + } + if (sfb <= sfbmax) { + iData += cod_info->width[sfb]; + xp += cod_info->width[sfb]; + j += cod_info->width[sfb]; + } + } + if (accumulate) { /*last data part */ + quantize_lines_xrpow(accumulate, istep, acc_xp, acc_iData); + accumulate = 0; + } + if (accumulate01) { /*last data part */ + quantize_lines_xrpow_01(accumulate01, istep, acc_xp, acc_iData); + accumulate01 = 0; + } + +} + + + + +/*************************************************************************/ +/* ix_max */ +/*************************************************************************/ + +static int +ix_max(const int *ix, const int *end) +{ + int max1 = 0, max2 = 0; + + do { + int const x1 = *ix++; + int const x2 = *ix++; + if (max1 < x1) + max1 = x1; + + if (max2 < x2) + max2 = x2; + } while (ix < end); + if (max1 < max2) + max1 = max2; + return max1; +} + + + + + + + + +static int +count_bit_ESC(const int *ix, const int *const end, int t1, const int t2, unsigned int *const s) +{ + /* ESC-table is used */ + unsigned int const linbits = ht[t1].xlen * 65536u + ht[t2].xlen; + unsigned int sum = 0, sum2; + + do { + unsigned int x = *ix++; + unsigned int y = *ix++; + + if (x >= 15u) { + x = 15u; + sum += linbits; + } + if (y >= 15u) { + y = 15u; + sum += linbits; + } + x <<= 4u; + x += y; + sum += largetbl[x]; + } while (ix < end); + + sum2 = sum & 0xffffu; + sum >>= 16u; + + if (sum > sum2) { + sum = sum2; + t1 = t2; + } + + *s += sum; + return t1; +} + + +static int +count_bit_noESC(const int *ix, const int *end, int mx, unsigned int *s) +{ + /* No ESC-words */ + unsigned int sum1 = 0; + const uint8_t *const hlen1 = ht[1].hlen; + (void) mx; + + do { + unsigned int const x0 = *ix++; + unsigned int const x1 = *ix++; + sum1 += hlen1[ x0+x0 + x1 ]; + } while (ix < end); + + *s += sum1; + return 1; +} + + +static const int huf_tbl_noESC[] = { + 1, 2, 5, 7, 7, 10, 10, 13, 13, 13, 13, 13, 13, 13, 13 +}; + + +static int +count_bit_noESC_from2(const int *ix, const int *end, int max, unsigned int *s) +{ + int t1 = huf_tbl_noESC[max - 1]; + /* No ESC-words */ + const unsigned int xlen = ht[t1].xlen; + uint32_t const* table = (t1 == 2) ? &table23[0] : &table56[0]; + unsigned int sum = 0, sum2; + + do { + unsigned int const x0 = *ix++; + unsigned int const x1 = *ix++; + sum += table[ x0 * xlen + x1 ]; + } while (ix < end); + + sum2 = sum & 0xffffu; + sum >>= 16u; + + if (sum > sum2) { + sum = sum2; + t1++; + } + + *s += sum; + return t1; +} + + +inline static int +count_bit_noESC_from3(const int *ix, const int *end, int max, unsigned int * s) +{ + int t1 = huf_tbl_noESC[max - 1]; + /* No ESC-words */ + unsigned int sum1 = 0; + unsigned int sum2 = 0; + unsigned int sum3 = 0; + const unsigned int xlen = ht[t1].xlen; + const uint8_t *const hlen1 = ht[t1].hlen; + const uint8_t *const hlen2 = ht[t1 + 1].hlen; + const uint8_t *const hlen3 = ht[t1 + 2].hlen; + int t; + + do { + unsigned int x0 = *ix++; + unsigned int x1 = *ix++; + unsigned int x = x0 * xlen + x1; + sum1 += hlen1[x]; + sum2 += hlen2[x]; + sum3 += hlen3[x]; + } while (ix < end); + + t = t1; + if (sum1 > sum2) { + sum1 = sum2; + t++; + } + if (sum1 > sum3) { + sum1 = sum3; + t = t1 + 2; + } + *s += sum1; + + return t; +} + + +/*************************************************************************/ +/* choose table */ +/*************************************************************************/ + +/* + Choose the Huffman table that will encode ix[begin..end] with + the fewest bits. + + Note: This code contains knowledge about the sizes and characteristics + of the Huffman tables as defined in the IS (Table B.7), and will not work + with any arbitrary tables. +*/ +static int count_bit_null(const int* ix, const int* end, int max, unsigned int* s) +{ + (void) ix; + (void) end; + (void) max; + (void) s; + return 0; +} + +typedef int (*count_fnc)(const int* ix, const int* end, int max, unsigned int* s); + +static const count_fnc count_fncs[] = +{ &count_bit_null +, &count_bit_noESC +, &count_bit_noESC_from2 +, &count_bit_noESC_from2 +, &count_bit_noESC_from3 +, &count_bit_noESC_from3 +, &count_bit_noESC_from3 +, &count_bit_noESC_from3 +, &count_bit_noESC_from3 +, &count_bit_noESC_from3 +, &count_bit_noESC_from3 +, &count_bit_noESC_from3 +, &count_bit_noESC_from3 +, &count_bit_noESC_from3 +, &count_bit_noESC_from3 +, &count_bit_noESC_from3 +}; + +static int +choose_table_nonMMX(const int *ix, const int *const end, int *const _s) +{ + unsigned int* s = (unsigned int*)_s; + unsigned int max; + int choice, choice2; + max = ix_max(ix, end); + + if (max <= 15) { + return count_fncs[max](ix, end, max, s); + } + /* try tables with linbits */ + if (max > IXMAX_VAL) { + *s = LARGE_BITS; + return -1; + } + max -= 15u; + for (choice2 = 24; choice2 < 32; choice2++) { + if (ht[choice2].linmax >= max) { + break; + } + } + + for (choice = choice2 - 8; choice < 24; choice++) { + if (ht[choice].linmax >= max) { + break; + } + } + return count_bit_ESC(ix, end, choice, choice2, s); +} + + + +/*************************************************************************/ +/* count_bit */ +/*************************************************************************/ +int +noquant_count_bits(lame_internal_flags const *const gfc, + gr_info * const gi, calc_noise_data * prev_noise) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + int bits = 0; + int i, a1, a2; + int const *const ix = gi->l3_enc; + + i = Min(576, ((gi->max_nonzero_coeff + 2) >> 1) << 1); + + if (prev_noise) + prev_noise->sfb_count1 = 0; + + /* Determine count1 region */ + for (; i > 1; i -= 2) + if (ix[i - 1] | ix[i - 2]) + break; + gi->count1 = i; + + /* Determines the number of bits to encode the quadruples. */ + a1 = a2 = 0; + for (; i > 3; i -= 4) { + int x4 = ix[i-4]; + int x3 = ix[i-3]; + int x2 = ix[i-2]; + int x1 = ix[i-1]; + int p; + /* hack to check if all values <= 1 */ + if ((unsigned int) (x4 | x3 | x2 | x1) > 1) + break; + + p = ((x4 * 2 + x3) * 2 + x2) * 2 + x1; + a1 += t32l[p]; + a2 += t33l[p]; + } + + bits = a1; + gi->count1table_select = 0; + if (a1 > a2) { + bits = a2; + gi->count1table_select = 1; + } + + gi->count1bits = bits; + gi->big_values = i; + if (i == 0) + return bits; + + if (gi->block_type == SHORT_TYPE) { + a1 = 3 * gfc->scalefac_band.s[3]; + if (a1 > gi->big_values) + a1 = gi->big_values; + a2 = gi->big_values; + + } + else if (gi->block_type == NORM_TYPE) { + assert(i <= 576); /* bv_scf has 576 entries (0..575) */ + a1 = gi->region0_count = gfc->sv_qnt.bv_scf[i - 2]; + a2 = gi->region1_count = gfc->sv_qnt.bv_scf[i - 1]; + + assert(a1 + a2 + 2 < SBPSY_l); + a2 = gfc->scalefac_band.l[a1 + a2 + 2]; + a1 = gfc->scalefac_band.l[a1 + 1]; + if (a2 < i) + gi->table_select[2] = gfc->choose_table(ix + a2, ix + i, &bits); + + } + else { + gi->region0_count = 7; + /*gi->region1_count = SBPSY_l - 7 - 1; */ + gi->region1_count = SBMAX_l - 1 - 7 - 1; + a1 = gfc->scalefac_band.l[7 + 1]; + a2 = i; + if (a1 > a2) { + a1 = a2; + } + } + + + /* have to allow for the case when bigvalues < region0 < region1 */ + /* (and region0, region1 are ignored) */ + a1 = Min(a1, i); + a2 = Min(a2, i); + + assert(a1 >= 0); + assert(a2 >= 0); + + /* Count the number of bits necessary to code the bigvalues region. */ + if (0 < a1) + gi->table_select[0] = gfc->choose_table(ix, ix + a1, &bits); + if (a1 < a2) + gi->table_select[1] = gfc->choose_table(ix + a1, ix + a2, &bits); + if (cfg->use_best_huffman == 2) { + gi->part2_3_length = bits; + best_huffman_divide(gfc, gi); + bits = gi->part2_3_length; + } + + + if (prev_noise) { + if (gi->block_type == NORM_TYPE) { + int sfb = 0; + while (gfc->scalefac_band.l[sfb] < gi->big_values) { + sfb++; + } + prev_noise->sfb_count1 = sfb; + } + } + + return bits; +} + +int +count_bits(lame_internal_flags const *const gfc, + const FLOAT * const xr, gr_info * const gi, calc_noise_data * prev_noise) +{ + int *const ix = gi->l3_enc; + + /* since quantize_xrpow uses table lookup, we need to check this first: */ + FLOAT const w = (IXMAX_VAL) / IPOW20(gi->global_gain); + + if (gi->xrpow_max > w) + return LARGE_BITS; + + quantize_xrpow(xr, ix, IPOW20(gi->global_gain), gi, prev_noise); + + if (gfc->sv_qnt.substep_shaping & 2) { + int sfb, j = 0; + /* 0.634521682242439 = 0.5946*2**(.5*0.1875) */ + int const gain = gi->global_gain + gi->scalefac_scale; + const FLOAT roundfac = 0.634521682242439 / IPOW20(gain); + for (sfb = 0; sfb < gi->sfbmax; sfb++) { + int const width = gi->width[sfb]; + assert(width >= 0); + if (!gfc->sv_qnt.pseudohalf[sfb]) { + j += width; + } + else { + int k; + for (k = j, j += width; k < j; ++k) { + ix[k] = (xr[k] >= roundfac) ? ix[k] : 0; + } + } + } + } + return noquant_count_bits(gfc, gi, prev_noise); +} + +/*********************************************************************** + re-calculate the best scalefac_compress using scfsi + the saved bits are kept in the bit reservoir. + **********************************************************************/ + + +inline static void +recalc_divide_init(const lame_internal_flags * const gfc, + gr_info const *cod_info, + int const *const ix, int r01_bits[], int r01_div[], int r0_tbl[], int r1_tbl[]) +{ + int r0, r1, bigv, r0t, r1t, bits; + + bigv = cod_info->big_values; + + for (r0 = 0; r0 <= 7 + 15; r0++) { + r01_bits[r0] = LARGE_BITS; + } + + for (r0 = 0; r0 < 16; r0++) { + int const a1 = gfc->scalefac_band.l[r0 + 1]; + int r0bits; + if (a1 >= bigv) + break; + r0bits = 0; + r0t = gfc->choose_table(ix, ix + a1, &r0bits); + + for (r1 = 0; r1 < 8; r1++) { + int const a2 = gfc->scalefac_band.l[r0 + r1 + 2]; + if (a2 >= bigv) + break; + + bits = r0bits; + r1t = gfc->choose_table(ix + a1, ix + a2, &bits); + if (r01_bits[r0 + r1] > bits) { + r01_bits[r0 + r1] = bits; + r01_div[r0 + r1] = r0; + r0_tbl[r0 + r1] = r0t; + r1_tbl[r0 + r1] = r1t; + } + } + } +} + +inline static void +recalc_divide_sub(const lame_internal_flags * const gfc, + const gr_info * cod_info2, + gr_info * const gi, + const int *const ix, + const int r01_bits[], const int r01_div[], const int r0_tbl[], const int r1_tbl[]) +{ + int bits, r2, a2, bigv, r2t; + + bigv = cod_info2->big_values; + + for (r2 = 2; r2 < SBMAX_l + 1; r2++) { + a2 = gfc->scalefac_band.l[r2]; + if (a2 >= bigv) + break; + + bits = r01_bits[r2 - 2] + cod_info2->count1bits; + if (gi->part2_3_length <= bits) + break; + + r2t = gfc->choose_table(ix + a2, ix + bigv, &bits); + if (gi->part2_3_length <= bits) + continue; + + memcpy(gi, cod_info2, sizeof(gr_info)); + gi->part2_3_length = bits; + gi->region0_count = r01_div[r2 - 2]; + gi->region1_count = r2 - 2 - r01_div[r2 - 2]; + gi->table_select[0] = r0_tbl[r2 - 2]; + gi->table_select[1] = r1_tbl[r2 - 2]; + gi->table_select[2] = r2t; + } +} + + + + +void +best_huffman_divide(const lame_internal_flags * const gfc, gr_info * const gi) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + int i, a1, a2; + gr_info cod_info2; + int const *const ix = gi->l3_enc; + + int r01_bits[7 + 15 + 1]; + int r01_div[7 + 15 + 1]; + int r0_tbl[7 + 15 + 1]; + int r1_tbl[7 + 15 + 1]; + + + /* SHORT BLOCK stuff fails for MPEG2 */ + if (gi->block_type == SHORT_TYPE && cfg->mode_gr == 1) + return; + + + memcpy(&cod_info2, gi, sizeof(gr_info)); + if (gi->block_type == NORM_TYPE) { + recalc_divide_init(gfc, gi, ix, r01_bits, r01_div, r0_tbl, r1_tbl); + recalc_divide_sub(gfc, &cod_info2, gi, ix, r01_bits, r01_div, r0_tbl, r1_tbl); + } + + i = cod_info2.big_values; + if (i == 0 || (unsigned int) (ix[i - 2] | ix[i - 1]) > 1) + return; + + i = gi->count1 + 2; + if (i > 576) + return; + + /* Determines the number of bits to encode the quadruples. */ + memcpy(&cod_info2, gi, sizeof(gr_info)); + cod_info2.count1 = i; + a1 = a2 = 0; + + assert(i <= 576); + + for (; i > cod_info2.big_values; i -= 4) { + int const p = ((ix[i - 4] * 2 + ix[i - 3]) * 2 + ix[i - 2]) * 2 + ix[i - 1]; + a1 += t32l[p]; + a2 += t33l[p]; + } + cod_info2.big_values = i; + + cod_info2.count1table_select = 0; + if (a1 > a2) { + a1 = a2; + cod_info2.count1table_select = 1; + } + + cod_info2.count1bits = a1; + + if (cod_info2.block_type == NORM_TYPE) + recalc_divide_sub(gfc, &cod_info2, gi, ix, r01_bits, r01_div, r0_tbl, r1_tbl); + else { + /* Count the number of bits necessary to code the bigvalues region. */ + cod_info2.part2_3_length = a1; + a1 = gfc->scalefac_band.l[7 + 1]; + if (a1 > i) { + a1 = i; + } + if (a1 > 0) + cod_info2.table_select[0] = + gfc->choose_table(ix, ix + a1, (int *) &cod_info2.part2_3_length); + if (i > a1) + cod_info2.table_select[1] = + gfc->choose_table(ix + a1, ix + i, (int *) &cod_info2.part2_3_length); + if (gi->part2_3_length > cod_info2.part2_3_length) + memcpy(gi, &cod_info2, sizeof(gr_info)); + } +} + +static const int slen1_n[16] = { 1, 1, 1, 1, 8, 2, 2, 2, 4, 4, 4, 8, 8, 8, 16, 16 }; +static const int slen2_n[16] = { 1, 2, 4, 8, 1, 2, 4, 8, 2, 4, 8, 2, 4, 8, 4, 8 }; +const int slen1_tab[16] = { 0, 0, 0, 0, 3, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4 }; +const int slen2_tab[16] = { 0, 1, 2, 3, 0, 1, 2, 3, 1, 2, 3, 1, 2, 3, 2, 3 }; + +static void +scfsi_calc(int ch, III_side_info_t * l3_side) +{ + unsigned int i; + int s1, s2, c1, c2; + int sfb; + gr_info *const gi = &l3_side->tt[1][ch]; + gr_info const *const g0 = &l3_side->tt[0][ch]; + + for (i = 0; i < (sizeof(scfsi_band) / sizeof(int)) - 1; i++) { + for (sfb = scfsi_band[i]; sfb < scfsi_band[i + 1]; sfb++) { + if (g0->scalefac[sfb] != gi->scalefac[sfb] + && gi->scalefac[sfb] >= 0) + break; + } + if (sfb == scfsi_band[i + 1]) { + for (sfb = scfsi_band[i]; sfb < scfsi_band[i + 1]; sfb++) { + gi->scalefac[sfb] = -1; + } + l3_side->scfsi[ch][i] = 1; + } + } + + s1 = c1 = 0; + for (sfb = 0; sfb < 11; sfb++) { + if (gi->scalefac[sfb] == -1) + continue; + c1++; + if (s1 < gi->scalefac[sfb]) + s1 = gi->scalefac[sfb]; + } + + s2 = c2 = 0; + for (; sfb < SBPSY_l; sfb++) { + if (gi->scalefac[sfb] == -1) + continue; + c2++; + if (s2 < gi->scalefac[sfb]) + s2 = gi->scalefac[sfb]; + } + + for (i = 0; i < 16; i++) { + if (s1 < slen1_n[i] && s2 < slen2_n[i]) { + int const c = slen1_tab[i] * c1 + slen2_tab[i] * c2; + if (gi->part2_length > c) { + gi->part2_length = c; + gi->scalefac_compress = (int)i; + } + } + } +} + +/* +Find the optimal way to store the scalefactors. +Only call this routine after final scalefactors have been +chosen and the channel/granule will not be re-encoded. + */ +void +best_scalefac_store(const lame_internal_flags * gfc, + const int gr, const int ch, III_side_info_t * const l3_side) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + /* use scalefac_scale if we can */ + gr_info *const gi = &l3_side->tt[gr][ch]; + int sfb, i, j, l; + int recalc = 0; + + /* remove scalefacs from bands with ix=0. This idea comes + * from the AAC ISO docs. added mt 3/00 */ + /* check if l3_enc=0 */ + j = 0; + for (sfb = 0; sfb < gi->sfbmax; sfb++) { + int const width = gi->width[sfb]; + assert(width >= 0); + for (l = j, j += width; l < j; ++l) { + if (gi->l3_enc[l] != 0) + break; + } + if (l == j) + gi->scalefac[sfb] = recalc = -2; /* anything goes. */ + /* only best_scalefac_store and calc_scfsi + * know--and only they should know--about the magic number -2. + */ + } + + if (!gi->scalefac_scale && !gi->preflag) { + int s = 0; + for (sfb = 0; sfb < gi->sfbmax; sfb++) + if (gi->scalefac[sfb] > 0) + s |= gi->scalefac[sfb]; + + if (!(s & 1) && s != 0) { + for (sfb = 0; sfb < gi->sfbmax; sfb++) + if (gi->scalefac[sfb] > 0) + gi->scalefac[sfb] >>= 1; + + gi->scalefac_scale = recalc = 1; + } + } + + if (!gi->preflag && gi->block_type != SHORT_TYPE && cfg->mode_gr == 2) { + for (sfb = 11; sfb < SBPSY_l; sfb++) + if (gi->scalefac[sfb] < pretab[sfb] && gi->scalefac[sfb] != -2) + break; + if (sfb == SBPSY_l) { + for (sfb = 11; sfb < SBPSY_l; sfb++) + if (gi->scalefac[sfb] > 0) + gi->scalefac[sfb] -= pretab[sfb]; + + gi->preflag = recalc = 1; + } + } + + for (i = 0; i < 4; i++) + l3_side->scfsi[ch][i] = 0; + + if (cfg->mode_gr == 2 && gr == 1 + && l3_side->tt[0][ch].block_type != SHORT_TYPE + && l3_side->tt[1][ch].block_type != SHORT_TYPE) { + scfsi_calc(ch, l3_side); + recalc = 0; + } + for (sfb = 0; sfb < gi->sfbmax; sfb++) { + if (gi->scalefac[sfb] == -2) { + gi->scalefac[sfb] = 0; /* if anything goes, then 0 is a good choice */ + } + } + if (recalc) { + (void) scale_bitcount(gfc, gi); + } +} + + +#ifndef NDEBUG +static int +all_scalefactors_not_negative(int const *scalefac, int n) +{ + int i; + for (i = 0; i < n; ++i) { + if (scalefac[i] < 0) + return 0; + } + return 1; +} +#endif + + +/* number of bits used to encode scalefacs */ + +/* 18*slen1_tab[i] + 18*slen2_tab[i] */ +static const int scale_short[16] = { + 0, 18, 36, 54, 54, 36, 54, 72, 54, 72, 90, 72, 90, 108, 108, 126 +}; + +/* 17*slen1_tab[i] + 18*slen2_tab[i] */ +static const int scale_mixed[16] = { + 0, 18, 36, 54, 51, 35, 53, 71, 52, 70, 88, 69, 87, 105, 104, 122 +}; + +/* 11*slen1_tab[i] + 10*slen2_tab[i] */ +static const int scale_long[16] = { + 0, 10, 20, 30, 33, 21, 31, 41, 32, 42, 52, 43, 53, 63, 64, 74 +}; + + +/*************************************************************************/ +/* scale_bitcount */ +/*************************************************************************/ + +/* Also calculates the number of bits necessary to code the scalefactors. */ + +static int +mpeg1_scale_bitcount(const lame_internal_flags * gfc, gr_info * const cod_info) +{ + int k, sfb, max_slen1 = 0, max_slen2 = 0; + + /* maximum values */ + const int *tab; + int *const scalefac = cod_info->scalefac; + + (void) gfc; + assert(all_scalefactors_not_negative(scalefac, cod_info->sfbmax)); + + if (cod_info->block_type == SHORT_TYPE) { + tab = scale_short; + if (cod_info->mixed_block_flag) + tab = scale_mixed; + } + else { /* block_type == 1,2,or 3 */ + tab = scale_long; + if (!cod_info->preflag) { + for (sfb = 11; sfb < SBPSY_l; sfb++) + if (scalefac[sfb] < pretab[sfb]) + break; + + if (sfb == SBPSY_l) { + cod_info->preflag = 1; + for (sfb = 11; sfb < SBPSY_l; sfb++) + scalefac[sfb] -= pretab[sfb]; + } + } + } + + for (sfb = 0; sfb < cod_info->sfbdivide; sfb++) + if (max_slen1 < scalefac[sfb]) + max_slen1 = scalefac[sfb]; + + for (; sfb < cod_info->sfbmax; sfb++) + if (max_slen2 < scalefac[sfb]) + max_slen2 = scalefac[sfb]; + + /* from Takehiro TOMINAGA 10/99 + * loop over *all* posible values of scalefac_compress to find the + * one which uses the smallest number of bits. ISO would stop + * at first valid index */ + cod_info->part2_length = LARGE_BITS; + for (k = 0; k < 16; k++) { + if (max_slen1 < slen1_n[k] && max_slen2 < slen2_n[k] + && cod_info->part2_length > tab[k]) { + cod_info->part2_length = tab[k]; + cod_info->scalefac_compress = k; + } + } + return cod_info->part2_length == LARGE_BITS; +} + + + +/* + table of largest scalefactor values for MPEG2 +*/ +static const int max_range_sfac_tab[6][4] = { + {15, 15, 7, 7}, + {15, 15, 7, 0}, + {7, 3, 0, 0}, + {15, 31, 31, 0}, + {7, 7, 7, 0}, + {3, 3, 0, 0} +}; + + + + +/*************************************************************************/ +/* scale_bitcount_lsf */ +/*************************************************************************/ + +/* Also counts the number of bits to encode the scalefacs but for MPEG 2 */ +/* Lower sampling frequencies (24, 22.05 and 16 kHz.) */ + +/* This is reverse-engineered from section 2.4.3.2 of the MPEG2 IS, */ +/* "Audio Decoding Layer III" */ + +static int +mpeg2_scale_bitcount(const lame_internal_flags * gfc, gr_info * const cod_info) +{ + int table_number, row_in_table, partition, nr_sfb, window, over; + int i, sfb, max_sfac[4]; + const int *partition_table; + int const *const scalefac = cod_info->scalefac; + + /* + Set partition table. Note that should try to use table one, + but do not yet... + */ + if (cod_info->preflag) + table_number = 2; + else + table_number = 0; + + for (i = 0; i < 4; i++) + max_sfac[i] = 0; + + if (cod_info->block_type == SHORT_TYPE) { + row_in_table = 1; + partition_table = &nr_of_sfb_block[table_number][row_in_table][0]; + for (sfb = 0, partition = 0; partition < 4; partition++) { + nr_sfb = partition_table[partition] / 3; + for (i = 0; i < nr_sfb; i++, sfb++) + for (window = 0; window < 3; window++) + if (scalefac[sfb * 3 + window] > max_sfac[partition]) + max_sfac[partition] = scalefac[sfb * 3 + window]; + } + } + else { + row_in_table = 0; + partition_table = &nr_of_sfb_block[table_number][row_in_table][0]; + for (sfb = 0, partition = 0; partition < 4; partition++) { + nr_sfb = partition_table[partition]; + for (i = 0; i < nr_sfb; i++, sfb++) + if (scalefac[sfb] > max_sfac[partition]) + max_sfac[partition] = scalefac[sfb]; + } + } + + for (over = 0, partition = 0; partition < 4; partition++) { + if (max_sfac[partition] > max_range_sfac_tab[table_number][partition]) + over++; + } + if (!over) { + /* + Since no bands have been over-amplified, we can set scalefac_compress + and slen[] for the formatter + */ + static const int log2tab[] = { 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4 }; + + int slen1, slen2, slen3, slen4; + + cod_info->sfb_partition_table = nr_of_sfb_block[table_number][row_in_table]; + for (partition = 0; partition < 4; partition++) + cod_info->slen[partition] = log2tab[max_sfac[partition]]; + + /* set scalefac_compress */ + slen1 = cod_info->slen[0]; + slen2 = cod_info->slen[1]; + slen3 = cod_info->slen[2]; + slen4 = cod_info->slen[3]; + + switch (table_number) { + case 0: + cod_info->scalefac_compress = (((slen1 * 5) + slen2) << 4) + + (slen3 << 2) + + slen4; + break; + + case 1: + cod_info->scalefac_compress = 400 + (((slen1 * 5) + slen2) << 2) + + slen3; + break; + + case 2: + cod_info->scalefac_compress = 500 + (slen1 * 3) + slen2; + break; + + default: + ERRORF(gfc, "intensity stereo not implemented yet\n"); + break; + } + } +#ifdef DEBUG + if (over) + ERRORF(gfc, "---WARNING !! Amplification of some bands over limits\n"); +#endif + if (!over) { + assert(cod_info->sfb_partition_table); + cod_info->part2_length = 0; + for (partition = 0; partition < 4; partition++) + cod_info->part2_length += + cod_info->slen[partition] * cod_info->sfb_partition_table[partition]; + } + return over; +} + + +int +scale_bitcount(const lame_internal_flags * gfc, gr_info * cod_info) +{ + if (gfc->cfg.mode_gr == 2) { + return mpeg1_scale_bitcount(gfc, cod_info); + } + else { + return mpeg2_scale_bitcount(gfc, cod_info); + } +} + + +#ifdef MMX_choose_table +extern int choose_table_MMX(const int *ix, const int *const end, int *const s); +#endif + +void +huffman_init(lame_internal_flags * const gfc) +{ + int i; + + gfc->choose_table = choose_table_nonMMX; + +#ifdef MMX_choose_table + if (gfc->CPU_features.MMX) { + gfc->choose_table = choose_table_MMX; + } +#endif + + for (i = 2; i <= 576; i += 2) { + int scfb_anz = 0, bv_index; + while (gfc->scalefac_band.l[++scfb_anz] < i); + + bv_index = subdv_table[scfb_anz].region0_count; + while (gfc->scalefac_band.l[bv_index + 1] > i) + bv_index--; + + if (bv_index < 0) { + /* this is an indication that everything is going to + be encoded as region0: bigvalues < region0 < region1 + so lets set region0, region1 to some value larger + than bigvalues */ + bv_index = subdv_table[scfb_anz].region0_count; + } + + gfc->sv_qnt.bv_scf[i - 2] = bv_index; + + bv_index = subdv_table[scfb_anz].region1_count; + while (gfc->scalefac_band.l[bv_index + gfc->sv_qnt.bv_scf[i - 2] + 2] > i) + bv_index--; + + if (bv_index < 0) { + bv_index = subdv_table[scfb_anz].region1_count; + } + + gfc->sv_qnt.bv_scf[i - 1] = bv_index; + } +} diff --git a/pkg/lame/clame/util.c b/pkg/lame/clame/util.c new file mode 100644 index 0000000..43b457c --- /dev/null +++ b/pkg/lame/clame/util.c @@ -0,0 +1,1018 @@ +/* + * lame utility library source file + * + * Copyright (c) 1999 Albert L Faber + * Copyright (c) 2000-2005 Alexander Leidinger + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* $Id: util.c,v 1.159 2017/09/06 15:07:30 robert Exp $ */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "lame.h" +#include "machine.h" +#include "encoder.h" +#include "util.h" +#include "tables.h" + +#define PRECOMPUTE +#if defined(__FreeBSD__) && !defined(__alpha__) +# include +#endif + + +/*********************************************************************** +* +* Global Function Definitions +* +***********************************************************************/ +/*empty and close mallocs in gfc */ + +void +free_id3tag(lame_internal_flags * const gfc) +{ + gfc->tag_spec.language[0] = 0; + if (gfc->tag_spec.title != 0) { + free(gfc->tag_spec.title); + gfc->tag_spec.title = 0; + } + if (gfc->tag_spec.artist != 0) { + free(gfc->tag_spec.artist); + gfc->tag_spec.artist = 0; + } + if (gfc->tag_spec.album != 0) { + free(gfc->tag_spec.album); + gfc->tag_spec.album = 0; + } + if (gfc->tag_spec.comment != 0) { + free(gfc->tag_spec.comment); + gfc->tag_spec.comment = 0; + } + + if (gfc->tag_spec.albumart != 0) { + free(gfc->tag_spec.albumart); + gfc->tag_spec.albumart = 0; + gfc->tag_spec.albumart_size = 0; + gfc->tag_spec.albumart_mimetype = MIMETYPE_NONE; + } + if (gfc->tag_spec.v2_head != 0) { + FrameDataNode *node = gfc->tag_spec.v2_head; + do { + void *p = node->dsc.ptr.b; + void *q = node->txt.ptr.b; + void *r = node; + node = node->nxt; + free(p); + free(q); + free(r); + } while (node != 0); + gfc->tag_spec.v2_head = 0; + gfc->tag_spec.v2_tail = 0; + } +} + + +static void +free_global_data(lame_internal_flags * gfc) +{ + if (gfc && gfc->cd_psy) { + if (gfc->cd_psy->l.s3) { + /* XXX allocated in psymodel_init() */ + free(gfc->cd_psy->l.s3); + } + if (gfc->cd_psy->s.s3) { + /* XXX allocated in psymodel_init() */ + free(gfc->cd_psy->s.s3); + } + free(gfc->cd_psy); + gfc->cd_psy = 0; + } +} + + +void +freegfc(lame_internal_flags * const gfc) +{ /* bit stream structure */ + int i; + + if (gfc == 0) return; + + for (i = 0; i <= 2 * BPC; i++) + if (gfc->sv_enc.blackfilt[i] != NULL) { + free(gfc->sv_enc.blackfilt[i]); + gfc->sv_enc.blackfilt[i] = NULL; + } + if (gfc->sv_enc.inbuf_old[0]) { + free(gfc->sv_enc.inbuf_old[0]); + gfc->sv_enc.inbuf_old[0] = NULL; + } + if (gfc->sv_enc.inbuf_old[1]) { + free(gfc->sv_enc.inbuf_old[1]); + gfc->sv_enc.inbuf_old[1] = NULL; + } + + if (gfc->bs.buf != NULL) { + free(gfc->bs.buf); + gfc->bs.buf = NULL; + } + + if (gfc->VBR_seek_table.bag) { + free(gfc->VBR_seek_table.bag); + gfc->VBR_seek_table.bag = NULL; + gfc->VBR_seek_table.size = 0; + } + if (gfc->ATH) { + free(gfc->ATH); + } + if (gfc->sv_rpg.rgdata) { + free(gfc->sv_rpg.rgdata); + } + if (gfc->sv_enc.in_buffer_0) { + free(gfc->sv_enc.in_buffer_0); + } + if (gfc->sv_enc.in_buffer_1) { + free(gfc->sv_enc.in_buffer_1); + } + free_id3tag(gfc); + +#ifdef DECODE_ON_THE_FLY + if (gfc->hip) { + hip_decode_exit(gfc->hip); + gfc->hip = 0; + } +#endif + + free_global_data(gfc); + + free(gfc); +} + +void +calloc_aligned(aligned_pointer_t * ptr, unsigned int size, unsigned int bytes) +{ + if (ptr) { + if (!ptr->pointer) { + ptr->pointer = malloc(size + bytes); + if (ptr->pointer != 0) { + memset(ptr->pointer, 0, size + bytes); + if (bytes > 0) { + ptr->aligned = (void *) ((((size_t) ptr->pointer + bytes - 1) / bytes) * bytes); + } + else { + ptr->aligned = ptr->pointer; + } + } + else { + ptr->aligned = 0; + } + } + } +} + +void +free_aligned(aligned_pointer_t * ptr) +{ + if (ptr) { + if (ptr->pointer) { + free(ptr->pointer); + ptr->pointer = 0; + ptr->aligned = 0; + } + } +} + +/*those ATH formulas are returning +their minimum value for input = -1*/ + +static FLOAT +ATHformula_GB(FLOAT f, FLOAT value, FLOAT f_min, FLOAT f_max) +{ + /* from Painter & Spanias + modified by Gabriel Bouvigne to better fit the reality + ath = 3.640 * pow(f,-0.8) + - 6.800 * exp(-0.6*pow(f-3.4,2.0)) + + 6.000 * exp(-0.15*pow(f-8.7,2.0)) + + 0.6* 0.001 * pow(f,4.0); + + + In the past LAME was using the Painter &Spanias formula. + But we had some recurrent problems with HF content. + We measured real ATH values, and found the older formula + to be inacurate in the higher part. So we made this new + formula and this solved most of HF problematic testcases. + The tradeoff is that in VBR mode it increases a lot the + bitrate. */ + + +/*this curve can be udjusted according to the VBR scale: +it adjusts from something close to Painter & Spanias +on V9 up to Bouvigne's formula for V0. This way the VBR +bitrate is more balanced according to the -V value.*/ + + FLOAT ath; + + /* the following Hack allows to ask for the lowest value */ + if (f < -.3) + f = 3410; + + f /= 1000; /* convert to khz */ + f = Max(f_min, f); + f = Min(f_max, f); + + ath = 3.640 * pow(f, -0.8) + - 6.800 * exp(-0.6 * pow(f - 3.4, 2.0)) + + 6.000 * exp(-0.15 * pow(f - 8.7, 2.0)) + + (0.6 + 0.04 * value) * 0.001 * pow(f, 4.0); + return ath; +} + + + +FLOAT +ATHformula(SessionConfig_t const *cfg, FLOAT f) +{ + FLOAT ath; + switch (cfg->ATHtype) { + case 0: + ath = ATHformula_GB(f, 9, 0.1f, 24.0f); + break; + case 1: + ath = ATHformula_GB(f, -1, 0.1f, 24.0f); /*over sensitive, should probably be removed */ + break; + case 2: + ath = ATHformula_GB(f, 0, 0.1f, 24.0f); + break; + case 3: + ath = ATHformula_GB(f, 1, 0.1f, 24.0f) + 6; /*modification of GB formula by Roel */ + break; + case 4: + ath = ATHformula_GB(f, cfg->ATHcurve, 0.1f, 24.0f); + break; + case 5: + ath = ATHformula_GB(f, cfg->ATHcurve, 3.41f, 16.1f); + break; + default: + ath = ATHformula_GB(f, 0, 0.1f, 24.0f); + break; + } + return ath; +} + +/* see for example "Zwicker: Psychoakustik, 1982; ISBN 3-540-11401-7 */ +FLOAT +freq2bark(FLOAT freq) +{ + /* input: freq in hz output: barks */ + if (freq < 0) + freq = 0; + freq = freq * 0.001; + return 13.0 * atan(.76 * freq) + 3.5 * atan(freq * freq / (7.5 * 7.5)); +} + +#if 0 +extern FLOAT freq2cbw(FLOAT freq); + +/* see for example "Zwicker: Psychoakustik, 1982; ISBN 3-540-11401-7 */ +FLOAT +freq2cbw(FLOAT freq) +{ + /* input: freq in hz output: critical band width */ + freq = freq * 0.001; + return 25 + 75 * pow(1 + 1.4 * (freq * freq), 0.69); +} + +#endif + + + + +#define ABS(A) (((A)>0) ? (A) : -(A)) + +int +FindNearestBitrate(int bRate, /* legal rates from 8 to 320 */ + int version, int samplerate) +{ /* MPEG-1 or MPEG-2 LSF */ + int bitrate; + int i; + + if (samplerate < 16000) + version = 2; + + bitrate = bitrate_table[version][1]; + + for (i = 2; i <= 14; i++) { + if (bitrate_table[version][i] > 0) { + if (ABS(bitrate_table[version][i] - bRate) < ABS(bitrate - bRate)) + bitrate = bitrate_table[version][i]; + } + } + return bitrate; +} + + + + + +#ifndef Min +#define Min(A, B) ((A) < (B) ? (A) : (B)) +#endif +#ifndef Max +#define Max(A, B) ((A) > (B) ? (A) : (B)) +#endif + + +/* Used to find table index when + * we need bitrate-based values + * determined using tables + * + * bitrate in kbps + * + * Gabriel Bouvigne 2002-11-03 + */ +int +nearestBitrateFullIndex(uint16_t bitrate) +{ + /* borrowed from DM abr presets */ + + const int full_bitrate_table[] = + { 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320 }; + + + int lower_range = 0, lower_range_kbps = 0, upper_range = 0, upper_range_kbps = 0; + + + int b; + + + /* We assume specified bitrate will be 320kbps */ + upper_range_kbps = full_bitrate_table[16]; + upper_range = 16; + lower_range_kbps = full_bitrate_table[16]; + lower_range = 16; + + /* Determine which significant bitrates the value specified falls between, + * if loop ends without breaking then we were correct above that the value was 320 + */ + for (b = 0; b < 16; b++) { + if ((Max(bitrate, full_bitrate_table[b + 1])) != bitrate) { + upper_range_kbps = full_bitrate_table[b + 1]; + upper_range = b + 1; + lower_range_kbps = full_bitrate_table[b]; + lower_range = (b); + break; /* We found upper range */ + } + } + + /* Determine which range the value specified is closer to */ + if ((upper_range_kbps - bitrate) > (bitrate - lower_range_kbps)) { + return lower_range; + } + return upper_range; +} + + + + + +/* map frequency to a valid MP3 sample frequency + * + * Robert Hegemann 2000-07-01 + */ +int +map2MP3Frequency(int freq) +{ + if (freq <= 8000) + return 8000; + if (freq <= 11025) + return 11025; + if (freq <= 12000) + return 12000; + if (freq <= 16000) + return 16000; + if (freq <= 22050) + return 22050; + if (freq <= 24000) + return 24000; + if (freq <= 32000) + return 32000; + if (freq <= 44100) + return 44100; + + return 48000; +} + +int +BitrateIndex(int bRate, /* legal rates from 32 to 448 kbps */ + int version, /* MPEG-1 or MPEG-2/2.5 LSF */ + int samplerate) +{ /* convert bitrate in kbps to index */ + int i; + if (samplerate < 16000) + version = 2; + for (i = 0; i <= 14; i++) { + if (bitrate_table[version][i] > 0) { + if (bitrate_table[version][i] == bRate) { + return i; + } + } + } + return -1; +} + +/* convert samp freq in Hz to index */ + +int +SmpFrqIndex(int sample_freq, int *const version) +{ + switch (sample_freq) { + case 44100: + *version = 1; + return 0; + case 48000: + *version = 1; + return 1; + case 32000: + *version = 1; + return 2; + case 22050: + *version = 0; + return 0; + case 24000: + *version = 0; + return 1; + case 16000: + *version = 0; + return 2; + case 11025: + *version = 0; + return 0; + case 12000: + *version = 0; + return 1; + case 8000: + *version = 0; + return 2; + default: + *version = 0; + return -1; + } +} + + +/***************************************************************************** +* +* End of bit_stream.c package +* +*****************************************************************************/ + + + + + + + + + + +/* resampling via FIR filter, blackman window */ +inline static FLOAT +blackman(FLOAT x, FLOAT fcn, int l) +{ + /* This algorithm from: + SIGNAL PROCESSING ALGORITHMS IN FORTRAN AND C + S.D. Stearns and R.A. David, Prentice-Hall, 1992 + */ + FLOAT bkwn, x2; + FLOAT const wcn = (PI * fcn); + + x /= l; + if (x < 0) + x = 0; + if (x > 1) + x = 1; + x2 = x - .5; + + bkwn = 0.42 - 0.5 * cos(2 * x * PI) + 0.08 * cos(4 * x * PI); + if (fabs(x2) < 1e-9) + return wcn / PI; + else + return (bkwn * sin(l * wcn * x2) / (PI * l * x2)); + + +} + + + + +/* gcd - greatest common divisor */ +/* Joint work of Euclid and M. Hendry */ + +static int +gcd(int i, int j) +{ + /* assert ( i > 0 && j > 0 ); */ + return j ? gcd(j, i % j) : i; +} + + + +static int +fill_buffer_resample(lame_internal_flags * gfc, + sample_t * outbuf, + int desired_len, sample_t const *inbuf, int len, int *num_used, int ch) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + EncStateVar_t *esv = &gfc->sv_enc; + double resample_ratio = (double)cfg->samplerate_in / (double)cfg->samplerate_out; + int BLACKSIZE; + FLOAT offset, xvalue; + int i, j = 0, k; + int filter_l; + FLOAT fcn, intratio; + FLOAT *inbuf_old; + int bpc; /* number of convolution functions to pre-compute */ + bpc = cfg->samplerate_out / gcd(cfg->samplerate_out, cfg->samplerate_in); + if (bpc > BPC) + bpc = BPC; + + intratio = (fabs(resample_ratio - floor(.5 + resample_ratio)) < FLT_EPSILON); + fcn = 1.00 / resample_ratio; + if (fcn > 1.00) + fcn = 1.00; + filter_l = 31; /* must be odd */ + filter_l += intratio; /* unless resample_ratio=int, it must be even */ + + + BLACKSIZE = filter_l + 1; /* size of data needed for FIR */ + + if (gfc->fill_buffer_resample_init == 0) { + esv->inbuf_old[0] = lame_calloc(sample_t, BLACKSIZE); + esv->inbuf_old[1] = lame_calloc(sample_t, BLACKSIZE); + for (i = 0; i <= 2 * bpc; ++i) + esv->blackfilt[i] = lame_calloc(sample_t, BLACKSIZE); + + esv->itime[0] = 0; + esv->itime[1] = 0; + + /* precompute blackman filter coefficients */ + for (j = 0; j <= 2 * bpc; j++) { + FLOAT sum = 0.; + offset = (j - bpc) / (2. * bpc); + for (i = 0; i <= filter_l; i++) + sum += esv->blackfilt[j][i] = blackman(i - offset, fcn, filter_l); + for (i = 0; i <= filter_l; i++) + esv->blackfilt[j][i] /= sum; + } + gfc->fill_buffer_resample_init = 1; + } + + inbuf_old = esv->inbuf_old[ch]; + + /* time of j'th element in inbuf = itime + j/ifreq; */ + /* time of k'th element in outbuf = j/ofreq */ + for (k = 0; k < desired_len; k++) { + double time0 = k * resample_ratio; /* time of k'th output sample */ + int joff; + + j = floor(time0 - esv->itime[ch]); + + /* check if we need more input data */ + if ((filter_l + j - filter_l / 2) >= len) + break; + + /* blackman filter. by default, window centered at j+.5(filter_l%2) */ + /* but we want a window centered at time0. */ + offset = (time0 - esv->itime[ch] - (j + .5 * (filter_l % 2))); + assert(fabs(offset) <= .501); + + /* find the closest precomputed window for this offset: */ + joff = floor((offset * 2 * bpc) + bpc + .5); + + xvalue = 0.; + for (i = 0; i <= filter_l; ++i) { + int const j2 = i + j - filter_l / 2; + sample_t y; + assert(j2 < len); + assert(j2 + BLACKSIZE >= 0); + y = (j2 < 0) ? inbuf_old[BLACKSIZE + j2] : inbuf[j2]; +#ifdef PRECOMPUTE + xvalue += y * esv->blackfilt[joff][i]; +#else + xvalue += y * blackman(i - offset, fcn, filter_l); /* very slow! */ +#endif + } + outbuf[k] = xvalue; + } + + + /* k = number of samples added to outbuf */ + /* last k sample used data from [j-filter_l/2,j+filter_l-filter_l/2] */ + + /* how many samples of input data were used: */ + *num_used = Min(len, filter_l + j - filter_l / 2); + + /* adjust our input time counter. Incriment by the number of samples used, + * then normalize so that next output sample is at time 0, next + * input buffer is at time itime[ch] */ + esv->itime[ch] += *num_used - k * resample_ratio; + + /* save the last BLACKSIZE samples into the inbuf_old buffer */ + if (*num_used >= BLACKSIZE) { + for (i = 0; i < BLACKSIZE; i++) + inbuf_old[i] = inbuf[*num_used + i - BLACKSIZE]; + } + else { + /* shift in *num_used samples into inbuf_old */ + int const n_shift = BLACKSIZE - *num_used; /* number of samples to shift */ + + /* shift n_shift samples by *num_used, to make room for the + * num_used new samples */ + for (i = 0; i < n_shift; ++i) + inbuf_old[i] = inbuf_old[i + *num_used]; + + /* shift in the *num_used samples */ + for (j = 0; i < BLACKSIZE; ++i, ++j) + inbuf_old[i] = inbuf[j]; + + assert(j == *num_used); + } + return k; /* return the number samples created at the new samplerate */ +} + +int +isResamplingNecessary(SessionConfig_t const* cfg) +{ + int const l = cfg->samplerate_out * 0.9995f; + int const h = cfg->samplerate_out * 1.0005f; + return (cfg->samplerate_in < l) || (h < cfg->samplerate_in) ? 1 : 0; +} + +/* copy in new samples from in_buffer into mfbuf, with resampling + if necessary. n_in = number of samples from the input buffer that + were used. n_out = number of samples copied into mfbuf */ + +void +fill_buffer(lame_internal_flags * gfc, + sample_t * const mfbuf[2], sample_t const * const in_buffer[2], int nsamples, int *n_in, int *n_out) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + int mf_size = gfc->sv_enc.mf_size; + int framesize = 576 * cfg->mode_gr; + int nout, ch = 0; + int nch = cfg->channels_out; + + /* copy in new samples into mfbuf, with resampling if necessary */ + if (isResamplingNecessary(cfg)) { + do { + nout = + fill_buffer_resample(gfc, &mfbuf[ch][mf_size], + framesize, in_buffer[ch], nsamples, n_in, ch); + } while (++ch < nch); + *n_out = nout; + } + else { + nout = Min(framesize, nsamples); + do { + memcpy(&mfbuf[ch][mf_size], &in_buffer[ch][0], nout * sizeof(mfbuf[0][0])); + } while (++ch < nch); + *n_out = nout; + *n_in = nout; + } +} + + + + + + + +/*********************************************************************** +* +* Message Output +* +***********************************************************************/ + +void +lame_report_def(const char *format, va_list args) +{ + (void) vfprintf(stderr, format, args); + fflush(stderr); /* an debug function should flush immediately */ +} + +void +lame_report_fnc(lame_report_function print_f, const char *format, ...) +{ + if (print_f) { + va_list args; + va_start(args, format); + print_f(format, args); + va_end(args); + } +} + + +void +lame_debugf(const lame_internal_flags* gfc, const char *format, ...) +{ + if (gfc && gfc->report_dbg) { + va_list args; + va_start(args, format); + gfc->report_dbg(format, args); + va_end(args); + } +} + + +void +lame_msgf(const lame_internal_flags* gfc, const char *format, ...) +{ + if (gfc && gfc->report_msg) { + va_list args; + va_start(args, format); + gfc->report_msg(format, args); + va_end(args); + } +} + + +void +lame_errorf(const lame_internal_flags* gfc, const char *format, ...) +{ + if (gfc && gfc->report_err) { + va_list args; + va_start(args, format); + gfc->report_err(format, args); + va_end(args); + } +} + + + +/*********************************************************************** + * + * routines to detect CPU specific features like 3DNow, MMX, SSE + * + * donated by Frank Klemm + * added Robert Hegemann 2000-10-10 + * + ***********************************************************************/ + +#ifdef HAVE_NASM +extern int has_MMX_nasm(void); +extern int has_3DNow_nasm(void); +extern int has_SSE_nasm(void); +extern int has_SSE2_nasm(void); +#endif + +int +has_MMX(void) +{ +#ifdef HAVE_NASM + return has_MMX_nasm(); +#else + return 0; /* don't know, assume not */ +#endif +} + +int +has_3DNow(void) +{ +#ifdef HAVE_NASM + return has_3DNow_nasm(); +#else + return 0; /* don't know, assume not */ +#endif +} + +int +has_SSE(void) +{ +#ifdef HAVE_NASM + return has_SSE_nasm(); +#else +#if defined( _M_X64 ) || defined( MIN_ARCH_SSE ) + return 1; +#else + return 0; /* don't know, assume not */ +#endif +#endif +} + +int +has_SSE2(void) +{ +#ifdef HAVE_NASM + return has_SSE2_nasm(); +#else +#if defined( _M_X64 ) || defined( MIN_ARCH_SSE ) + return 1; +#else + return 0; /* don't know, assume not */ +#endif +#endif +} + +void +disable_FPE(void) +{ +/* extremly system dependent stuff, move to a lib to make the code readable */ +/*==========================================================================*/ + + + + /* + * Disable floating point exceptions + */ + + + + +#if defined(__FreeBSD__) && !defined(__alpha__) + { + /* seet floating point mask to the Linux default */ + fp_except_t mask; + mask = fpgetmask(); + /* if bit is set, we get SIGFPE on that error! */ + fpsetmask(mask & ~(FP_X_INV | FP_X_DZ)); + /* DEBUGF("FreeBSD mask is 0x%x\n",mask); */ + } +#endif + +#if defined(__riscos__) && !defined(ABORTFP) + /* Disable FPE's under RISC OS */ + /* if bit is set, we disable trapping that error! */ + /* _FPE_IVO : invalid operation */ + /* _FPE_DVZ : divide by zero */ + /* _FPE_OFL : overflow */ + /* _FPE_UFL : underflow */ + /* _FPE_INX : inexact */ + DisableFPETraps(_FPE_IVO | _FPE_DVZ | _FPE_OFL); +#endif + + /* + * Debugging stuff + * The default is to ignore FPE's, unless compiled with -DABORTFP + * so add code below to ENABLE FPE's. + */ + +#if defined(ABORTFP) +#if defined(_MSC_VER) + { +#if 0 + /* rh 061207 + the following fix seems to be a workaround for a problem in the + parent process calling LAME. It would be better to fix the broken + application => code disabled. + */ + + /* set affinity to a single CPU. Fix for EAC/lame on SMP systems from + "Todd Richmond" */ + SYSTEM_INFO si; + GetSystemInfo(&si); + SetProcessAffinityMask(GetCurrentProcess(), si.dwActiveProcessorMask); +#endif +#include + unsigned int mask; + mask = _controlfp(0, 0); + mask &= ~(_EM_OVERFLOW | _EM_UNDERFLOW | _EM_ZERODIVIDE | _EM_INVALID); + mask = _controlfp(mask, _MCW_EM); + } +#elif defined(__CYGWIN__) +# define _FPU_GETCW(cw) __asm__ ("fnstcw %0" : "=m" (*&cw)) +# define _FPU_SETCW(cw) __asm__ ("fldcw %0" : : "m" (*&cw)) + +# define _EM_INEXACT 0x00000020 /* inexact (precision) */ +# define _EM_UNDERFLOW 0x00000010 /* underflow */ +# define _EM_OVERFLOW 0x00000008 /* overflow */ +# define _EM_ZERODIVIDE 0x00000004 /* zero divide */ +# define _EM_INVALID 0x00000001 /* invalid */ + { + unsigned int mask; + _FPU_GETCW(mask); + /* Set the FPU control word to abort on most FPEs */ + mask &= ~(_EM_OVERFLOW | _EM_ZERODIVIDE | _EM_INVALID); + _FPU_SETCW(mask); + } +# elif defined(__linux__) + { + +# include +# ifndef _FPU_GETCW +# define _FPU_GETCW(cw) __asm__ ("fnstcw %0" : "=m" (*&cw)) +# endif +# ifndef _FPU_SETCW +# define _FPU_SETCW(cw) __asm__ ("fldcw %0" : : "m" (*&cw)) +# endif + + /* + * Set the Linux mask to abort on most FPE's + * if bit is set, we _mask_ SIGFPE on that error! + * mask &= ~( _FPU_MASK_IM | _FPU_MASK_ZM | _FPU_MASK_OM | _FPU_MASK_UM ); + */ + + unsigned int mask; + _FPU_GETCW(mask); + mask &= ~(_FPU_MASK_IM | _FPU_MASK_ZM | _FPU_MASK_OM); + _FPU_SETCW(mask); + } +#endif +#endif /* ABORTFP */ +} + + + + + +#ifdef USE_FAST_LOG +/*********************************************************************** + * + * Fast Log Approximation for log2, used to approximate every other log + * (log10 and log) + * maximum absolute error for log10 is around 10-6 + * maximum *relative* error can be high when x is almost 1 because error/log10(x) tends toward x/e + * + * use it if typical RESULT values are > 1e-5 (for example if x>1.00001 or x<0.99999) + * or if the relative precision in the domain around 1 is not important (result in 1 is exact and 0) + * + ***********************************************************************/ + + +#define LOG2_SIZE (512) +#define LOG2_SIZE_L2 (9) + +static ieee754_float32_t log_table[LOG2_SIZE + 1]; + + + +void +init_log_table(void) +{ + int j; + static int init = 0; + + /* Range for log2(x) over [1,2[ is [0,1[ */ + assert((1 << LOG2_SIZE_L2) == LOG2_SIZE); + + if (!init) { + for (j = 0; j < LOG2_SIZE + 1; j++) + log_table[j] = log(1.0f + j / (ieee754_float32_t) LOG2_SIZE) / log(2.0f); + } + init = 1; +} + + + +ieee754_float32_t +fast_log2(ieee754_float32_t x) +{ + ieee754_float32_t log2val, partial; + union { + ieee754_float32_t f; + int i; + } fi; + int mantisse; + fi.f = x; + mantisse = fi.i & 0x7fffff; + log2val = ((fi.i >> 23) & 0xFF) - 0x7f; + partial = (mantisse & ((1 << (23 - LOG2_SIZE_L2)) - 1)); + partial *= 1.0f / ((1 << (23 - LOG2_SIZE_L2))); + + + mantisse >>= (23 - LOG2_SIZE_L2); + + /* log2val += log_table[mantisse]; without interpolation the results are not good */ + log2val += log_table[mantisse] * (1.0f - partial) + log_table[mantisse + 1] * partial; + + return log2val; +} + +#else /* Don't use FAST_LOG */ + + +void +init_log_table(void) +{ +} + + +#endif + +/* end of util.c */ diff --git a/pkg/lame/clame/util.h b/pkg/lame/clame/util.h new file mode 100644 index 0000000..13f0cd4 --- /dev/null +++ b/pkg/lame/clame/util.h @@ -0,0 +1,616 @@ +/* + * lame utility library include file + * + * Copyright (c) 1999 Albert L Faber + * Copyright (c) 2008 Robert Hegemann + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef LAME_UTIL_H +#define LAME_UTIL_H + +#include "l3side.h" +#include "id3tag.h" +#include "lame_global_flags.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*********************************************************************** +* +* Global Definitions +* +***********************************************************************/ + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE (!FALSE) +#endif + +#ifdef UINT_MAX +# define MAX_U_32_NUM UINT_MAX +#else +# define MAX_U_32_NUM 0xFFFFFFFF +#endif + +#ifndef PI +# ifdef M_PI +# define PI M_PI +# else +# define PI 3.14159265358979323846 +# endif +#endif + + +#ifdef M_LN2 +# define LOG2 M_LN2 +#else +# define LOG2 0.69314718055994530942 +#endif + +#ifdef M_LN10 +# define LOG10 M_LN10 +#else +# define LOG10 2.30258509299404568402 +#endif + + +#ifdef M_SQRT2 +# define SQRT2 M_SQRT2 +#else +# define SQRT2 1.41421356237309504880 +#endif + + +#define CRC16_POLYNOMIAL 0x8005 + +#define MAX_BITS_PER_CHANNEL 4095 +#define MAX_BITS_PER_GRANULE 7680 + +/* "bit_stream.h" Definitions */ +#define BUFFER_SIZE LAME_MAXMP3BUFFER + +#define Min(A, B) ((A) < (B) ? (A) : (B)) +#define Max(A, B) ((A) > (B) ? (A) : (B)) + +/* log/log10 approximations */ +#ifdef USE_FAST_LOG +#define FAST_LOG10(x) (fast_log2(x)*(LOG2/LOG10)) +#define FAST_LOG(x) (fast_log2(x)*LOG2) +#define FAST_LOG10_X(x,y) (fast_log2(x)*(LOG2/LOG10*(y))) +#define FAST_LOG_X(x,y) (fast_log2(x)*(LOG2*(y))) +#else +#define FAST_LOG10(x) log10(x) +#define FAST_LOG(x) log(x) +#define FAST_LOG10_X(x,y) (log10(x)*(y)) +#define FAST_LOG_X(x,y) (log(x)*(y)) +#endif + + + struct replaygain_data; +#ifndef replaygain_data_defined +#define replaygain_data_defined + typedef struct replaygain_data replaygain_t; +#endif + struct plotting_data; +#ifndef plotting_data_defined +#define plotting_data_defined + typedef struct plotting_data plotting_data; +#endif + +/*********************************************************************** +* +* Global Type Definitions +* +***********************************************************************/ + + typedef struct { + void *aligned; /* pointer to ie. 128 bit aligned memory */ + void *pointer; /* to use with malloc/free */ + } aligned_pointer_t; + + void calloc_aligned(aligned_pointer_t * ptr, unsigned int size, unsigned int bytes); + void free_aligned(aligned_pointer_t * ptr); + + + /* "bit_stream.h" Type Definitions */ + + typedef struct bit_stream_struc { + unsigned char *buf; /* bit stream buffer */ + int buf_size; /* size of buffer (in number of bytes) */ + int totbit; /* bit counter of bit stream */ + int buf_byte_idx; /* pointer to top byte in buffer */ + int buf_bit_idx; /* pointer to top bit of top byte in buffer */ + + /* format of file in rd mode (BINARY/ASCII) */ + } Bit_stream_struc; + + + + typedef struct { + int sum; /* what we have seen so far */ + int seen; /* how many frames we have seen in this chunk */ + int want; /* how many frames we want to collect into one chunk */ + int pos; /* actual position in our bag */ + int size; /* size of our bag */ + int *bag; /* pointer to our bag */ + unsigned int nVbrNumFrames; + unsigned long nBytesWritten; + /* VBR tag data */ + unsigned int TotalFrameSize; + } VBR_seek_info_t; + + + /** + * ATH related stuff, if something new ATH related has to be added, + * please plugg it here into the ATH_t struct + */ + typedef struct { + int use_adjust; /* method for the auto adjustment */ + FLOAT aa_sensitivity_p; /* factor for tuning the (sample power) + point below which adaptive threshold + of hearing adjustment occurs */ + FLOAT adjust_factor; /* lowering based on peak volume, 1 = no lowering */ + FLOAT adjust_limit; /* limit for dynamic ATH adjust */ + FLOAT decay; /* determined to lower x dB each second */ + FLOAT floor; /* lowest ATH value */ + FLOAT l[SBMAX_l]; /* ATH for sfbs in long blocks */ + FLOAT s[SBMAX_s]; /* ATH for sfbs in short blocks */ + FLOAT psfb21[PSFB21]; /* ATH for partitionned sfb21 in long blocks */ + FLOAT psfb12[PSFB12]; /* ATH for partitionned sfb12 in short blocks */ + FLOAT cb_l[CBANDS]; /* ATH for long block convolution bands */ + FLOAT cb_s[CBANDS]; /* ATH for short block convolution bands */ + FLOAT eql_w[BLKSIZE / 2]; /* equal loudness weights (based on ATH) */ + } ATH_t; + + /** + * PSY Model related stuff + */ + + typedef struct { + FLOAT masking_lower[CBANDS]; + FLOAT minval[CBANDS]; + FLOAT rnumlines[CBANDS]; + FLOAT mld_cb[CBANDS]; + FLOAT mld[Max(SBMAX_l,SBMAX_s)]; + FLOAT bo_weight[Max(SBMAX_l,SBMAX_s)]; /* band weight long scalefactor bands, at transition */ + FLOAT attack_threshold; /* short block tuning */ + int s3ind[CBANDS][2]; + int numlines[CBANDS]; + int bm[Max(SBMAX_l,SBMAX_s)]; + int bo[Max(SBMAX_l,SBMAX_s)]; + int npart; + int n_sb; /* SBMAX_l or SBMAX_s */ + FLOAT *s3; + } PsyConst_CB2SB_t; + + + /** + * global data constants + */ + typedef struct { + FLOAT window[BLKSIZE], window_s[BLKSIZE_s / 2]; + PsyConst_CB2SB_t l; + PsyConst_CB2SB_t s; + PsyConst_CB2SB_t l_to_s; + FLOAT attack_threshold[4]; + FLOAT decay; + int force_short_block_calc; + } PsyConst_t; + + + typedef struct { + + FLOAT nb_l1[4][CBANDS], nb_l2[4][CBANDS]; + FLOAT nb_s1[4][CBANDS], nb_s2[4][CBANDS]; + + III_psy_xmin thm[4]; + III_psy_xmin en[4]; + + /* loudness calculation (for adaptive threshold of hearing) */ + FLOAT loudness_sq_save[2]; /* account for granule delay of L3psycho_anal */ + + FLOAT tot_ener[4]; + + FLOAT last_en_subshort[4][9]; + int last_attacks[4]; + + int blocktype_old[2]; + } PsyStateVar_t; + + + typedef struct { + /* loudness calculation (for adaptive threshold of hearing) */ + FLOAT loudness_sq[2][2]; /* loudness^2 approx. per granule and channel */ + } PsyResult_t; + + + /* variables used by encoder.c */ + typedef struct { + /* variables for newmdct.c */ + FLOAT sb_sample[2][2][18][SBLIMIT]; + FLOAT amp_filter[32]; + + /* variables used by util.c */ + /* BPC = maximum number of filter convolution windows to precompute */ +#define BPC 320 + double itime[2]; /* float precision seems to be not enough */ + sample_t *inbuf_old[2]; + sample_t *blackfilt[2 * BPC + 1]; + + FLOAT pefirbuf[19]; + + /* used for padding */ + int frac_SpF; + int slot_lag; + + /* variables for bitstream.c */ + /* mpeg1: buffer=511 bytes smallest frame: 96-38(sideinfo)=58 + * max number of frames in reservoir: 8 + * mpeg2: buffer=255 bytes. smallest frame: 24-23bytes=1 + * with VBR, if you are encoding all silence, it is possible to + * have 8kbs/24khz frames with 1byte of data each, which means we need + * to buffer up to 255 headers! */ + /* also, max_header_buf has to be a power of two */ +#define MAX_HEADER_BUF 256 +#define MAX_HEADER_LEN 40 /* max size of header is 38 */ + struct { + int write_timing; + int ptr; + char buf[MAX_HEADER_LEN]; + } header[MAX_HEADER_BUF]; + + int h_ptr; + int w_ptr; + int ancillary_flag; + + /* variables for reservoir.c */ + int ResvSize; /* in bits */ + int ResvMax; /* in bits */ + + int in_buffer_nsamples; + sample_t *in_buffer_0; + sample_t *in_buffer_1; + +#ifndef MFSIZE +# define MFSIZE ( 3*1152 + ENCDELAY - MDCTDELAY ) +#endif + sample_t mfbuf[2][MFSIZE]; + + int mf_samples_to_encode; + int mf_size; + + } EncStateVar_t; + + + typedef struct { + /* simple statistics */ + int bitrate_channelmode_hist[16][4 + 1]; + int bitrate_blocktype_hist[16][4 + 1 + 1]; /*norm/start/short/stop/mixed(short)/sum */ + + int bitrate_index; + int frame_number; /* number of frames encoded */ + int padding; /* padding for the current frame? */ + int mode_ext; + int encoder_delay; + int encoder_padding; /* number of samples of padding appended to input */ + } EncResult_t; + + + /* variables used by quantize.c */ + typedef struct { + /* variables for nspsytune */ + FLOAT longfact[SBMAX_l]; + FLOAT shortfact[SBMAX_s]; + FLOAT masking_lower; + FLOAT mask_adjust; /* the dbQ stuff */ + FLOAT mask_adjust_short; /* the dbQ stuff */ + int OldValue[2]; + int CurrentStep[2]; + int pseudohalf[SFBMAX]; + int sfb21_extra; /* will be set in lame_init_params */ + int substep_shaping; /* 0 = no substep + 1 = use substep shaping at last step(VBR only) + (not implemented yet) + 2 = use substep inside loop + 3 = use substep inside loop and last step + */ + + + char bv_scf[576]; + } QntStateVar_t; + + + typedef struct { + replaygain_t *rgdata; + /* ReplayGain */ + } RpgStateVar_t; + + + typedef struct { + FLOAT noclipScale; /* user-specified scale factor required for preventing clipping */ + sample_t PeakSample; + int RadioGain; + int noclipGainChange; /* gain change required for preventing clipping */ + } RpgResult_t; + + + typedef struct { + int version; /* 0=MPEG-2/2.5 1=MPEG-1 */ + int samplerate_index; + int sideinfo_len; + + int noise_shaping; /* 0 = none + 1 = ISO AAC model + 2 = allow scalefac_select=1 + */ + + int subblock_gain; /* 0 = no, 1 = yes */ + int use_best_huffman; /* 0 = no. 1=outside loop 2=inside loop(slow) */ + int noise_shaping_amp; /* 0 = ISO model: amplify all distorted bands + 1 = amplify within 50% of max (on db scale) + 2 = amplify only most distorted band + 3 = method 1 and refine with method 2 + */ + + int noise_shaping_stop; /* 0 = stop at over=0, all scalefacs amplified or + a scalefac has reached max value + 1 = stop when all scalefacs amplified or + a scalefac has reached max value + 2 = stop when all scalefacs amplified + */ + + + int full_outer_loop; /* 0 = stop early after 0 distortion found. 1 = full search */ + + int lowpassfreq; + int highpassfreq; + int samplerate_in; /* input_samp_rate in Hz. default=44.1 kHz */ + int samplerate_out; /* output_samp_rate. */ + int channels_in; /* number of channels in the input data stream (PCM or decoded PCM) */ + int channels_out; /* number of channels in the output data stream (not used for decoding) */ + int mode_gr; /* granules per frame */ + int force_ms; /* force M/S mode. requires mode=1 */ + + int quant_comp; + int quant_comp_short; + + int use_temporal_masking_effect; + int use_safe_joint_stereo; + + int preset; + + vbr_mode vbr; + int vbr_avg_bitrate_kbps; + int vbr_min_bitrate_index; /* min bitrate index */ + int vbr_max_bitrate_index; /* max bitrate index */ + int avg_bitrate; + int enforce_min_bitrate; /* strictly enforce VBR_min_bitrate normaly, it will be violated for analog silence */ + + int findReplayGain; /* find the RG value? default=0 */ + int findPeakSample; + int decode_on_the_fly; /* decode on the fly? default=0 */ + int analysis; + int disable_reservoir; + int buffer_constraint; /* enforce ISO spec as much as possible */ + int free_format; + int write_lame_tag; /* add Xing VBR tag? */ + + int error_protection; /* use 2 bytes per frame for a CRC checksum. default=0 */ + int copyright; /* mark as copyright. default=0 */ + int original; /* mark as original. default=1 */ + int extension; /* the MP3 'private extension' bit. Meaningless */ + int emphasis; /* Input PCM is emphased PCM (for + instance from one of the rarely + emphased CDs), it is STRONGLY not + recommended to use this, because + psycho does not take it into account, + and last but not least many decoders + don't care about these bits */ + + + MPEG_mode mode; + short_block_t short_blocks; + + float interChRatio; + float msfix; /* Naoki's adjustment of Mid/Side maskings */ + float ATH_offset_db;/* add to ATH this many db */ + float ATH_offset_factor;/* change ATH by this factor, derived from ATH_offset_db */ + float ATHcurve; /* change ATH formula 4 shape */ + int ATHtype; + int ATHonly; /* only use ATH */ + int ATHshort; /* only use ATH for short blocks */ + int noATH; /* disable ATH */ + + float ATHfixpoint; + + float adjust_alto_db; + float adjust_bass_db; + float adjust_treble_db; + float adjust_sfb21_db; + + float compression_ratio; /* sizeof(wav file)/sizeof(mp3 file) */ + + /* lowpass and highpass filter control */ + FLOAT lowpass1, lowpass2; /* normalized frequency bounds of passband */ + FLOAT highpass1, highpass2; /* normalized frequency bounds of passband */ + + /* scale input by this amount before encoding at least not used for MP3 decoding */ + FLOAT pcm_transform[2][2]; + + FLOAT minval; + } SessionConfig_t; + + + struct lame_internal_flags { + + /******************************************************************** + * internal variables NOT set by calling program, and should not be * + * modified by the calling program * + ********************************************************************/ + + /* + * Some remarks to the Class_ID field: + * The Class ID is an Identifier for a pointer to this struct. + * It is very unlikely that a pointer to lame_global_flags has the same 32 bits + * in it's structure (large and other special properties, for instance prime). + * + * To test that the structure is right and initialized, use: + * if ( gfc -> Class_ID == LAME_ID ) ... + * Other remark: + * If you set a flag to 0 for uninit data and 1 for init data, the right test + * should be "if (flag == 1)" and NOT "if (flag)". Unintended modification + * of this element will be otherwise misinterpreted as an init. + */ +# define LAME_ID 0xFFF88E3B + unsigned long class_id; + + int lame_init_params_successful; + int lame_encode_frame_init; + int iteration_init_init; + int fill_buffer_resample_init; + + SessionConfig_t cfg; + + /* variables used by lame.c */ + Bit_stream_struc bs; + III_side_info_t l3_side; + + scalefac_struct scalefac_band; + + PsyStateVar_t sv_psy; /* DATA FROM PSYMODEL.C */ + PsyResult_t ov_psy; + EncStateVar_t sv_enc; /* DATA FROM ENCODER.C */ + EncResult_t ov_enc; + QntStateVar_t sv_qnt; /* DATA FROM QUANTIZE.C */ + + RpgStateVar_t sv_rpg; + RpgResult_t ov_rpg; + + /* optional ID3 tags, used in id3tag.c */ + struct id3tag_spec tag_spec; + uint16_t nMusicCRC; + + uint16_t _unused; + + /* CPU features */ + struct { + unsigned int MMX:1; /* Pentium MMX, Pentium II...IV, K6, K6-2, + K6-III, Athlon */ + unsigned int AMD_3DNow:1; /* K6-2, K6-III, Athlon */ + unsigned int SSE:1; /* Pentium III, Pentium 4 */ + unsigned int SSE2:1; /* Pentium 4, K8 */ + unsigned int _unused:28; + } CPU_features; + + + VBR_seek_info_t VBR_seek_table; /* used for Xing VBR header */ + + ATH_t *ATH; /* all ATH related stuff */ + + PsyConst_t *cd_psy; + + /* used by the frame analyzer */ + plotting_data *pinfo; + hip_t hip; + + /* functions to replace with CPU feature optimized versions in takehiro.c */ + int (*choose_table) (const int *ix, const int *const end, int *const s); + void (*fft_fht) (FLOAT *, int); + void (*init_xrpow_core) (gr_info * const cod_info, FLOAT xrpow[576], int upper, + FLOAT * sum); + + lame_report_function report_msg; + lame_report_function report_dbg; + lame_report_function report_err; + }; + +#ifndef lame_internal_flags_defined +#define lame_internal_flags_defined + typedef struct lame_internal_flags lame_internal_flags; +#endif + + +/*********************************************************************** +* +* Global Function Prototype Declarations +* +***********************************************************************/ + void freegfc(lame_internal_flags * const gfc); + void free_id3tag(lame_internal_flags * const gfc); + extern int BitrateIndex(int, int, int); + extern int FindNearestBitrate(int, int, int); + extern int map2MP3Frequency(int freq); + extern int SmpFrqIndex(int, int *const); + extern int nearestBitrateFullIndex(uint16_t brate); + extern FLOAT ATHformula(SessionConfig_t const *cfg, FLOAT freq); + extern FLOAT freq2bark(FLOAT freq); + void disable_FPE(void); + +/* log/log10 approximations */ + extern void init_log_table(void); + extern ieee754_float32_t fast_log2(ieee754_float32_t x); + + int isResamplingNecessary(SessionConfig_t const* cfg); + + void fill_buffer(lame_internal_flags * gfc, + sample_t *const mfbuf[2], + sample_t const *const in_buffer[2], int nsamples, int *n_in, int *n_out); + +/* same as lame_decode1 (look in lame.h), but returns + unclipped raw floating-point samples. It is declared + here, not in lame.h, because it returns LAME's + internal type sample_t. No more than 1152 samples + per channel are allowed. */ + int hip_decode1_unclipped(hip_t hip, unsigned char *mp3buf, + size_t len, sample_t pcm_l[], sample_t pcm_r[]); + + + extern int has_MMX(void); + extern int has_3DNow(void); + extern int has_SSE(void); + extern int has_SSE2(void); + + + +/*********************************************************************** +* +* Macros about Message Printing and Exit +* +***********************************************************************/ + + extern void lame_report_def(const char* format, va_list args); + extern void lame_report_fnc(lame_report_function print_f, const char *, ...); + extern void lame_errorf(const lame_internal_flags * gfc, const char *, ...); + extern void lame_debugf(const lame_internal_flags * gfc, const char *, ...); + extern void lame_msgf(const lame_internal_flags * gfc, const char *, ...); +#define DEBUGF lame_debugf +#define ERRORF lame_errorf +#define MSGF lame_msgf + + int is_lame_internal_flags_valid(const lame_internal_flags * gfp); + + extern void hip_set_pinfo(hip_t hip, plotting_data* pinfo); + +#ifdef __cplusplus +} +#endif +#endif /* LAME_UTIL_H */ diff --git a/pkg/lame/clame/vbrquantize.c b/pkg/lame/clame/vbrquantize.c new file mode 100644 index 0000000..0f703b7 --- /dev/null +++ b/pkg/lame/clame/vbrquantize.c @@ -0,0 +1,1580 @@ +/* + * MP3 quantization + * + * Copyright (c) 1999-2000 Mark Taylor + * Copyright (c) 2000-2012 Robert Hegemann + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* $Id: vbrquantize.c,v 1.142 2012/02/07 13:36:35 robert Exp $ */ + +#ifdef HAVE_CONFIG_H +# include +#endif + + +#include "lame.h" +#include "machine.h" +#include "encoder.h" +#include "util.h" +#include "vbrquantize.h" +#include "quantize_pvt.h" + + + + +struct algo_s; +typedef struct algo_s algo_t; + +typedef void (*alloc_sf_f) (const algo_t *, const int *, const int *, int); +typedef uint8_t (*find_sf_f) (const FLOAT *, const FLOAT *, FLOAT, unsigned int, uint8_t); + +struct algo_s { + alloc_sf_f alloc; + find_sf_f find; + const FLOAT *xr34orig; + lame_internal_flags *gfc; + gr_info *cod_info; + int mingain_l; + int mingain_s[3]; +}; + + + +/* Remarks on optimizing compilers: + * + * the MSVC compiler may get into aliasing problems when accessing + * memory through the fi_union. declaring it volatile does the trick here + * + * the calc_sfb_noise_* functions are not inlined because the intel compiler + * optimized executeables won't work as expected anymore + */ + +#ifdef _MSC_VER +# if _MSC_VER < 1400 +# define VOLATILE volatile +# else +# define VOLATILE +# endif +#else +# define VOLATILE +#endif + +typedef VOLATILE union { + float f; + int i; +} fi_union; + + + +#ifdef TAKEHIRO_IEEE754_HACK +#define DOUBLEX double +#else +#define DOUBLEX FLOAT +#endif + +#define MAGIC_FLOAT_def (65536*(128)) +#define MAGIC_INT_def 0x4b000000 + +#ifdef TAKEHIRO_IEEE754_HACK +#else +/********************************************************************* + * XRPOW_FTOI is a macro to convert floats to ints. + * if XRPOW_FTOI(x) = nearest_int(x), then QUANTFAC(x)=adj43asm[x] + * ROUNDFAC= -0.0946 + * + * if XRPOW_FTOI(x) = floor(x), then QUANTFAC(x)=asj43[x] + * ROUNDFAC=0.4054 + *********************************************************************/ +# define QUANTFAC(rx) adj43[rx] +# define ROUNDFAC_def 0.4054f +# define XRPOW_FTOI(src,dest) ((dest) = (int)(src)) +#endif + +static int const MAGIC_INT = MAGIC_INT_def; +#ifndef TAKEHIRO_IEEE754_HACK +static DOUBLEX const ROUNDFAC = ROUNDFAC_def; +#endif +static DOUBLEX const MAGIC_FLOAT = MAGIC_FLOAT_def; + + +inline static float +vec_max_c(const float * xr34, unsigned int bw) +{ + float xfsf = 0; + unsigned int i = bw >> 2u; + unsigned int const remaining = (bw & 0x03u); + + while (i-- > 0) { + if (xfsf < xr34[0]) { + xfsf = xr34[0]; + } + if (xfsf < xr34[1]) { + xfsf = xr34[1]; + } + if (xfsf < xr34[2]) { + xfsf = xr34[2]; + } + if (xfsf < xr34[3]) { + xfsf = xr34[3]; + } + xr34 += 4; + } + switch( remaining ) { + case 3: if (xfsf < xr34[2]) xfsf = xr34[2]; + case 2: if (xfsf < xr34[1]) xfsf = xr34[1]; + case 1: if (xfsf < xr34[0]) xfsf = xr34[0]; + default: break; + } + return xfsf; +} + + +inline static uint8_t +find_lowest_scalefac(const FLOAT xr34) +{ + uint8_t sf_ok = 255; + uint8_t sf = 128, delsf = 64; + uint8_t i; + FLOAT const ixmax_val = IXMAX_VAL; + for (i = 0; i < 8; ++i) { + FLOAT const xfsf = ipow20[sf] * xr34; + if (xfsf <= ixmax_val) { + sf_ok = sf; + sf -= delsf; + } + else { + sf += delsf; + } + delsf >>= 1; + } + return sf_ok; +} + + +inline static void +k_34_4(DOUBLEX x[4], int l3[4]) +{ +#ifdef TAKEHIRO_IEEE754_HACK + fi_union fi[4]; + + assert(x[0] <= IXMAX_VAL && x[1] <= IXMAX_VAL && x[2] <= IXMAX_VAL && x[3] <= IXMAX_VAL); + x[0] += MAGIC_FLOAT; + fi[0].f = x[0]; + x[1] += MAGIC_FLOAT; + fi[1].f = x[1]; + x[2] += MAGIC_FLOAT; + fi[2].f = x[2]; + x[3] += MAGIC_FLOAT; + fi[3].f = x[3]; + fi[0].f = x[0] + adj43asm[fi[0].i - MAGIC_INT]; + fi[1].f = x[1] + adj43asm[fi[1].i - MAGIC_INT]; + fi[2].f = x[2] + adj43asm[fi[2].i - MAGIC_INT]; + fi[3].f = x[3] + adj43asm[fi[3].i - MAGIC_INT]; + l3[0] = fi[0].i - MAGIC_INT; + l3[1] = fi[1].i - MAGIC_INT; + l3[2] = fi[2].i - MAGIC_INT; + l3[3] = fi[3].i - MAGIC_INT; +#else + assert(x[0] <= IXMAX_VAL && x[1] <= IXMAX_VAL && x[2] <= IXMAX_VAL && x[3] <= IXMAX_VAL); + XRPOW_FTOI(x[0], l3[0]); + XRPOW_FTOI(x[1], l3[1]); + XRPOW_FTOI(x[2], l3[2]); + XRPOW_FTOI(x[3], l3[3]); + x[0] += QUANTFAC(l3[0]); + x[1] += QUANTFAC(l3[1]); + x[2] += QUANTFAC(l3[2]); + x[3] += QUANTFAC(l3[3]); + XRPOW_FTOI(x[0], l3[0]); + XRPOW_FTOI(x[1], l3[1]); + XRPOW_FTOI(x[2], l3[2]); + XRPOW_FTOI(x[3], l3[3]); +#endif +} + + + + + +/* do call the calc_sfb_noise_* functions only with sf values + * for which holds: sfpow34*xr34 <= IXMAX_VAL + */ + +static FLOAT +calc_sfb_noise_x34(const FLOAT * xr, const FLOAT * xr34, unsigned int bw, uint8_t sf) +{ + DOUBLEX x[4]; + int l3[4]; + const FLOAT sfpow = pow20[sf + Q_MAX2]; /*pow(2.0,sf/4.0); */ + const FLOAT sfpow34 = ipow20[sf]; /*pow(sfpow,-3.0/4.0); */ + + FLOAT xfsf = 0; + unsigned int i = bw >> 2u; + unsigned int const remaining = (bw & 0x03u); + + while (i-- > 0) { + x[0] = sfpow34 * xr34[0]; + x[1] = sfpow34 * xr34[1]; + x[2] = sfpow34 * xr34[2]; + x[3] = sfpow34 * xr34[3]; + + k_34_4(x, l3); + + x[0] = fabsf(xr[0]) - sfpow * pow43[l3[0]]; + x[1] = fabsf(xr[1]) - sfpow * pow43[l3[1]]; + x[2] = fabsf(xr[2]) - sfpow * pow43[l3[2]]; + x[3] = fabsf(xr[3]) - sfpow * pow43[l3[3]]; + xfsf += (x[0] * x[0] + x[1] * x[1]) + (x[2] * x[2] + x[3] * x[3]); + + xr += 4; + xr34 += 4; + } + if (remaining) { + x[0] = x[1] = x[2] = x[3] = 0; + switch( remaining ) { + case 3: x[2] = sfpow34 * xr34[2]; + case 2: x[1] = sfpow34 * xr34[1]; + case 1: x[0] = sfpow34 * xr34[0]; + } + + k_34_4(x, l3); + x[0] = x[1] = x[2] = x[3] = 0; + + switch( remaining ) { + case 3: x[2] = fabsf(xr[2]) - sfpow * pow43[l3[2]]; + case 2: x[1] = fabsf(xr[1]) - sfpow * pow43[l3[1]]; + case 1: x[0] = fabsf(xr[0]) - sfpow * pow43[l3[0]]; + } + xfsf += (x[0] * x[0] + x[1] * x[1]) + (x[2] * x[2] + x[3] * x[3]); + } + return xfsf; +} + + + +struct calc_noise_cache { + int valid; + FLOAT value; +}; + +typedef struct calc_noise_cache calc_noise_cache_t; + + +static uint8_t +tri_calc_sfb_noise_x34(const FLOAT * xr, const FLOAT * xr34, FLOAT l3_xmin, unsigned int bw, + uint8_t sf, calc_noise_cache_t * did_it) +{ + if (did_it[sf].valid == 0) { + did_it[sf].valid = 1; + did_it[sf].value = calc_sfb_noise_x34(xr, xr34, bw, sf); + } + if (l3_xmin < did_it[sf].value) { + return 1; + } + if (sf < 255) { + uint8_t const sf_x = sf + 1; + if (did_it[sf_x].valid == 0) { + did_it[sf_x].valid = 1; + did_it[sf_x].value = calc_sfb_noise_x34(xr, xr34, bw, sf_x); + } + if (l3_xmin < did_it[sf_x].value) { + return 1; + } + } + if (sf > 0) { + uint8_t const sf_x = sf - 1; + if (did_it[sf_x].valid == 0) { + did_it[sf_x].valid = 1; + did_it[sf_x].value = calc_sfb_noise_x34(xr, xr34, bw, sf_x); + } + if (l3_xmin < did_it[sf_x].value) { + return 1; + } + } + return 0; +} + + +/** + * Robert Hegemann 2001-05-01 + * calculates quantization step size determined by allowed masking + */ +static int +calc_scalefac(FLOAT l3_xmin, int bw) +{ + FLOAT const c = 5.799142446; /* 10 * 10^(2/3) * log10(4/3) */ + return 210 + (int) (c * log10f(l3_xmin / bw) - .5f); +} + +static uint8_t +guess_scalefac_x34(const FLOAT * xr, const FLOAT * xr34, FLOAT l3_xmin, unsigned int bw, uint8_t sf_min) +{ + int const guess = calc_scalefac(l3_xmin, bw); + if (guess < sf_min) return sf_min; + if (guess >= 255) return 255; + (void) xr; + (void) xr34; + return guess; +} + + +/* the find_scalefac* routines calculate + * a quantization step size which would + * introduce as much noise as is allowed. + * The larger the step size the more + * quantization noise we'll get. The + * scalefactors are there to lower the + * global step size, allowing limited + * differences in quantization step sizes + * per band (shaping the noise). + */ + +static uint8_t +find_scalefac_x34(const FLOAT * xr, const FLOAT * xr34, FLOAT l3_xmin, unsigned int bw, + uint8_t sf_min) +{ + calc_noise_cache_t did_it[256]; + uint8_t sf = 128, sf_ok = 255, delsf = 128, seen_good_one = 0, i; + memset(did_it, 0, sizeof(did_it)); + for (i = 0; i < 8; ++i) { + delsf >>= 1; + if (sf <= sf_min) { + sf += delsf; + } + else { + uint8_t const bad = tri_calc_sfb_noise_x34(xr, xr34, l3_xmin, bw, sf, did_it); + if (bad) { /* distortion. try a smaller scalefactor */ + sf -= delsf; + } + else { + sf_ok = sf; + sf += delsf; + seen_good_one = 1; + } + } + } + /* returning a scalefac without distortion, if possible + */ + if (seen_good_one > 0) { + sf = sf_ok; + } + if (sf <= sf_min) { + sf = sf_min; + } + return sf; +} + + + +/*********************************************************************** + * + * calc_short_block_vbr_sf() + * calc_long_block_vbr_sf() + * + * Mark Taylor 2000-??-?? + * Robert Hegemann 2000-10-25 made functions of it + * + ***********************************************************************/ + +/* a variation for vbr-mtrh */ +static int +block_sf(algo_t * that, const FLOAT l3_xmin[SFBMAX], int vbrsf[SFBMAX], int vbrsfmin[SFBMAX]) +{ + FLOAT max_xr34; + const FLOAT *const xr = &that->cod_info->xr[0]; + const FLOAT *const xr34_orig = &that->xr34orig[0]; + const int *const width = &that->cod_info->width[0]; + const char *const energy_above_cutoff = &that->cod_info->energy_above_cutoff[0]; + unsigned int const max_nonzero_coeff = (unsigned int) that->cod_info->max_nonzero_coeff; + uint8_t maxsf = 0; + int sfb = 0, m_o = -1; + unsigned int j = 0, i = 0; + int const psymax = that->cod_info->psymax; + + assert(that->cod_info->max_nonzero_coeff >= 0); + + that->mingain_l = 0; + that->mingain_s[0] = 0; + that->mingain_s[1] = 0; + that->mingain_s[2] = 0; + while (j <= max_nonzero_coeff) { + unsigned int const w = (unsigned int) width[sfb]; + unsigned int const m = (unsigned int) (max_nonzero_coeff - j + 1); + unsigned int l = w; + uint8_t m1, m2; + if (l > m) { + l = m; + } + max_xr34 = vec_max_c(&xr34_orig[j], l); + + m1 = find_lowest_scalefac(max_xr34); + vbrsfmin[sfb] = m1; + if (that->mingain_l < m1) { + that->mingain_l = m1; + } + if (that->mingain_s[i] < m1) { + that->mingain_s[i] = m1; + } + if (++i > 2) { + i = 0; + } + if (sfb < psymax && w > 2) { /* mpeg2.5 at 8 kHz doesn't use all scalefactors, unused have width 2 */ + if (energy_above_cutoff[sfb]) { + m2 = that->find(&xr[j], &xr34_orig[j], l3_xmin[sfb], l, m1); +#if 0 + if (0) { + /** Robert Hegemann 2007-09-29: + * It seems here is some more potential for speed improvements. + * Current find method does 11-18 quantization calculations. + * Using a "good guess" may help to reduce this amount. + */ + uint8_t guess = calc_scalefac(l3_xmin[sfb], l); + DEBUGF(that->gfc, "sfb=%3d guess=%3d found=%3d diff=%3d\n", sfb, guess, m2, + m2 - guess); + } +#endif + if (maxsf < m2) { + maxsf = m2; + } + if (m_o < m2 && m2 < 255) { + m_o = m2; + } + } + else { + m2 = 255; + maxsf = 255; + } + } + else { + if (maxsf < m1) { + maxsf = m1; + } + m2 = maxsf; + } + vbrsf[sfb] = m2; + ++sfb; + j += w; + } + for (; sfb < SFBMAX; ++sfb) { + vbrsf[sfb] = maxsf; + vbrsfmin[sfb] = 0; + } + if (m_o > -1) { + maxsf = m_o; + for (sfb = 0; sfb < SFBMAX; ++sfb) { + if (vbrsf[sfb] == 255) { + vbrsf[sfb] = m_o; + } + } + } + return maxsf; +} + + + +/*********************************************************************** + * + * quantize xr34 based on scalefactors + * + * block_xr34 + * + * Mark Taylor 2000-??-?? + * Robert Hegemann 2000-10-20 made functions of them + * + ***********************************************************************/ + +static void +quantize_x34(const algo_t * that) +{ + DOUBLEX x[4]; + const FLOAT *xr34_orig = that->xr34orig; + gr_info *const cod_info = that->cod_info; + int const ifqstep = (cod_info->scalefac_scale == 0) ? 2 : 4; + int *l3 = cod_info->l3_enc; + unsigned int j = 0, sfb = 0; + unsigned int const max_nonzero_coeff = (unsigned int) cod_info->max_nonzero_coeff; + + assert(cod_info->max_nonzero_coeff >= 0); + assert(cod_info->max_nonzero_coeff < 576); + + while (j <= max_nonzero_coeff) { + int const s = + (cod_info->scalefac[sfb] + (cod_info->preflag ? pretab[sfb] : 0)) * ifqstep + + cod_info->subblock_gain[cod_info->window[sfb]] * 8; + uint8_t const sfac = (uint8_t) (cod_info->global_gain - s); + FLOAT const sfpow34 = ipow20[sfac]; + unsigned int const w = (unsigned int) cod_info->width[sfb]; + unsigned int const m = (unsigned int) (max_nonzero_coeff - j + 1); + unsigned int i, remaining; + + assert((cod_info->global_gain - s) >= 0); + assert(cod_info->width[sfb] >= 0); + j += w; + ++sfb; + + i = (w <= m) ? w : m; + remaining = (i & 0x03u); + i >>= 2u; + + while (i-- > 0) { + x[0] = sfpow34 * xr34_orig[0]; + x[1] = sfpow34 * xr34_orig[1]; + x[2] = sfpow34 * xr34_orig[2]; + x[3] = sfpow34 * xr34_orig[3]; + + k_34_4(x, l3); + + l3 += 4; + xr34_orig += 4; + } + if (remaining) { + int tmp_l3[4]; + x[0] = x[1] = x[2] = x[3] = 0; + switch( remaining ) { + case 3: x[2] = sfpow34 * xr34_orig[2]; + case 2: x[1] = sfpow34 * xr34_orig[1]; + case 1: x[0] = sfpow34 * xr34_orig[0]; + } + + k_34_4(x, tmp_l3); + + switch( remaining ) { + case 3: l3[2] = tmp_l3[2]; + case 2: l3[1] = tmp_l3[1]; + case 1: l3[0] = tmp_l3[0]; + } + + l3 += remaining; + xr34_orig += remaining; + } + } +} + + + +static const uint8_t max_range_short[SBMAX_s * 3] = { + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 0, 0, 0 +}; + +static const uint8_t max_range_long[SBMAX_l] = { + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0 +}; + +static const uint8_t max_range_long_lsf_pretab[SBMAX_l] = { + 7, 7, 7, 7, 7, 7, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + + + +/* + sfb=0..5 scalefac < 16 + sfb>5 scalefac < 8 + + ifqstep = ( cod_info->scalefac_scale == 0 ) ? 2 : 4; + ol_sf = (cod_info->global_gain-210.0); + ol_sf -= 8*cod_info->subblock_gain[i]; + ol_sf -= ifqstep*scalefac[gr][ch].s[sfb][i]; +*/ + +static void +set_subblock_gain(gr_info * cod_info, const int mingain_s[3], int sf[]) +{ + const int maxrange1 = 15, maxrange2 = 7; + const int ifqstepShift = (cod_info->scalefac_scale == 0) ? 1 : 2; + int *const sbg = cod_info->subblock_gain; + unsigned int const psymax = (unsigned int) cod_info->psymax; + unsigned int psydiv = 18; + int sbg0, sbg1, sbg2; + unsigned int sfb, i; + int min_sbg = 7; + + if (psydiv > psymax) { + psydiv = psymax; + } + for (i = 0; i < 3; ++i) { + int maxsf1 = 0, maxsf2 = 0, minsf = 1000; + /* see if we should use subblock gain */ + for (sfb = i; sfb < psydiv; sfb += 3) { /* part 1 */ + int const v = -sf[sfb]; + if (maxsf1 < v) { + maxsf1 = v; + } + if (minsf > v) { + minsf = v; + } + } + for (; sfb < SFBMAX; sfb += 3) { /* part 2 */ + int const v = -sf[sfb]; + if (maxsf2 < v) { + maxsf2 = v; + } + if (minsf > v) { + minsf = v; + } + } + + /* boost subblock gain as little as possible so we can + * reach maxsf1 with scalefactors + * 8*sbg >= maxsf1 + */ + { + int const m1 = maxsf1 - (maxrange1 << ifqstepShift); + int const m2 = maxsf2 - (maxrange2 << ifqstepShift); + + maxsf1 = Max(m1, m2); + } + if (minsf > 0) { + sbg[i] = minsf >> 3; + } + else { + sbg[i] = 0; + } + if (maxsf1 > 0) { + int const m1 = sbg[i]; + int const m2 = (maxsf1 + 7) >> 3; + sbg[i] = Max(m1, m2); + } + if (sbg[i] > 0 && mingain_s[i] > (cod_info->global_gain - sbg[i] * 8)) { + sbg[i] = (cod_info->global_gain - mingain_s[i]) >> 3; + } + if (sbg[i] > 7) { + sbg[i] = 7; + } + if (min_sbg > sbg[i]) { + min_sbg = sbg[i]; + } + } + sbg0 = sbg[0] * 8; + sbg1 = sbg[1] * 8; + sbg2 = sbg[2] * 8; + for (sfb = 0; sfb < SFBMAX; sfb += 3) { + sf[sfb + 0] += sbg0; + sf[sfb + 1] += sbg1; + sf[sfb + 2] += sbg2; + } + if (min_sbg > 0) { + for (i = 0; i < 3; ++i) { + sbg[i] -= min_sbg; + } + cod_info->global_gain -= min_sbg * 8; + } +} + + + +/* + ifqstep = ( cod_info->scalefac_scale == 0 ) ? 2 : 4; + ol_sf = (cod_info->global_gain-210.0); + ol_sf -= ifqstep*scalefac[gr][ch].l[sfb]; + if (cod_info->preflag && sfb>=11) + ol_sf -= ifqstep*pretab[sfb]; +*/ +static void +set_scalefacs(gr_info * cod_info, const int *vbrsfmin, int sf[], const uint8_t * max_range) +{ + const int ifqstep = (cod_info->scalefac_scale == 0) ? 2 : 4; + const int ifqstepShift = (cod_info->scalefac_scale == 0) ? 1 : 2; + int *const scalefac = cod_info->scalefac; + int const sfbmax = cod_info->sfbmax; + int sfb; + int const *const sbg = cod_info->subblock_gain; + int const *const window = cod_info->window; + int const preflag = cod_info->preflag; + + if (preflag) { + for (sfb = 11; sfb < sfbmax; ++sfb) { + sf[sfb] += pretab[sfb] * ifqstep; + } + } + for (sfb = 0; sfb < sfbmax; ++sfb) { + int const gain = cod_info->global_gain - (sbg[window[sfb]] * 8) + - ((preflag ? pretab[sfb] : 0) * ifqstep); + + if (sf[sfb] < 0) { + int const m = gain - vbrsfmin[sfb]; + /* ifqstep*scalefac >= -sf[sfb], so round UP */ + scalefac[sfb] = (ifqstep - 1 - sf[sfb]) >> ifqstepShift; + + if (scalefac[sfb] > max_range[sfb]) { + scalefac[sfb] = max_range[sfb]; + } + if (scalefac[sfb] > 0 && (scalefac[sfb] << ifqstepShift) > m) { + scalefac[sfb] = m >> ifqstepShift; + } + } + else { + scalefac[sfb] = 0; + } + } + for (; sfb < SFBMAX; ++sfb) { + scalefac[sfb] = 0; /* sfb21 */ + } +} + + +#ifndef NDEBUG +static int +checkScalefactor(const gr_info * cod_info, const int vbrsfmin[SFBMAX]) +{ + int const ifqstep = cod_info->scalefac_scale == 0 ? 2 : 4; + int sfb; + for (sfb = 0; sfb < cod_info->psymax; ++sfb) { + const int s = + ((cod_info->scalefac[sfb] + + (cod_info->preflag ? pretab[sfb] : 0)) * ifqstep) + + cod_info->subblock_gain[cod_info->window[sfb]] * 8; + + if ((cod_info->global_gain - s) < vbrsfmin[sfb]) { + /* + fprintf( stdout, "sf %d\n", sfb ); + fprintf( stdout, "min %d\n", vbrsfmin[sfb] ); + fprintf( stdout, "ggain %d\n", cod_info->global_gain ); + fprintf( stdout, "scalefac %d\n", cod_info->scalefac[sfb] ); + fprintf( stdout, "pretab %d\n", (cod_info->preflag ? pretab[sfb] : 0) ); + fprintf( stdout, "scale %d\n", (cod_info->scalefac_scale + 1) ); + fprintf( stdout, "subgain %d\n", cod_info->subblock_gain[cod_info->window[sfb]] * 8 ); + fflush( stdout ); + exit(-1); + */ + return 0; + } + } + return 1; +} +#endif + + +/****************************************************************** + * + * short block scalefacs + * + ******************************************************************/ + +static void +short_block_constrain(const algo_t * that, const int vbrsf[SFBMAX], + const int vbrsfmin[SFBMAX], int vbrmax) +{ + gr_info *const cod_info = that->cod_info; + lame_internal_flags const *const gfc = that->gfc; + SessionConfig_t const *const cfg = &gfc->cfg; + int const maxminsfb = that->mingain_l; + int mover, maxover0 = 0, maxover1 = 0, delta = 0; + int v, v0, v1; + int sfb; + int const psymax = cod_info->psymax; + + for (sfb = 0; sfb < psymax; ++sfb) { + assert(vbrsf[sfb] >= vbrsfmin[sfb]); + v = vbrmax - vbrsf[sfb]; + if (delta < v) { + delta = v; + } + v0 = v - (4 * 14 + 2 * max_range_short[sfb]); + v1 = v - (4 * 14 + 4 * max_range_short[sfb]); + if (maxover0 < v0) { + maxover0 = v0; + } + if (maxover1 < v1) { + maxover1 = v1; + } + } + if (cfg->noise_shaping == 2) { + /* allow scalefac_scale=1 */ + mover = Min(maxover0, maxover1); + } + else { + mover = maxover0; + } + if (delta > mover) { + delta = mover; + } + vbrmax -= delta; + maxover0 -= mover; + maxover1 -= mover; + + if (maxover0 == 0) { + cod_info->scalefac_scale = 0; + } + else if (maxover1 == 0) { + cod_info->scalefac_scale = 1; + } + if (vbrmax < maxminsfb) { + vbrmax = maxminsfb; + } + cod_info->global_gain = vbrmax; + + if (cod_info->global_gain < 0) { + cod_info->global_gain = 0; + } + else if (cod_info->global_gain > 255) { + cod_info->global_gain = 255; + } + { + int sf_temp[SFBMAX]; + for (sfb = 0; sfb < SFBMAX; ++sfb) { + sf_temp[sfb] = vbrsf[sfb] - vbrmax; + } + set_subblock_gain(cod_info, &that->mingain_s[0], sf_temp); + set_scalefacs(cod_info, vbrsfmin, sf_temp, max_range_short); + } + assert(checkScalefactor(cod_info, vbrsfmin)); +} + + + +/****************************************************************** + * + * long block scalefacs + * + ******************************************************************/ + +static void +long_block_constrain(const algo_t * that, const int vbrsf[SFBMAX], const int vbrsfmin[SFBMAX], + int vbrmax) +{ + gr_info *const cod_info = that->cod_info; + lame_internal_flags const *const gfc = that->gfc; + SessionConfig_t const *const cfg = &gfc->cfg; + uint8_t const *max_rangep; + int const maxminsfb = that->mingain_l; + int sfb; + int maxover0, maxover1, maxover0p, maxover1p, mover, delta = 0; + int v, v0, v1, v0p, v1p, vm0p = 1, vm1p = 1; + int const psymax = cod_info->psymax; + + max_rangep = cfg->mode_gr == 2 ? max_range_long : max_range_long_lsf_pretab; + + maxover0 = 0; + maxover1 = 0; + maxover0p = 0; /* pretab */ + maxover1p = 0; /* pretab */ + + for (sfb = 0; sfb < psymax; ++sfb) { + assert(vbrsf[sfb] >= vbrsfmin[sfb]); + v = vbrmax - vbrsf[sfb]; + if (delta < v) { + delta = v; + } + v0 = v - 2 * max_range_long[sfb]; + v1 = v - 4 * max_range_long[sfb]; + v0p = v - 2 * (max_rangep[sfb] + pretab[sfb]); + v1p = v - 4 * (max_rangep[sfb] + pretab[sfb]); + if (maxover0 < v0) { + maxover0 = v0; + } + if (maxover1 < v1) { + maxover1 = v1; + } + if (maxover0p < v0p) { + maxover0p = v0p; + } + if (maxover1p < v1p) { + maxover1p = v1p; + } + } + if (vm0p == 1) { + int gain = vbrmax - maxover0p; + if (gain < maxminsfb) { + gain = maxminsfb; + } + for (sfb = 0; sfb < psymax; ++sfb) { + int const a = (gain - vbrsfmin[sfb]) - 2 * pretab[sfb]; + if (a <= 0) { + vm0p = 0; + vm1p = 0; + break; + } + } + } + if (vm1p == 1) { + int gain = vbrmax - maxover1p; + if (gain < maxminsfb) { + gain = maxminsfb; + } + for (sfb = 0; sfb < psymax; ++sfb) { + int const b = (gain - vbrsfmin[sfb]) - 4 * pretab[sfb]; + if (b <= 0) { + vm1p = 0; + break; + } + } + } + if (vm0p == 0) { + maxover0p = maxover0; + } + if (vm1p == 0) { + maxover1p = maxover1; + } + if (cfg->noise_shaping != 2) { + maxover1 = maxover0; + maxover1p = maxover0p; + } + mover = Min(maxover0, maxover0p); + mover = Min(mover, maxover1); + mover = Min(mover, maxover1p); + + if (delta > mover) { + delta = mover; + } + vbrmax -= delta; + if (vbrmax < maxminsfb) { + vbrmax = maxminsfb; + } + maxover0 -= mover; + maxover0p -= mover; + maxover1 -= mover; + maxover1p -= mover; + + if (maxover0 == 0) { + cod_info->scalefac_scale = 0; + cod_info->preflag = 0; + max_rangep = max_range_long; + } + else if (maxover0p == 0) { + cod_info->scalefac_scale = 0; + cod_info->preflag = 1; + } + else if (maxover1 == 0) { + cod_info->scalefac_scale = 1; + cod_info->preflag = 0; + max_rangep = max_range_long; + } + else if (maxover1p == 0) { + cod_info->scalefac_scale = 1; + cod_info->preflag = 1; + } + else { + assert(0); /* this should not happen */ + } + cod_info->global_gain = vbrmax; + if (cod_info->global_gain < 0) { + cod_info->global_gain = 0; + } + else if (cod_info->global_gain > 255) { + cod_info->global_gain = 255; + } + { + int sf_temp[SFBMAX]; + for (sfb = 0; sfb < SFBMAX; ++sfb) { + sf_temp[sfb] = vbrsf[sfb] - vbrmax; + } + set_scalefacs(cod_info, vbrsfmin, sf_temp, max_rangep); + } + assert(checkScalefactor(cod_info, vbrsfmin)); +} + + + +static void +bitcount(const algo_t * that) +{ + int rc = scale_bitcount(that->gfc, that->cod_info); + + if (rc == 0) { + return; + } + /* this should not happen due to the way the scalefactors are selected */ + ERRORF(that->gfc, "INTERNAL ERROR IN VBR NEW CODE (986), please send bug report\n"); + exit(-1); +} + + + +static int +quantizeAndCountBits(const algo_t * that) +{ + quantize_x34(that); + that->cod_info->part2_3_length = noquant_count_bits(that->gfc, that->cod_info, 0); + return that->cod_info->part2_3_length; +} + + + + + +static int +tryGlobalStepsize(const algo_t * that, const int sfwork[SFBMAX], + const int vbrsfmin[SFBMAX], int delta) +{ + FLOAT const xrpow_max = that->cod_info->xrpow_max; + int sftemp[SFBMAX], i, nbits; + int gain, vbrmax = 0; + for (i = 0; i < SFBMAX; ++i) { + gain = sfwork[i] + delta; + if (gain < vbrsfmin[i]) { + gain = vbrsfmin[i]; + } + if (gain > 255) { + gain = 255; + } + if (vbrmax < gain) { + vbrmax = gain; + } + sftemp[i] = gain; + } + that->alloc(that, sftemp, vbrsfmin, vbrmax); + bitcount(that); + nbits = quantizeAndCountBits(that); + that->cod_info->xrpow_max = xrpow_max; + return nbits; +} + + + +static void +searchGlobalStepsizeMax(const algo_t * that, const int sfwork[SFBMAX], + const int vbrsfmin[SFBMAX], int target) +{ + gr_info const *const cod_info = that->cod_info; + const int gain = cod_info->global_gain; + int curr = gain; + int gain_ok = 1024; + int nbits = LARGE_BITS; + int l = gain, r = 512; + + assert(gain >= 0); + while (l <= r) { + curr = (l + r) >> 1; + nbits = tryGlobalStepsize(that, sfwork, vbrsfmin, curr - gain); + if (nbits == 0 || (nbits + cod_info->part2_length) < target) { + r = curr - 1; + gain_ok = curr; + } + else { + l = curr + 1; + if (gain_ok == 1024) { + gain_ok = curr; + } + } + } + if (gain_ok != curr) { + curr = gain_ok; + nbits = tryGlobalStepsize(that, sfwork, vbrsfmin, curr - gain); + } +} + + + +static int +sfDepth(const int sfwork[SFBMAX]) +{ + int m = 0; + unsigned int i, j; + for (j = SFBMAX, i = 0; j > 0; --j, ++i) { + int const di = 255 - sfwork[i]; + if (m < di) { + m = di; + } + assert(sfwork[i] >= 0); + assert(sfwork[i] <= 255); + } + assert(m >= 0); + assert(m <= 255); + return m; +} + + +static void +cutDistribution(const int sfwork[SFBMAX], int sf_out[SFBMAX], int cut) +{ + unsigned int i, j; + for (j = SFBMAX, i = 0; j > 0; --j, ++i) { + int const x = sfwork[i]; + sf_out[i] = x < cut ? x : cut; + } +} + + +static int +flattenDistribution(const int sfwork[SFBMAX], int sf_out[SFBMAX], int dm, int k, int p) +{ + unsigned int i, j; + int x, sfmax = 0; + if (dm > 0) { + for (j = SFBMAX, i = 0; j > 0; --j, ++i) { + int const di = p - sfwork[i]; + x = sfwork[i] + (k * di) / dm; + if (x < 0) { + x = 0; + } + else { + if (x > 255) { + x = 255; + } + } + sf_out[i] = x; + if (sfmax < x) { + sfmax = x; + } + } + } + else { + for (j = SFBMAX, i = 0; j > 0u; --j, ++i) { + x = sfwork[i]; + sf_out[i] = x; + if (sfmax < x) { + sfmax = x; + } + } + } + return sfmax; +} + + +static int +tryThatOne(algo_t const* that, const int sftemp[SFBMAX], const int vbrsfmin[SFBMAX], int vbrmax) +{ + FLOAT const xrpow_max = that->cod_info->xrpow_max; + int nbits = LARGE_BITS; + that->alloc(that, sftemp, vbrsfmin, vbrmax); + bitcount(that); + nbits = quantizeAndCountBits(that); + nbits += that->cod_info->part2_length; + that->cod_info->xrpow_max = xrpow_max; + return nbits; +} + + +static void +outOfBitsStrategy(algo_t const* that, const int sfwork[SFBMAX], const int vbrsfmin[SFBMAX], int target) +{ + int wrk[SFBMAX]; + int const dm = sfDepth(sfwork); + int const p = that->cod_info->global_gain; + int nbits; + + /* PART 1 */ + { + int bi = dm / 2; + int bi_ok = -1; + int bu = 0; + int bo = dm; + for (;;) { + int const sfmax = flattenDistribution(sfwork, wrk, dm, bi, p); + nbits = tryThatOne(that, wrk, vbrsfmin, sfmax); + if (nbits <= target) { + bi_ok = bi; + bo = bi - 1; + } + else { + bu = bi + 1; + } + if (bu <= bo) { + bi = (bu + bo) / 2; + } + else { + break; + } + } + if (bi_ok >= 0) { + if (bi != bi_ok) { + int const sfmax = flattenDistribution(sfwork, wrk, dm, bi_ok, p); + nbits = tryThatOne(that, wrk, vbrsfmin, sfmax); + } + return; + } + } + + /* PART 2: */ + { + int bi = (255 + p) / 2; + int bi_ok = -1; + int bu = p; + int bo = 255; + for (;;) { + int const sfmax = flattenDistribution(sfwork, wrk, dm, dm, bi); + nbits = tryThatOne(that, wrk, vbrsfmin, sfmax); + if (nbits <= target) { + bi_ok = bi; + bo = bi - 1; + } + else { + bu = bi + 1; + } + if (bu <= bo) { + bi = (bu + bo) / 2; + } + else { + break; + } + } + if (bi_ok >= 0) { + if (bi != bi_ok) { + int const sfmax = flattenDistribution(sfwork, wrk, dm, dm, bi_ok); + nbits = tryThatOne(that, wrk, vbrsfmin, sfmax); + } + return; + } + } + + /* fall back to old code, likely to be never called */ + searchGlobalStepsizeMax(that, wrk, vbrsfmin, target); +} + + +static int +reduce_bit_usage(lame_internal_flags * gfc, int gr, int ch +#if 0 + , const FLOAT xr34orig[576], const FLOAT l3_xmin[SFBMAX], int maxbits +#endif + ) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + gr_info *const cod_info = &gfc->l3_side.tt[gr][ch]; + /* try some better scalefac storage + */ + best_scalefac_store(gfc, gr, ch, &gfc->l3_side); + + /* best huffman_divide may save some bits too + */ + if (cfg->use_best_huffman == 1) + best_huffman_divide(gfc, cod_info); + return cod_info->part2_3_length + cod_info->part2_length; +} + + + + +int +VBR_encode_frame(lame_internal_flags * gfc, const FLOAT xr34orig[2][2][576], + const FLOAT l3_xmin[2][2][SFBMAX], const int max_bits[2][2]) +{ + SessionConfig_t const *const cfg = &gfc->cfg; + int sfwork_[2][2][SFBMAX]; + int vbrsfmin_[2][2][SFBMAX]; + algo_t that_[2][2]; + int const ngr = cfg->mode_gr; + int const nch = cfg->channels_out; + int max_nbits_ch[2][2] = {{0, 0}, {0 ,0}}; + int max_nbits_gr[2] = {0, 0}; + int max_nbits_fr = 0; + int use_nbits_ch[2][2] = {{MAX_BITS_PER_CHANNEL+1, MAX_BITS_PER_CHANNEL+1} + ,{MAX_BITS_PER_CHANNEL+1, MAX_BITS_PER_CHANNEL+1}}; + int use_nbits_gr[2] = { MAX_BITS_PER_GRANULE+1, MAX_BITS_PER_GRANULE+1 }; + int use_nbits_fr = MAX_BITS_PER_GRANULE+MAX_BITS_PER_GRANULE; + int gr, ch; + int ok, sum_fr; + + /* set up some encoding parameters + */ + for (gr = 0; gr < ngr; ++gr) { + max_nbits_gr[gr] = 0; + for (ch = 0; ch < nch; ++ch) { + max_nbits_ch[gr][ch] = max_bits[gr][ch]; + use_nbits_ch[gr][ch] = 0; + max_nbits_gr[gr] += max_bits[gr][ch]; + max_nbits_fr += max_bits[gr][ch]; + that_[gr][ch].find = (cfg->full_outer_loop < 0) ? guess_scalefac_x34 : find_scalefac_x34; + that_[gr][ch].gfc = gfc; + that_[gr][ch].cod_info = &gfc->l3_side.tt[gr][ch]; + that_[gr][ch].xr34orig = xr34orig[gr][ch]; + if (that_[gr][ch].cod_info->block_type == SHORT_TYPE) { + that_[gr][ch].alloc = short_block_constrain; + } + else { + that_[gr][ch].alloc = long_block_constrain; + } + } /* for ch */ + } + /* searches scalefactors + */ + for (gr = 0; gr < ngr; ++gr) { + for (ch = 0; ch < nch; ++ch) { + if (max_bits[gr][ch] > 0) { + algo_t *that = &that_[gr][ch]; + int *sfwork = sfwork_[gr][ch]; + int *vbrsfmin = vbrsfmin_[gr][ch]; + int vbrmax; + + vbrmax = block_sf(that, l3_xmin[gr][ch], sfwork, vbrsfmin); + that->alloc(that, sfwork, vbrsfmin, vbrmax); + bitcount(that); + } + else { + /* xr contains no energy + * l3_enc, our encoding data, will be quantized to zero + * continue with next channel + */ + } + } /* for ch */ + } + /* encode 'as is' + */ + use_nbits_fr = 0; + for (gr = 0; gr < ngr; ++gr) { + use_nbits_gr[gr] = 0; + for (ch = 0; ch < nch; ++ch) { + algo_t const *that = &that_[gr][ch]; + if (max_bits[gr][ch] > 0) { + memset(&that->cod_info->l3_enc[0], 0, sizeof(that->cod_info->l3_enc)); + (void) quantizeAndCountBits(that); + } + else { + /* xr contains no energy + * l3_enc, our encoding data, will be quantized to zero + * continue with next channel + */ + } + use_nbits_ch[gr][ch] = reduce_bit_usage(gfc, gr, ch); + use_nbits_gr[gr] += use_nbits_ch[gr][ch]; + } /* for ch */ + use_nbits_fr += use_nbits_gr[gr]; + } + + /* check bit constrains + */ + if (use_nbits_fr <= max_nbits_fr) { + ok = 1; + for (gr = 0; gr < ngr; ++gr) { + if (use_nbits_gr[gr] > MAX_BITS_PER_GRANULE) { + /* violates the rule that every granule has to use no more + * bits than MAX_BITS_PER_GRANULE + */ + ok = 0; + } + for (ch = 0; ch < nch; ++ch) { + if (use_nbits_ch[gr][ch] > MAX_BITS_PER_CHANNEL) { + /* violates the rule that every gr_ch has to use no more + * bits than MAX_BITS_PER_CHANNEL + * + * This isn't explicitly stated in the ISO docs, but the + * part2_3_length field has only 12 bits, that makes it + * up to a maximum size of 4095 bits!!! + */ + ok = 0; + } + } + } + if (ok) { + return use_nbits_fr; + } + } + + /* OK, we are in trouble and have to define how many bits are + * to be used for each granule + */ + { + ok = 1; + sum_fr = 0; + + for (gr = 0; gr < ngr; ++gr) { + max_nbits_gr[gr] = 0; + for (ch = 0; ch < nch; ++ch) { + if (use_nbits_ch[gr][ch] > MAX_BITS_PER_CHANNEL) { + max_nbits_ch[gr][ch] = MAX_BITS_PER_CHANNEL; + } + else { + max_nbits_ch[gr][ch] = use_nbits_ch[gr][ch]; + } + max_nbits_gr[gr] += max_nbits_ch[gr][ch]; + } + if (max_nbits_gr[gr] > MAX_BITS_PER_GRANULE) { + float f[2] = {0.0f, 0.0f}, s = 0.0f; + for (ch = 0; ch < nch; ++ch) { + if (max_nbits_ch[gr][ch] > 0) { + f[ch] = sqrt(sqrt(max_nbits_ch[gr][ch])); + s += f[ch]; + } + else { + f[ch] = 0; + } + } + for (ch = 0; ch < nch; ++ch) { + if (s > 0) { + max_nbits_ch[gr][ch] = MAX_BITS_PER_GRANULE * f[ch] / s; + } + else { + max_nbits_ch[gr][ch] = 0; + } + } + if (nch > 1) { + if (max_nbits_ch[gr][0] > use_nbits_ch[gr][0] + 32) { + max_nbits_ch[gr][1] += max_nbits_ch[gr][0]; + max_nbits_ch[gr][1] -= use_nbits_ch[gr][0] + 32; + max_nbits_ch[gr][0] = use_nbits_ch[gr][0] + 32; + } + if (max_nbits_ch[gr][1] > use_nbits_ch[gr][1] + 32) { + max_nbits_ch[gr][0] += max_nbits_ch[gr][1]; + max_nbits_ch[gr][0] -= use_nbits_ch[gr][1] + 32; + max_nbits_ch[gr][1] = use_nbits_ch[gr][1] + 32; + } + if (max_nbits_ch[gr][0] > MAX_BITS_PER_CHANNEL) { + max_nbits_ch[gr][0] = MAX_BITS_PER_CHANNEL; + } + if (max_nbits_ch[gr][1] > MAX_BITS_PER_CHANNEL) { + max_nbits_ch[gr][1] = MAX_BITS_PER_CHANNEL; + } + } + max_nbits_gr[gr] = 0; + for (ch = 0; ch < nch; ++ch) { + max_nbits_gr[gr] += max_nbits_ch[gr][ch]; + } + } + sum_fr += max_nbits_gr[gr]; + } + if (sum_fr > max_nbits_fr) { + { + float f[2] = {0.0f, 0.0f}, s = 0.0f; + for (gr = 0; gr < ngr; ++gr) { + if (max_nbits_gr[gr] > 0) { + f[gr] = sqrt(max_nbits_gr[gr]); + s += f[gr]; + } + else { + f[gr] = 0; + } + } + for (gr = 0; gr < ngr; ++gr) { + if (s > 0) { + max_nbits_gr[gr] = max_nbits_fr * f[gr] / s; + } + else { + max_nbits_gr[gr] = 0; + } + } + } + if (ngr > 1) { + if (max_nbits_gr[0] > use_nbits_gr[0] + 125) { + max_nbits_gr[1] += max_nbits_gr[0]; + max_nbits_gr[1] -= use_nbits_gr[0] + 125; + max_nbits_gr[0] = use_nbits_gr[0] + 125; + } + if (max_nbits_gr[1] > use_nbits_gr[1] + 125) { + max_nbits_gr[0] += max_nbits_gr[1]; + max_nbits_gr[0] -= use_nbits_gr[1] + 125; + max_nbits_gr[1] = use_nbits_gr[1] + 125; + } + for (gr = 0; gr < ngr; ++gr) { + if (max_nbits_gr[gr] > MAX_BITS_PER_GRANULE) { + max_nbits_gr[gr] = MAX_BITS_PER_GRANULE; + } + } + } + for (gr = 0; gr < ngr; ++gr) { + float f[2] = {0.0f, 0.0f}, s = 0.0f; + for (ch = 0; ch < nch; ++ch) { + if (max_nbits_ch[gr][ch] > 0) { + f[ch] = sqrt(max_nbits_ch[gr][ch]); + s += f[ch]; + } + else { + f[ch] = 0; + } + } + for (ch = 0; ch < nch; ++ch) { + if (s > 0) { + max_nbits_ch[gr][ch] = max_nbits_gr[gr] * f[ch] / s; + } + else { + max_nbits_ch[gr][ch] = 0; + } + } + if (nch > 1) { + if (max_nbits_ch[gr][0] > use_nbits_ch[gr][0] + 32) { + max_nbits_ch[gr][1] += max_nbits_ch[gr][0]; + max_nbits_ch[gr][1] -= use_nbits_ch[gr][0] + 32; + max_nbits_ch[gr][0] = use_nbits_ch[gr][0] + 32; + } + if (max_nbits_ch[gr][1] > use_nbits_ch[gr][1] + 32) { + max_nbits_ch[gr][0] += max_nbits_ch[gr][1]; + max_nbits_ch[gr][0] -= use_nbits_ch[gr][1] + 32; + max_nbits_ch[gr][1] = use_nbits_ch[gr][1] + 32; + } + for (ch = 0; ch < nch; ++ch) { + if (max_nbits_ch[gr][ch] > MAX_BITS_PER_CHANNEL) { + max_nbits_ch[gr][ch] = MAX_BITS_PER_CHANNEL; + } + } + } + } + } + /* sanity check */ + sum_fr = 0; + for (gr = 0; gr < ngr; ++gr) { + int sum_gr = 0; + for (ch = 0; ch < nch; ++ch) { + sum_gr += max_nbits_ch[gr][ch]; + if (max_nbits_ch[gr][ch] > MAX_BITS_PER_CHANNEL) { + ok = 0; + } + } + sum_fr += sum_gr; + if (sum_gr > MAX_BITS_PER_GRANULE) { + ok = 0; + } + } + if (sum_fr > max_nbits_fr) { + ok = 0; + } + if (!ok) { + /* we must have done something wrong, fallback to 'on_pe' based constrain */ + for (gr = 0; gr < ngr; ++gr) { + for (ch = 0; ch < nch; ++ch) { + max_nbits_ch[gr][ch] = max_bits[gr][ch]; + } + } + } + } + + /* we already called the 'best_scalefac_store' function, so we need to reset some + * variables before we can do it again. + */ + for (ch = 0; ch < nch; ++ch) { + gfc->l3_side.scfsi[ch][0] = 0; + gfc->l3_side.scfsi[ch][1] = 0; + gfc->l3_side.scfsi[ch][2] = 0; + gfc->l3_side.scfsi[ch][3] = 0; + } + for (gr = 0; gr < ngr; ++gr) { + for (ch = 0; ch < nch; ++ch) { + gfc->l3_side.tt[gr][ch].scalefac_compress = 0; + } + } + + /* alter our encoded data, until it fits into the target bitrate + */ + use_nbits_fr = 0; + for (gr = 0; gr < ngr; ++gr) { + use_nbits_gr[gr] = 0; + for (ch = 0; ch < nch; ++ch) { + algo_t const *that = &that_[gr][ch]; + use_nbits_ch[gr][ch] = 0; + if (max_bits[gr][ch] > 0) { + int *sfwork = sfwork_[gr][ch]; + int const *vbrsfmin = vbrsfmin_[gr][ch]; + cutDistribution(sfwork, sfwork, that->cod_info->global_gain); + outOfBitsStrategy(that, sfwork, vbrsfmin, max_nbits_ch[gr][ch]); + } + use_nbits_ch[gr][ch] = reduce_bit_usage(gfc, gr, ch); + assert(use_nbits_ch[gr][ch] <= max_nbits_ch[gr][ch]); + use_nbits_gr[gr] += use_nbits_ch[gr][ch]; + } /* for ch */ + use_nbits_fr += use_nbits_gr[gr]; + } + + /* check bit constrains, but it should always be ok, iff there are no bugs ;-) + */ + if (use_nbits_fr <= max_nbits_fr) { + return use_nbits_fr; + } + + ERRORF(gfc, "INTERNAL ERROR IN VBR NEW CODE (1313), please send bug report\n" + "maxbits=%d usedbits=%d\n", max_nbits_fr, use_nbits_fr); + exit(-1); +} diff --git a/pkg/lame/clame/vbrquantize.h b/pkg/lame/clame/vbrquantize.h new file mode 100644 index 0000000..1c0d18f --- /dev/null +++ b/pkg/lame/clame/vbrquantize.h @@ -0,0 +1,28 @@ +/* + * MP3 VBR quantization + * + * Copyright (c) 1999 Mark Taylor + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef LAME_VBRQUANTIZE_H +#define LAME_VBRQUANTIZE_H + +int VBR_encode_frame(lame_internal_flags * gfc, const FLOAT xr34orig[2][2][576], + const FLOAT l3_xmin[2][2][SFBMAX], const int maxbits[2][2]); + +#endif /* LAME_VBRQUANTIZE_H */ diff --git a/pkg/lame/clame/version.c b/pkg/lame/clame/version.c new file mode 100644 index 0000000..2943406 --- /dev/null +++ b/pkg/lame/clame/version.c @@ -0,0 +1,254 @@ +/* + * Version numbering for LAME. + * + * Copyright (c) 1999 A.L. Faber + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/*! + \file version.c + \brief Version numbering for LAME. + + Contains functions which describe the version of LAME. + + \author A.L. Faber + \version \$Id: version.c,v 1.34 2011/11/18 09:51:02 robert Exp $ + \ingroup libmp3lame +*/ + + +#ifdef HAVE_CONFIG_H +# include +#endif + + +#include "lame.h" +#include "machine.h" + +#include "version.h" /* macros of version numbers */ + + + + + +/*! Get the LAME version string. */ +/*! + \param void + \return a pointer to a string which describes the version of LAME. +*/ +const char * +get_lame_version(void) +{ /* primary to write screen reports */ + /* Here we can also add informations about compile time configurations */ + +#if LAME_ALPHA_VERSION + static /*@observer@ */ const char *const str = + STR(LAME_MAJOR_VERSION) "." STR(LAME_MINOR_VERSION) " " + "(alpha " STR(LAME_PATCH_VERSION) ", " __DATE__ " " __TIME__ ")"; +#elif LAME_BETA_VERSION + static /*@observer@ */ const char *const str = + STR(LAME_MAJOR_VERSION) "." STR(LAME_MINOR_VERSION) " " + "(beta " STR(LAME_PATCH_VERSION) ", " __DATE__ ")"; +#elif LAME_RELEASE_VERSION && (LAME_PATCH_VERSION > 0) + static /*@observer@ */ const char *const str = + STR(LAME_MAJOR_VERSION) "." STR(LAME_MINOR_VERSION) "." STR(LAME_PATCH_VERSION); +#else + static /*@observer@ */ const char *const str = + STR(LAME_MAJOR_VERSION) "." STR(LAME_MINOR_VERSION); +#endif + + return str; +} + + +/*! Get the short LAME version string. */ +/*! + It's mainly for inclusion into the MP3 stream. + + \param void + \return a pointer to the short version of the LAME version string. +*/ +const char * +get_lame_short_version(void) +{ + /* adding date and time to version string makes it harder for output + validation */ + +#if LAME_ALPHA_VERSION + static /*@observer@ */ const char *const str = + STR(LAME_MAJOR_VERSION) "." STR(LAME_MINOR_VERSION) " (alpha " STR(LAME_PATCH_VERSION) ")"; +#elif LAME_BETA_VERSION + static /*@observer@ */ const char *const str = + STR(LAME_MAJOR_VERSION) "." STR(LAME_MINOR_VERSION) " (beta " STR(LAME_PATCH_VERSION) ")"; +#elif LAME_RELEASE_VERSION && (LAME_PATCH_VERSION > 0) + static /*@observer@ */ const char *const str = + STR(LAME_MAJOR_VERSION) "." STR(LAME_MINOR_VERSION) "." STR(LAME_PATCH_VERSION); +#else + static /*@observer@ */ const char *const str = + STR(LAME_MAJOR_VERSION) "." STR(LAME_MINOR_VERSION); +#endif + + return str; +} + +/*! Get the _very_ short LAME version string. */ +/*! + It's used in the LAME VBR tag only. + + \param void + \return a pointer to the short version of the LAME version string. +*/ +const char * +get_lame_very_short_version(void) +{ + /* adding date and time to version string makes it harder for output + validation */ +#if LAME_ALPHA_VERSION +#define P "a" +#elif LAME_BETA_VERSION +#define P "b" +#elif LAME_RELEASE_VERSION && (LAME_PATCH_VERSION > 0) +#define P "r" +#else +#define P " " +#endif + static /*@observer@ */ const char *const str = +#if (LAME_PATCH_VERSION > 0) + "LAME" STR(LAME_MAJOR_VERSION) "." STR(LAME_MINOR_VERSION) P STR(LAME_PATCH_VERSION) +#else + "LAME" STR(LAME_MAJOR_VERSION) "." STR(LAME_MINOR_VERSION) P +#endif + ; + return str; +} + +/*! Get the _very_ short LAME version string. */ +/*! + It's used in the LAME VBR tag only, limited to 9 characters max. + Due to some 3rd party HW/SW decoders, it has to start with LAME. + + \param void + \return a pointer to the short version of the LAME version string. + */ +const char* +get_lame_tag_encoder_short_version(void) +{ + static /*@observer@ */ const char *const str = + /* FIXME: new scheme / new version counting / drop versioning here ? */ + "LAME" STR(LAME_MAJOR_VERSION) "." STR(LAME_MINOR_VERSION) P + ; + return str; +} + +/*! Get the version string for GPSYCHO. */ +/*! + \param void + \return a pointer to a string which describes the version of GPSYCHO. +*/ +const char * +get_psy_version(void) +{ +#if PSY_ALPHA_VERSION > 0 + static /*@observer@ */ const char *const str = + STR(PSY_MAJOR_VERSION) "." STR(PSY_MINOR_VERSION) + " (alpha " STR(PSY_ALPHA_VERSION) ", " __DATE__ " " __TIME__ ")"; +#elif PSY_BETA_VERSION > 0 + static /*@observer@ */ const char *const str = + STR(PSY_MAJOR_VERSION) "." STR(PSY_MINOR_VERSION) + " (beta " STR(PSY_BETA_VERSION) ", " __DATE__ ")"; +#else + static /*@observer@ */ const char *const str = + STR(PSY_MAJOR_VERSION) "." STR(PSY_MINOR_VERSION); +#endif + + return str; +} + + +/*! Get the URL for the LAME website. */ +/*! + \param void + \return a pointer to a string which is a URL for the LAME website. +*/ +const char * +get_lame_url(void) +{ + static /*@observer@ */ const char *const str = LAME_URL; + + return str; +} + + +/*! Get the numerical representation of the version. */ +/*! + Writes the numerical representation of the version of LAME and + GPSYCHO into lvp. + + \param lvp +*/ +void +get_lame_version_numerical(lame_version_t * lvp) +{ + static /*@observer@ */ const char *const features = ""; /* obsolete */ + + /* generic version */ + lvp->major = LAME_MAJOR_VERSION; + lvp->minor = LAME_MINOR_VERSION; +#if LAME_ALPHA_VERSION + lvp->alpha = LAME_PATCH_VERSION; + lvp->beta = 0; +#elif LAME_BETA_VERSION + lvp->alpha = 0; + lvp->beta = LAME_PATCH_VERSION; +#else + lvp->alpha = 0; + lvp->beta = 0; +#endif + + /* psy version */ + lvp->psy_major = PSY_MAJOR_VERSION; + lvp->psy_minor = PSY_MINOR_VERSION; + lvp->psy_alpha = PSY_ALPHA_VERSION; + lvp->psy_beta = PSY_BETA_VERSION; + + /* compile time features */ + /*@-mustfree@ */ + lvp->features = features; + /*@=mustfree@ */ +} + + +const char * +get_lame_os_bitness(void) +{ + static /*@observer@ */ const char *const strXX = ""; + static /*@observer@ */ const char *const str32 = "32bits"; + static /*@observer@ */ const char *const str64 = "64bits"; + + switch (sizeof(void *)) { + case 4: + return str32; + + case 8: + return str64; + + default: + return strXX; + } +} + +/* end of version.c */ diff --git a/pkg/lame/clame/version.h b/pkg/lame/clame/version.h new file mode 100644 index 0000000..f5fef50 --- /dev/null +++ b/pkg/lame/clame/version.h @@ -0,0 +1,68 @@ +/* + * Version numbering for LAME. + * + * Copyright (c) 1999 A.L. Faber + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef LAME_VERSION_H +#define LAME_VERSION_H + + +/* + * To make a string from a token, use the # operator: + */ +#ifndef STR +# define __STR(x) #x +# define STR(x) __STR(x) +#endif + +# define LAME_URL "http://lame.sf.net" + + +# define LAME_MAJOR_VERSION 3 /* Major version number */ +# define LAME_MINOR_VERSION 100 /* Minor version number */ +# define LAME_TYPE_VERSION 2 /* 0:alpha 1:beta 2:release */ +# define LAME_PATCH_VERSION 0 /* Patch level */ +# define LAME_ALPHA_VERSION (LAME_TYPE_VERSION==0) +# define LAME_BETA_VERSION (LAME_TYPE_VERSION==1) +# define LAME_RELEASE_VERSION (LAME_TYPE_VERSION==2) + +# define PSY_MAJOR_VERSION 1 /* Major version number */ +# define PSY_MINOR_VERSION 0 /* Minor version number */ +# define PSY_ALPHA_VERSION 0 /* Set number if this is an alpha version, otherwise zero */ +# define PSY_BETA_VERSION 0 /* Set number if this is a beta version, otherwise zero */ + +#if LAME_ALPHA_VERSION +#define LAME_PATCH_LEVEL_STRING " alpha " STR(LAME_PATCH_VERSION) +#endif +#if LAME_BETA_VERSION +#define LAME_PATCH_LEVEL_STRING " beta " STR(LAME_PATCH_VERSION) +#endif +#if LAME_RELEASE_VERSION +#if LAME_PATCH_VERSION +#define LAME_PATCH_LEVEL_STRING " release " STR(LAME_PATCH_VERSION) +#else +#define LAME_PATCH_LEVEL_STRING "" +#endif +#endif + +# define LAME_VERSION_STRING STR(LAME_MAJOR_VERSION) "." STR(LAME_MINOR_VERSION) LAME_PATCH_LEVEL_STRING + +#endif /* LAME_VERSION_H */ + +/* End of version.h */ diff --git a/pkg/lame/clame/xmm_quantize_sub.c b/pkg/lame/clame/xmm_quantize_sub.c new file mode 100644 index 0000000..d68f761 --- /dev/null +++ b/pkg/lame/clame/xmm_quantize_sub.c @@ -0,0 +1,240 @@ +/* + * MP3 quantization, intrinsics functions + * + * Copyright (c) 2005-2006 Gabriel Bouvigne + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "lame.h" +#include "machine.h" +#include "encoder.h" +#include "util.h" +#include "lame_intrin.h" + + + +#ifdef HAVE_XMMINTRIN_H + +#include + +typedef union { + int32_t _i_32[4]; /* unions are initialized by its first member */ + float _float[4]; + __m128 _m128; +} vecfloat_union; + +#define TRI_SIZE (5-1) /* 1024 = 4**5 */ +static const FLOAT costab[TRI_SIZE * 2] = { + 9.238795325112867e-01, 3.826834323650898e-01, + 9.951847266721969e-01, 9.801714032956060e-02, + 9.996988186962042e-01, 2.454122852291229e-02, + 9.999811752826011e-01, 6.135884649154475e-03 +}; + + +/* make sure functions with SSE instructions maintain their own properly aligned stack */ +#if defined (__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 2))) +#define SSE_FUNCTION __attribute__((force_align_arg_pointer)) +#else +#define SSE_FUNCTION +#endif + + +SSE_FUNCTION void +init_xrpow_core_sse(gr_info * const cod_info, FLOAT xrpow[576], int upper, FLOAT * sum) +{ + int i; + float tmp_max = 0; + float tmp_sum = 0; + int upper4 = (upper / 4) * 4; + int rest = upper-upper4; + + const vecfloat_union fabs_mask = {{ 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF }}; + const __m128 vec_fabs_mask = _mm_loadu_ps(&fabs_mask._float[0]); + vecfloat_union vec_xrpow_max; + vecfloat_union vec_sum; + vecfloat_union vec_tmp; + + _mm_prefetch((char *) cod_info->xr, _MM_HINT_T0); + _mm_prefetch((char *) xrpow, _MM_HINT_T0); + + vec_xrpow_max._m128 = _mm_set_ps1(0); + vec_sum._m128 = _mm_set_ps1(0); + + for (i = 0; i < upper4; i += 4) { + vec_tmp._m128 = _mm_loadu_ps(&(cod_info->xr[i])); /* load */ + vec_tmp._m128 = _mm_and_ps(vec_tmp._m128, vec_fabs_mask); /* fabs */ + vec_sum._m128 = _mm_add_ps(vec_sum._m128, vec_tmp._m128); + vec_tmp._m128 = _mm_sqrt_ps(_mm_mul_ps(vec_tmp._m128, _mm_sqrt_ps(vec_tmp._m128))); + vec_xrpow_max._m128 = _mm_max_ps(vec_xrpow_max._m128, vec_tmp._m128); /* retrieve max */ + _mm_storeu_ps(&(xrpow[i]), vec_tmp._m128); /* store into xrpow[] */ + } + vec_tmp._m128 = _mm_set_ps1(0); + switch (rest) { + case 3: vec_tmp._float[2] = cod_info->xr[upper4+2]; + case 2: vec_tmp._float[1] = cod_info->xr[upper4+1]; + case 1: vec_tmp._float[0] = cod_info->xr[upper4+0]; + vec_tmp._m128 = _mm_and_ps(vec_tmp._m128, vec_fabs_mask); /* fabs */ + vec_sum._m128 = _mm_add_ps(vec_sum._m128, vec_tmp._m128); + vec_tmp._m128 = _mm_sqrt_ps(_mm_mul_ps(vec_tmp._m128, _mm_sqrt_ps(vec_tmp._m128))); + vec_xrpow_max._m128 = _mm_max_ps(vec_xrpow_max._m128, vec_tmp._m128); /* retrieve max */ + switch (rest) { + case 3: xrpow[upper4+2] = vec_tmp._float[2]; + case 2: xrpow[upper4+1] = vec_tmp._float[1]; + case 1: xrpow[upper4+0] = vec_tmp._float[0]; + default: + break; + } + default: + break; + } + tmp_sum = vec_sum._float[0] + vec_sum._float[1] + vec_sum._float[2] + vec_sum._float[3]; + { + float ma = vec_xrpow_max._float[0] > vec_xrpow_max._float[1] + ? vec_xrpow_max._float[0] : vec_xrpow_max._float[1]; + float mb = vec_xrpow_max._float[2] > vec_xrpow_max._float[3] + ? vec_xrpow_max._float[2] : vec_xrpow_max._float[3]; + tmp_max = ma > mb ? ma : mb; + } + cod_info->xrpow_max = tmp_max; + *sum = tmp_sum; +} + + +SSE_FUNCTION static void +store4(__m128 v, float* f0, float* f1, float* f2, float* f3) +{ + vecfloat_union r; + r._m128 = v; + *f0 = r._float[0]; + *f1 = r._float[1]; + *f2 = r._float[2]; + *f3 = r._float[3]; +} + + +SSE_FUNCTION void +fht_SSE2(FLOAT * fz, int n) +{ + const FLOAT *tri = costab; + int k4; + FLOAT *fi, *gi; + FLOAT const *fn; + + n <<= 1; /* to get BLKSIZE, because of 3DNow! ASM routine */ + fn = fz + n; + k4 = 4; + do { + FLOAT s1, c1; + int i, k1, k2, k3, kx; + kx = k4 >> 1; + k1 = k4; + k2 = k4 << 1; + k3 = k2 + k1; + k4 = k2 << 1; + fi = fz; + gi = fi + kx; + do { + FLOAT f0, f1, f2, f3; + f1 = fi[0] - fi[k1]; + f0 = fi[0] + fi[k1]; + f3 = fi[k2] - fi[k3]; + f2 = fi[k2] + fi[k3]; + fi[k2] = f0 - f2; + fi[0] = f0 + f2; + fi[k3] = f1 - f3; + fi[k1] = f1 + f3; + f1 = gi[0] - gi[k1]; + f0 = gi[0] + gi[k1]; + f3 = SQRT2 * gi[k3]; + f2 = SQRT2 * gi[k2]; + gi[k2] = f0 - f2; + gi[0] = f0 + f2; + gi[k3] = f1 - f3; + gi[k1] = f1 + f3; + gi += k4; + fi += k4; + } while (fi < fn); + c1 = tri[0]; + s1 = tri[1]; + for (i = 1; i < kx; i++) { + __m128 v_s2; + __m128 v_c2; + __m128 v_c1; + __m128 v_s1; + FLOAT c2, s2, s1_2 = s1+s1; + c2 = 1 - s1_2 * s1; + s2 = s1_2 * c1; + fi = fz + i; + gi = fz + k1 - i; + v_c1 = _mm_set_ps1(c1); + v_s1 = _mm_set_ps1(s1); + v_c2 = _mm_set_ps1(c2); + v_s2 = _mm_set_ps1(s2); + { + static const vecfloat_union sign_mask = {{0x80000000,0,0,0}}; + v_c1 = _mm_xor_ps(sign_mask._m128, v_c1); /* v_c1 := {-c1, +c1, +c1, +c1} */ + } + { + static const vecfloat_union sign_mask = {{0,0x80000000,0,0}}; + v_s1 = _mm_xor_ps(sign_mask._m128, v_s1); /* v_s1 := {+s1, -s1, +s1, +s1} */ + } + { + static const vecfloat_union sign_mask = {{0,0,0x80000000,0x80000000}}; + v_c2 = _mm_xor_ps(sign_mask._m128, v_c2); /* v_c2 := {+c2, +c2, -c2, -c2} */ + } + do { + __m128 p, q, r; + + q = _mm_setr_ps(fi[k1], fi[k3], gi[k1], gi[k3]); /* Q := {fi_k1,fi_k3,gi_k1,gi_k3}*/ + p = _mm_mul_ps(_mm_set_ps1(s2), q); /* P := s2 * Q */ + q = _mm_mul_ps(v_c2, q); /* Q := c2 * Q */ + q = _mm_shuffle_ps(q, q, _MM_SHUFFLE(1,0,3,2)); /* Q := {-c2*gi_k1,-c2*gi_k3,c2*fi_k1,c2*fi_k3} */ + p = _mm_add_ps(p, q); + + r = _mm_setr_ps(gi[0], gi[k2], fi[0], fi[k2]); /* R := {gi_0,gi_k2,fi_0,fi_k2} */ + q = _mm_sub_ps(r, p); /* Q := {gi_0-p0,gi_k2-p1,fi_0-p2,fi_k2-p3} */ + r = _mm_add_ps(r, p); /* R := {gi_0+p0,gi_k2+p1,fi_0+p2,fi_k2+p3} */ + p = _mm_shuffle_ps(q, r, _MM_SHUFFLE(2,0,2,0)); /* P := {q0,q2,r0,r2} */ + p = _mm_shuffle_ps(p, p, _MM_SHUFFLE(3,1,2,0)); /* P := {q0,r0,q2,r2} */ + q = _mm_shuffle_ps(q, r, _MM_SHUFFLE(3,1,3,1)); /* Q := {q1,q3,r1,r3} */ + r = _mm_mul_ps(v_c1, q); + q = _mm_mul_ps(v_s1, q); + q = _mm_shuffle_ps(q, q, _MM_SHUFFLE(0,1,2,3)); /* Q := {q3,q2,q1,q0} */ + q = _mm_add_ps(q, r); + + store4(_mm_sub_ps(p, q), &gi[k3], &gi[k2], &fi[k3], &fi[k2]); + store4(_mm_add_ps(p, q), &gi[k1], &gi[ 0], &fi[k1], &fi[ 0]); + + gi += k4; + fi += k4; + } while (fi < fn); + c2 = c1; + c1 = c2 * tri[0] - s1 * tri[1]; + s1 = c2 * tri[1] + s1 * tri[0]; + } + tri += 2; + } while (k4 < n); +} + +#endif /* HAVE_XMMINTRIN_H */ + diff --git a/pkg/lame/lame.go b/pkg/lame/lame.go new file mode 100644 index 0000000..4129ab0 --- /dev/null +++ b/pkg/lame/lame.go @@ -0,0 +1,239 @@ +package lame + +// http://www.leidinger.net/lame/doxy/html/lame_8h-source.html + +/* +#cgo CFLAGS: -DHAVE_CONFIG_H -I./clame +#cgo LDFLAGS: -lm +#include "lame.h" +*/ +import "C" + +import ( + "runtime" + "unsafe" +) + +type Handle *C.struct_lame_global_struct + +const ( + STEREO = C.STEREO + JOINT_STEREO = C.JOINT_STEREO + DUAL_CHANNEL = C.DUAL_CHANNEL /* LAME doesn't supports this! */ + MONO = C.MONO + NOT_SET = C.NOT_SET + MAX_INDICATOR = C.MAX_INDICATOR + BIT_DEPTH = 16 + + VBR_OFF = C.vbr_off + VBR_RH = C.vbr_rh + VBR_ABR = C.vbr_abr + VBR_MTRH = C.vbr_mtrh + VBR_DEFAULT = C.vbr_default + + MAX_FRAME_SIZE = 2880 +) + +const ( + ABR_8 = C.ABR_8 + ABR_320 = C.ABR_320 + V9 = C.V9 + VBR_10 = C.VBR_10 + V8 = C.V8 + VBR_20 = C.VBR_20 + V7 = C.V7 + VBR_30 = C.VBR_30 + V6 = C.V6 + VBR_40 = C.VBR_40 + V5 = C.V5 + VBR_50 = C.VBR_50 + V4 = C.V4 + VBR_60 = C.VBR_60 + V3 = C.V3 + VBR_70 = C.VBR_70 + V2 = C.V2 + VBR_80 = C.VBR_80 + V1 = C.V1 + VBR_90 = C.VBR_90 + V0 = C.V0 + VBR_100 = C.VBR_100 +) + +type Encoder struct { + handle Handle + remainder []byte + closed bool +} + +func Init() *Encoder { + handle := C.lame_init() + encoder := &Encoder{handle, make([]byte, 0), false} + runtime.SetFinalizer(encoder, finalize) + return encoder +} + +func (e *Encoder) SetVBR(mode C.vbr_mode) { + C.lame_set_VBR(e.handle, mode) +} + +func (e *Encoder) SetVBRAverageBitRate(averageBitRate int) { + C.lame_set_VBR_mean_bitrate_kbps(e.handle, C.int(averageBitRate)) +} + +func (e *Encoder) SetVBRQuality(quality int) { + C.lame_set_VBR_q(e.handle, C.int(quality)) +} + +func (e *Encoder) SetLowPassFrequency(frequency int) { + // Frequency in Hz + C.lame_set_lowpassfreq(e.handle, C.int(frequency)) +} + +func (e *Encoder) SetNumChannels(num int) { + C.lame_set_num_channels(e.handle, C.int(num)) +} + +func (e *Encoder) SetInSamplerate(sampleRate int) { + C.lame_set_in_samplerate(e.handle, C.int(sampleRate)) +} + +func (e *Encoder) SetBitrate(bitRate int) { + C.lame_set_brate(e.handle, C.int(bitRate)) +} + +func (e *Encoder) SetMode(mode C.MPEG_mode) { + C.lame_set_mode(e.handle, mode) +} + +func (e *Encoder) SetQuality(quality int) { + C.lame_set_quality(e.handle, C.int(quality)) +} + +func (e *Encoder) InitId3Tag() { + C.id3tag_init(e.handle) +} + +func (e *Encoder) SetWriteId3tagAutomatic(automaticWriteTag int) { + C.lame_set_write_id3tag_automatic(e.handle, C.int(automaticWriteTag)) +} + +func (e *Encoder) ID3TagAddV2() { + C.id3tag_add_v2(e.handle) +} + +func (e *Encoder) SetbWriteVbrTag(writeVbrTag int) { + C.lame_set_bWriteVbrTag(e.handle, C.int(writeVbrTag)) +} + +func (e *Encoder) GetLametagFrame() []byte { + tagFrame := make([]byte, MAX_FRAME_SIZE) + tagFrameLen := C.lame_get_lametag_frame(e.handle, (*C.uchar)(unsafe.Pointer(&tagFrame[0])), C.size_t(len(tagFrame))) + + return tagFrame[0:tagFrameLen] +} + +func (e *Encoder) InitParams() int { + retcode := C.lame_init_params(e.handle) + return int(retcode) +} + +func (e *Encoder) NumChannels() int { + n := C.lame_get_num_channels(e.handle) + return int(n) +} + +func (e *Encoder) Bitrate() int { + br := C.lame_get_brate(e.handle) + return int(br) +} + +func (e *Encoder) Mode() int { + m := C.lame_get_mode(e.handle) + return int(m) +} + +func (e *Encoder) Quality() int { + q := C.lame_get_quality(e.handle) + return int(q) +} + +func (e *Encoder) InSamplerate() int { + sr := C.lame_get_in_samplerate(e.handle) + return int(sr) +} + +func (e *Encoder) Encode(buf []byte) []byte { + + if len(e.remainder) > 0 { + buf = append(e.remainder, buf...) + } + + if len(buf) == 0 { + return make([]byte, 0) + } + + blockAlign := BIT_DEPTH / 8 * e.NumChannels() + + remainBytes := len(buf) % blockAlign + if remainBytes > 0 { + e.remainder = buf[len(buf)-remainBytes : len(buf)] + buf = buf[0 : len(buf)-remainBytes] + } else { + e.remainder = make([]byte, 0) + } + + numSamples := len(buf) / blockAlign + estimatedSize := int(1.25*float64(numSamples) + 7200) + out := make([]byte, estimatedSize) + + cBuf := (*C.short)(unsafe.Pointer(&buf[0])) + cOut := (*C.uchar)(unsafe.Pointer(&out[0])) + + var bytesOut C.int + + if e.NumChannels() == 1 { + bytesOut = C.int(C.lame_encode_buffer( + e.handle, + cBuf, + nil, + C.int(numSamples), + cOut, + C.int(estimatedSize), + )) + } else { + bytesOut = C.int(C.lame_encode_buffer_interleaved( + e.handle, + cBuf, + C.int(numSamples), + cOut, + C.int(estimatedSize), + )) + } + return out[0:bytesOut] + +} + +func (e *Encoder) Flush() []byte { + estimatedSize := 7200 + out := make([]byte, estimatedSize) + cOut := (*C.uchar)(unsafe.Pointer(&out[0])) + bytesOut := C.int(C.lame_encode_flush( + e.handle, + cOut, + C.int(estimatedSize), + )) + + return out[0:bytesOut] +} + +func (e *Encoder) Close() { + if e.closed { + return + } + C.lame_close(e.handle) + e.closed = true +} + +func finalize(e *Encoder) { + e.Close() +} diff --git a/pkg/lame/writer.go b/pkg/lame/writer.go new file mode 100644 index 0000000..6f6b59e --- /dev/null +++ b/pkg/lame/writer.go @@ -0,0 +1,41 @@ +package lame + +import ( + "io" +) + +type LameWriter struct { + output io.Writer + Encoder *Encoder + EncodedChunkSize int +} + +func NewWriter(out io.Writer) *LameWriter { + writer := &LameWriter{out, Init(), 0} + return writer +} + +func (lw *LameWriter) Write(p []byte) (int, error) { + // fmt.Println("lame Write len:", len(p)) + out := lw.Encoder.Encode(p) + lw.EncodedChunkSize = len(out) + + if lw.EncodedChunkSize > 0 { + _, err := lw.output.Write(out) + if err != nil { + return 0, err + } + } + + return len(p), nil +} + +func (lw *LameWriter) Close() error { + out := lw.Encoder.Flush() + if len(out) == 0 { + return nil + } + lw.Encoder.Close() + _, err := lw.output.Write(out) + return err +} diff --git a/pkg/lame/z_link_lame_c.c b/pkg/lame/z_link_lame_c.c new file mode 100644 index 0000000..830401d --- /dev/null +++ b/pkg/lame/z_link_lame_c.c @@ -0,0 +1,21 @@ +#include "./clame/reservoir.c" +#include "./clame/bitstream.c" +#include "./clame/newmdct.c" +#include "./clame/gain_analysis.c" +#include "./clame/version.c" +#include "./clame/mpglib_interface.c" +#include "./clame/xmm_quantize_sub.c" +#include "./clame/vbrquantize.c" +#include "./clame/quantize_pvt.c" +#include "./clame/VbrTag.c" +#include "./clame/encoder.c" +#include "./clame/quantize.c" +#include "./clame/takehiro.c" +#include "./clame/fft.c" +#include "./clame/lame.c" +#include "./clame/set_get.c" +#include "./clame/id3tag.c" +#include "./clame/tables.c" +#include "./clame/util.c" +#include "./clame/psymodel.c" +#include "./clame/presets.c" diff --git a/pkg/silk/csilk/Decoder_Api.c b/pkg/silk/csilk/Decoder_Api.c new file mode 100644 index 0000000..b67207b --- /dev/null +++ b/pkg/silk/csilk/Decoder_Api.c @@ -0,0 +1,80 @@ + +#include +#include +#include +#include "SKP_Silk_SDK_API.h" + +#define MAX_INPUT_FRAMES 5 + +typedef struct silk_handle{ + SKP_SILK_SDK_DecControlStruct dec_ctrl; + SKP_uint8 *dec_state; +} * silk_handle_t; + +struct silk_handle *silk_decoder_init(void) +{ + silk_handle_t handle = calloc(1, sizeof(struct silk_handle)); + if (NULL == handle) + return NULL; + + handle->dec_ctrl.API_sampleRate = 24000; + handle->dec_ctrl.framesPerPacket = 1; + + SKP_int32 dec_size; + SKP_Silk_SDK_Get_Decoder_Size(&dec_size); + + handle->dec_state = calloc(1, dec_size); + if (NULL == handle->dec_state) { + free(handle); + return NULL; + } + + SKP_Silk_SDK_InitDecoder(handle->dec_state); + + return handle; +} + +void silk_decoder_deinit(struct silk_handle *h) { + silk_handle_t handle = (silk_handle_t)h; + + if (handle) { + if (handle->dec_state) { + free(handle->dec_state); + handle->dec_state = NULL; + } + free(handle); + } +} + +int silk_decoder_process(struct silk_handle *h, unsigned char *frame, int frame_size, unsigned char *output_payload, int output_len) +{ + silk_handle_t handle = (silk_handle_t)h; + SKP_int16 *out_ptr = (SKP_int16 *)output_payload; + SKP_int16 len = 0, total_len = 0; + SKP_int32 frame_count = 0; + do { + SKP_Silk_SDK_Decode(handle->dec_state, &handle->dec_ctrl, 0, frame, frame_size, out_ptr, &len); + frame_count++; + out_ptr += len; + total_len += len; + if (frame_count > MAX_INPUT_FRAMES) { + printf("frame_count > MAX_INPUT_FRAMES frame_count %d, total_len %d\n", frame_count, total_len); + out_ptr = (SKP_int16 *)output_payload; + total_len = 0; + frame_count = 0; + } + } while (handle->dec_ctrl.moreInternalDecoderFrames); + + + return total_len * 2; +} + +int silk_decoder_set_sample_rate(struct silk_handle *h, int rate) +{ + silk_handle_t handle = (silk_handle_t)h; + if (handle) { + handle->dec_ctrl.API_sampleRate = rate; + } + + return 0; +} diff --git a/pkg/silk/csilk/SKP_Silk_A2NLSF.c b/pkg/silk/csilk/SKP_Silk_A2NLSF.c new file mode 100644 index 0000000..fd6918f --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_A2NLSF.c @@ -0,0 +1,287 @@ +/*********************************************************************** +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 ); + } +} +#if EMBEDDED_ARM<6 +/* 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; +} +#else +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 */ +); +#endif + +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/pkg/silk/csilk/SKP_Silk_AsmHelper.h b/pkg/silk/csilk/SKP_Silk_AsmHelper.h new file mode 100644 index 0000000..4e8a69b --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_AsmHelper.h @@ -0,0 +1,180 @@ +/*********************************************************************** +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_AsmHelper.h + * + * + * + * + */ + + +#ifndef _SKP_ASM_HELPER_H_ +#define _SKP_ASM_HELPER_H_ + +// Register bank +#define _REG 0 +#define _DREG 1 + +// Arg registers +#define _R0 0 +#define _R1 1 +#define _R2 2 +#define _R3 3 +#define _R4 4 +// GP registers +#define _R5 5 +#define _R6 6 +#define _R7 7 +#define _R8 8 +#define _SB 9 +#define _SL 10 +// fp and ip registers +#define _FP 11 +#define _IP 12 +// lr and sp registers +#define _SP 13 +#define _LR 14 + + +// Extension register bank +#define _numDReg + +#define _Q0 0 +#define _Q1 1 +#define _Q2 2 +#define _Q3 3 +#define _Q4 4 +#define _Q5 5 +#define _Q6 6 +#define _Q7 7 +#define _Q8 8 +#define _Q9 9 +#define _Q10 10 +#define _Q11 11 +#define _Q12 12 +#define _Q13 13 +#define _Q14 14 +#define _Q15 15 + +#if defined (_WINRT) +#else +#if defined (IPHONE) +#define MACRO .macro +#define END_MACRO .endmacro +#define ARG0_in +#define ARG1_in +#define ARG2_in +#define ARG3_in +#define ARG4_in +#define ARG5_in +#define ARG6_in +#define ARG7_in +#define ARG0 $0 +#define ARG1 $1 +#define ARG2 $2 +#define ARG3 $3 +#define ARG4 $4 +#define ARG5 $5 +#define ARG6 $6 +#define ARG7 $7 +#define RARG0 r$0 +#define RARG1 r$1 +#define QARG0 q$0 +#define QARG1 q$1 + +MACRO CHECK_ABS ARG0_in, ARG1_in + .abs is_abs, ARG1 + .if is_abs==1 + .set ARG0, ARG1 + .else + .set ARG0, -1 + .endif +END_MACRO + +#else +#define MACRO .macro +#define END_MACRO .endm +#define ARG0_in arg0=-1 +#define ARG1_in arg1=-1 +#define ARG2_in arg2=-1 +#define ARG3_in arg3=-1 +#define ARG4_in arg4=-1 +#define ARG5_in arg5=-1 +#define ARG6_in arg6=-1 +#define ARG7_in arg7=-1 +#define ARG0 \arg0 +#define ARG1 \arg1 +#define ARG2 \arg2 +#define ARG3 \arg3 +#define ARG4 \arg4 +#define ARG5 \arg5 +#define ARG6 \arg6 +#define ARG7 \arg7 +#define RARG0 r\arg0 +#define RARG1 r\arg1 +#define QARG0 q\arg0 +#define QARG1 q\arg1 + +MACRO CHECK_ABS ARG0_in, ARG1_in + .set ARG0, ARG1 +END_MACRO +#endif + +MACRO VARDEF ARG0_in, ARG1_in +ARG0 .req ARG1 +END_MACRO + +MACRO VARDEFD ARG0_in, ARG1_in +ARG0 .req ARG1 +END_MACRO + +MACRO VARDEFQ ARG0_in, ARG1_in +ARG0 .req ARG1 +END_MACRO + +MACRO END +END_MACRO + +MACRO EXTERN ARG0_in +END_MACRO + +MACRO ALIGN ARG0_in +.align ARG0 +END_MACRO + +MACRO DATA +.data +END_MACRO + +MACRO EXPORT ARG0_in +.globl ARG0 +END_MACRO + +#endif +#endif diff --git a/pkg/silk/csilk/SKP_Silk_AsmPreproc.h b/pkg/silk/csilk/SKP_Silk_AsmPreproc.h new file mode 100644 index 0000000..d2e47e8 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_AsmPreproc.h @@ -0,0 +1,220 @@ +/*********************************************************************** +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_AsmPreProc.h + * + * General header for all ARM asms uses SigProcLib. + * It contains C preprocessor part and asm preprocessor part. + * C preprocessor part: + * * Interfacing makefile, arch, fpu and neon support + * * Interfacing different symbol styles and asm directives. + * * Interfacing compiling time standard output + * ASM preprocessor part: + * * Defining general asm header/footer for stack/return value + * * Allocating stack for local variables and nasted function + * * Defining simple syntax checking and debugging routines + */ + + +/* + * C preprocessor part + */ +#ifndef _SKP_ASM_PREPROC_H_ +#define _SKP_ASM_PREPROC_H_ + +#include "SKP_Silk_AsmHelper.h" + + +/* Checking compilier __ARMEL__ defines */ +#if !__ARMEL__ && (!defined(NO_ASM)) && (!defined(_WINRT)) +#error Currently SKP_Silk_AsmPreProc only supports little endian. +// above line can be replaced by +// #warning __ARMEL__=0 +// #define NOASM +#endif + +/* Defining macro for different user label prefix. */ +#ifndef __USER_LABEL_PREFIX__ +#define __USER_LABEL_PREFIX__ +#endif + +#define CONCAT1(a, b) CONCAT2(a, b) +#define CONCAT2(a, b) a ## b + +#define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x) + +/* Remapping register for iphone. */ + +#ifdef IPHONE +# define _fp r7 +# define _r7 r11 +#else +# define _fp fp +# define _r7 r7 +#endif + +/* Checking compiler __ARM_EABI__ defines */ + +#if __ARMEB__ +#define NO_ASM //remove asm optimization for ARM big endian. +#else +#define ARM_LITTLE_ENDIAN +#endif + +/* Interfacing some asm directives to macros*/ +#define GBL .globl + +/* Legacy definition wrapper */ +#ifndef NO_ASM +#if defined (__ARM_ARCH_4__) || defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_5__) || defined (__ARM_ARCH_5T__) +#define EMBEDDED_ARM 4 +#define EMBEDDED_ARMv4 +#elif defined (__ARM_ARCH_5TE__) || defined (__ARM_ARCH_5TEJ__) +#define EMBEDDED_ARM 5 +#define EMBEDDED_ARMv5 +#elif defined (__ARM_ARCH_6__) ||defined (__ARM_ARCH_6J__) || defined (__ARM_ARCH_6Z__) || defined (__ARM_ARCH_6K__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) +#define EMBEDDED_ARM 6 +#define EMBEDDED_ARMv6 +#elif defined (__ARM_ARCH_7A__) && defined (__ARM_NEON__) +#define EMBEDDED_ARM 7 +#define EMBEDDED_ARMv6 +#elif defined (__ARM_ARCH_7A__) +#define EMBEDDED_ARM 6 +#define EMBEDDED_ARMv6 +#else +#define EMBEDDED_ARM 0 +#endif +#endif + +#ifdef _WINRT +#define L(a) a +#define LR(a,d) %##d##a + +#define TABLE(L, symbol) symbol +#else +#define L(a) a: +#define LR(a,d) a##d +#define DCD .long +#define DCW .short +#define TABLE(L, symbol) L +#endif + +#ifdef _WINRT +#define streqh strheq +#define strneh strhne +#define strgth strhgt +#define strlth strhlt +#define ldrgtsh ldrshgt +#define ldmgtia ldmiagt +#define ldmgtdb ldmdbgt +#define ldrneh ldrhne +#define ldmltia ldmialt +#endif +/* + * ASM preprocessor part: + */ + +#ifdef _WINRT +#else +// AT&T Format +#if EMBEDDED_ARM >= 7 +.set _ARCH, 7 +#elif EMBEDDED_ARM >= 6 +.set _ARCH, 6 +#elif EMBEDDED_ARM >= 5 // Should be re-considerred as ARMv5 != ARMv5E +.set _ARCH, 5 +#elif EMBEDDED_ARM >= 4 +.set _ARCH, 4 +#else +.set _ARCH, 0 +#endif + +#if NEON +.set _NEON, 1 +#else +.set _NEON, 0 +#endif + +MACRO SKP_TABLE ARG0_in, ARG1_in +SYM(ARG0): +END_MACRO + + + +MACRO SKP_SMLAD ARG0_in, ARG1_in, ARG2_in, ARG3_in +#if EMBEDDED_ARM>=6 + smlad ARG0, ARG1, ARG2, ARG3 +#elif EMBEDDED_ARM>=5 + smlabb ARG0, ARG1, ARG2, ARG3 + smlatt ARG0, ARG1, ARG2, ARG0 +#else + .abort "SKP_SMUAD can't be used for armv4 or lower device.." +#endif +END_MACRO + +MACRO SKP_SMUAD ARG0_in, ARG1_in, ARG2_in +#if EMBEDDED_ARM>=6 + smuad ARG0, ARG1, ARG2 +#elif EMBEDDED_ARM>=5 + smulbb ARG0, ARG1, ARG2 + smlatt ARG0, ARG1, ARG2, ARG0 +#else + .abort "SKP_SMUAD can't be used for armv4 or lower device.." +#endif +END_MACRO + +MACRO SKP_SMLALD ARG0_in, ARG1_in, ARG2_in, ARG3_in +#if EMBEDDED_ARM>=6 + smlald ARG0, ARG1, ARG2, ARG3 +#elif EMBEDDED_ARM>=5 + smlalbb ARG0, ARG1, ARG2, ARG3 + smlaltt ARG0, ARG1, ARG2, ARG3 +#else + .abort "SKP_SMLALD can't be used for armv4 or lower device.." +#endif +END_MACRO + +MACRO SKP_RSHIFT_ROUND ARG0_in, ARG1_in, ARG2_in +#if EMBEDDED_ARM>=4 + mov ARG0, ARG1, asr #(ARG2-1) + add ARG0, ARG0, #1 + mov ARG0, ARG0, asr #1 +#else + .abort "SKP_RSHIFT_ROUND can't be used for armv3 or lower device.." +#endif +END_MACRO + +MACRO ADD_SHIFT ARG0_in, ARG1_in, ARG2_in, ARG3_in, ARG4_in + add ARG0, ARG1, ARG2, ARG3 ARG4 +END_MACRO + +MACRO POST_IR ARG0_in, ARG1_in, ARG2_in, ARG3_in + ARG0 ARG1, [ARG2], ARG3 +END_MACRO + +#endif +#endif //_SKP_ASM_PREPROC_H_ diff --git a/pkg/silk/csilk/SKP_Silk_CNG.c b/pkg/silk/csilk/SKP_Silk_CNG.c new file mode 100644 index 0000000..8d0e6a1 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_HP_variable_cutoff_FIX.c b/pkg/silk/csilk/SKP_Silk_HP_variable_cutoff_FIX.c new file mode 100644 index 0000000..6a3b35a --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_HP_variable_cutoff_FIX.c @@ -0,0 +1,120 @@ +/*********************************************************************** +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_FIX.h" +#include "SKP_Silk_tuning_parameters.h" + +#if HIGH_PASS_INPUT + +#define SKP_RADIANS_CONSTANT_Q19 1482 // 0.45f * 2.0f * 3.14159265359 / 1000 +#define SKP_LOG2_VARIABLE_HP_MIN_FREQ_Q7 809 // log(80) in Q7 + +/* High-pass filter with cutoff frequency adaptation based on pitch lag statistics */ +void SKP_Silk_HP_variable_cutoff_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Encoder state FIX */ + SKP_Silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control FIX */ + SKP_int16 *out, /* O high-pass filtered output signal */ + const SKP_int16 *in /* I input signal */ +) +{ + SKP_int quality_Q15; + SKP_int32 B_Q28[ 3 ], A_Q28[ 2 ]; + SKP_int32 Fc_Q19, r_Q28, r_Q22; + SKP_int32 pitch_freq_Hz_Q16, pitch_freq_log_Q7, delta_freq_Q7; + + /*********************************************/ + /* Estimate Low End of Pitch Frequency Range */ + /*********************************************/ + if( psEnc->sCmn.prev_sigtype == SIG_TYPE_VOICED ) { + /* difference, in log domain */ + pitch_freq_Hz_Q16 = SKP_DIV32_16( SKP_LSHIFT( SKP_MUL( psEnc->sCmn.fs_kHz, 1000 ), 16 ), psEnc->sCmn.prevLag ); + pitch_freq_log_Q7 = SKP_Silk_lin2log( pitch_freq_Hz_Q16 ) - ( 16 << 7 ); //0x70 + + /* adjustment based on quality */ + quality_Q15 = psEncCtrl->input_quality_bands_Q15[ 0 ]; + pitch_freq_log_Q7 = SKP_SUB32( pitch_freq_log_Q7, SKP_SMULWB( SKP_SMULWB( SKP_LSHIFT( quality_Q15, 2 ), quality_Q15 ), + pitch_freq_log_Q7 - SKP_LOG2_VARIABLE_HP_MIN_FREQ_Q7 ) ); + pitch_freq_log_Q7 = SKP_ADD32( pitch_freq_log_Q7, SKP_RSHIFT( SKP_FIX_CONST( 0.6, 15 ) - quality_Q15, 9 ) ); + + //delta_freq = pitch_freq_log - psEnc->variable_HP_smth1; + delta_freq_Q7 = pitch_freq_log_Q7 - SKP_RSHIFT( psEnc->variable_HP_smth1_Q15, 8 ); + if( delta_freq_Q7 < 0 ) { + /* less smoothing for decreasing pitch frequency, to track something close to the minimum */ + delta_freq_Q7 = SKP_MUL( delta_freq_Q7, 3 ); + } + + /* limit delta, to reduce impact of outliers */ + delta_freq_Q7 = SKP_LIMIT_32( delta_freq_Q7, -SKP_FIX_CONST( VARIABLE_HP_MAX_DELTA_FREQ, 7 ), SKP_FIX_CONST( VARIABLE_HP_MAX_DELTA_FREQ, 7 ) ); + + /* update smoother */ + psEnc->variable_HP_smth1_Q15 = SKP_SMLAWB( psEnc->variable_HP_smth1_Q15, + SKP_MUL( SKP_LSHIFT( psEnc->speech_activity_Q8, 1 ), delta_freq_Q7 ), SKP_FIX_CONST( VARIABLE_HP_SMTH_COEF1, 16 ) ); + } + /* second smoother */ + psEnc->variable_HP_smth2_Q15 = SKP_SMLAWB( psEnc->variable_HP_smth2_Q15, + psEnc->variable_HP_smth1_Q15 - psEnc->variable_HP_smth2_Q15, SKP_FIX_CONST( VARIABLE_HP_SMTH_COEF2, 16 ) ); + + /* convert from log scale to Hertz */ + psEncCtrl->pitch_freq_low_Hz = SKP_Silk_log2lin( SKP_RSHIFT( psEnc->variable_HP_smth2_Q15, 8 ) ); + + /* limit frequency range */ + psEncCtrl->pitch_freq_low_Hz = SKP_LIMIT_32( psEncCtrl->pitch_freq_low_Hz, + SKP_FIX_CONST( VARIABLE_HP_MIN_FREQ, 0 ), SKP_FIX_CONST( VARIABLE_HP_MAX_FREQ, 0 ) ); + + /********************************/ + /* Compute Filter Coefficients */ + /********************************/ + /* compute cut-off frequency, in radians */ + //Fc_num = (SKP_float)( 0.45f * 2.0f * 3.14159265359 * psEncCtrl->pitch_freq_low_Hz ); + //Fc_denom = (SKP_float)( 1e3f * psEnc->sCmn.fs_kHz ); + SKP_assert( psEncCtrl->pitch_freq_low_Hz <= SKP_int32_MAX / SKP_RADIANS_CONSTANT_Q19 ); + Fc_Q19 = SKP_DIV32_16( SKP_SMULBB( SKP_RADIANS_CONSTANT_Q19, psEncCtrl->pitch_freq_low_Hz ), psEnc->sCmn.fs_kHz ); // range: 3704 - 27787, 11-15 bits + SKP_assert( Fc_Q19 >= 3704 ); + SKP_assert( Fc_Q19 <= 27787 ); + + r_Q28 = SKP_FIX_CONST( 1.0, 28 ) - SKP_MUL( SKP_FIX_CONST( 0.92, 9 ), Fc_Q19 ); + SKP_assert( r_Q28 >= 255347779 ); + SKP_assert( r_Q28 <= 266690872 ); + + /* b = r * [ 1; -2; 1 ]; */ + /* a = [ 1; -2 * r * ( 1 - 0.5 * Fc^2 ); r^2 ]; */ + B_Q28[ 0 ] = r_Q28; + B_Q28[ 1 ] = SKP_LSHIFT( -r_Q28, 1 ); + B_Q28[ 2 ] = r_Q28; + + // -r * ( 2 - Fc * Fc ); + r_Q22 = SKP_RSHIFT( r_Q28, 6 ); + A_Q28[ 0 ] = SKP_SMULWW( r_Q22, SKP_SMULWW( Fc_Q19, Fc_Q19 ) - SKP_FIX_CONST( 2.0, 22 ) ); + A_Q28[ 1 ] = SKP_SMULWW( r_Q22, r_Q22 ); + + /********************************/ + /* 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/pkg/silk/csilk/SKP_Silk_Inlines.h b/pkg/silk/csilk/SKP_Silk_Inlines.h new file mode 100644 index 0000000..6810e86 --- /dev/null +++ b/pkg/silk/csilk/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 SKP_Silk_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/pkg/silk/csilk/SKP_Silk_LBRR_reset.c b/pkg/silk/csilk/SKP_Silk_LBRR_reset.c new file mode 100644 index 0000000..f9ef0e6 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_LPC_inv_pred_gain.c b/pkg/silk/csilk/SKP_Silk_LPC_inv_pred_gain.c new file mode 100644 index 0000000..3f8de6f --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_LPC_inv_pred_gain.c @@ -0,0 +1,154 @@ +/*********************************************************************** +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" + +#undef QA +#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/pkg/silk/csilk/SKP_Silk_LPC_synthesis_filter.c b/pkg/silk/csilk/SKP_Silk_LPC_synthesis_filter.c new file mode 100644 index 0000000..9121e58 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_LPC_synthesis_filter.c @@ -0,0 +1,117 @@ +/*********************************************************************** +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; +#if !defined(_SYSTEM_IS_BIG_ENDIAN) + SKP_int32 Atmp, A_align_Q12[ SKP_Silk_MAX_ORDER_LPC >> 1 ]; + + /* combine two A_Q12 values and ensure 32-bit alignment */ + for( k = 0; k < Order_half; k++ ) { + idx = SKP_SMULBB( 2, k ); + A_align_Q12[ k ] = ( ( ( SKP_int32 )A_Q12[ idx ] ) & 0x0000ffff ) | SKP_LSHIFT( ( SKP_int32 )A_Q12[ idx + 1 ], 16 ); + } +#endif + + /* 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; +#if !defined(_SYSTEM_IS_BIG_ENDIAN) + /* multiply-add two prediction coefficients for each loop */ + /* NOTE: the code below loads two int16 values in an int32, and multiplies each using the */ + /* SMLAWB and SMLAWT instructions. On a big-endian CPU the two int16 variables would be */ + /* loaded in reverse order and the code will give the wrong result. In that case swapping */ + /* the SMLAWB and SMLAWT instructions should solve the problem. */ + Atmp = A_align_Q12[ j ]; + SB = S[ Order - 1 - idx ]; + S[ Order - 1 - idx ] = SA; + out32_Q10 = SKP_SMLAWB( out32_Q10, SA, Atmp ); + out32_Q10 = SKP_SMLAWT( out32_Q10, SB, Atmp ); + SA = S[ Order - 2 - idx ]; + S[ Order - 2 - idx ] = SB; +#else + 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; +#endif + } + +#if !defined(_SYSTEM_IS_BIG_ENDIAN) + /* unrolled loop: epilog */ + Atmp = A_align_Q12[ Order_half - 1 ]; + SB = S[ 0 ]; + S[ 0 ] = SA; + out32_Q10 = SKP_SMLAWB( out32_Q10, SA, Atmp ); + out32_Q10 = SKP_SMLAWT( out32_Q10, SB, Atmp ); +#else + /* 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 ] ); +#endif + /* 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/pkg/silk/csilk/SKP_Silk_LPC_synthesis_order16.c b/pkg/silk/csilk/SKP_Silk_LPC_synthesis_order16.c new file mode 100644 index 0000000..eae2435 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_LPC_synthesis_order16.c @@ -0,0 +1,216 @@ +/*********************************************************************** +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; +#if !defined(_SYSTEM_IS_BIG_ENDIAN) + SKP_int32 Atmp, A_align_Q12[ 8 ]; + /* combine two A_Q12 values and ensure 32-bit alignment */ + for( k = 0; k < 8; k++ ) { + A_align_Q12[ k ] = ( ( ( SKP_int32 )A_Q12[ 2 * k ] ) & 0x0000ffff ) | SKP_LSHIFT( ( SKP_int32 )A_Q12[ 2 * k + 1 ], 16 ); + } + /* S[] values are in Q14 */ + /* NOTE: the code below loads two int16 values in an int32, and multiplies each using the */ + /* SMLAWB and SMLAWT instructions. On a big-endian CPU the two int16 variables would be */ + /* loaded in reverse order and the code will give the wrong result. In that case swapping */ + /* the SMLAWB and SMLAWT instructions should solve the problem. */ + for( k = 0; k < len; k++ ) { + /* unrolled loop: prolog */ + /* multiply-add two prediction coefficients per iteration */ + SA = S[ 15 ]; + Atmp = A_align_Q12[ 0 ]; + SB = S[ 14 ]; + S[ 14 ] = SA; + out32_Q10 = SKP_SMULWB( SA, Atmp ); + out32_Q10 = SKP_SMLAWT_ovflw( out32_Q10, SB, Atmp ); + SA = S[ 13 ]; + S[ 13 ] = SB; + + /* unrolled loop: main loop */ + Atmp = A_align_Q12[ 1 ]; + SB = S[ 12 ]; + S[ 12 ] = SA; + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SA, Atmp ); + out32_Q10 = SKP_SMLAWT_ovflw( out32_Q10, SB, Atmp ); + SA = S[ 11 ]; + S[ 11 ] = SB; + + Atmp = A_align_Q12[ 2 ]; + SB = S[ 10 ]; + S[ 10 ] = SA; + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SA, Atmp ); + out32_Q10 = SKP_SMLAWT_ovflw( out32_Q10, SB, Atmp ); + SA = S[ 9 ]; + S[ 9 ] = SB; + + Atmp = A_align_Q12[ 3 ]; + SB = S[ 8 ]; + S[ 8 ] = SA; + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SA, Atmp ); + out32_Q10 = SKP_SMLAWT_ovflw( out32_Q10, SB, Atmp ); + SA = S[ 7 ]; + S[ 7 ] = SB; + + Atmp = A_align_Q12[ 4 ]; + SB = S[ 6 ]; + S[ 6 ] = SA; + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SA, Atmp ); + out32_Q10 = SKP_SMLAWT_ovflw( out32_Q10, SB, Atmp ); + SA = S[ 5 ]; + S[ 5 ] = SB; + + Atmp = A_align_Q12[ 5 ]; + SB = S[ 4 ]; + S[ 4 ] = SA; + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SA, Atmp ); + out32_Q10 = SKP_SMLAWT_ovflw( out32_Q10, SB, Atmp ); + SA = S[ 3 ]; + S[ 3 ] = SB; + + Atmp = A_align_Q12[ 6 ]; + SB = S[ 2 ]; + S[ 2 ] = SA; + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SA, Atmp ); + out32_Q10 = SKP_SMLAWT_ovflw( out32_Q10, SB, Atmp ); + SA = S[ 1 ]; + S[ 1 ] = SB; + + /* unrolled loop: epilog */ + Atmp = A_align_Q12[ 7 ]; + SB = S[ 0 ]; + S[ 0 ] = SA; + out32_Q10 = SKP_SMLAWB_ovflw( out32_Q10, SA, Atmp ); + out32_Q10 = SKP_SMLAWT_ovflw( out32_Q10, SB, Atmp ); + + /* 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 ); + } +#else + 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 ); + } +#endif +} + + diff --git a/pkg/silk/csilk/SKP_Silk_LP_variable_cutoff.c b/pkg/silk/csilk/SKP_Silk_LP_variable_cutoff.c new file mode 100644 index 0000000..ed19466 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_LSF_cos_table.c b/pkg/silk/csilk/SKP_Silk_LSF_cos_table.c new file mode 100644 index 0000000..4d9ffe5 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_LTP_analysis_filter_FIX.c b/pkg/silk/csilk/SKP_Silk_LTP_analysis_filter_FIX.c new file mode 100644 index 0000000..612124c --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_LTP_analysis_filter_FIX.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_FIX.h" + +void SKP_Silk_LTP_analysis_filter_FIX( + SKP_int16 *LTP_res, /* O: LTP residual signal of length NB_SUBFR * ( pre_length + subfr_length ) */ + const SKP_int16 *x, /* I: Pointer to input signal with at least max( pitchL ) preceeding samples */ + const SKP_int16 LTPCoef_Q14[ LTP_ORDER * NB_SUBFR ],/* I: LTP_ORDER LTP coefficients for each NB_SUBFR subframe */ + const SKP_int pitchL[ NB_SUBFR ], /* I: Pitch lag, one for each subframe */ + const SKP_int32 invGains_Q16[ NB_SUBFR ], /* I: Inverse quantization gains, one for each subframe */ + const SKP_int subfr_length, /* I: Length of each subframe */ + const SKP_int pre_length /* I: Length of the preceeding samples starting at &x[0] for each subframe */ +) +{ + const SKP_int16 *x_ptr, *x_lag_ptr; + SKP_int16 Btmp_Q14[ LTP_ORDER ]; + SKP_int16 *LTP_res_ptr; + SKP_int k, i, j; + SKP_int32 LTP_est; + + x_ptr = x; + LTP_res_ptr = LTP_res; + for( k = 0; k < NB_SUBFR; k++ ) { + + x_lag_ptr = x_ptr - pitchL[ k ]; + for( i = 0; i < LTP_ORDER; i++ ) { + Btmp_Q14[ i ] = LTPCoef_Q14[ k * LTP_ORDER + i ]; + } + + /* LTP analysis FIR filter */ + for( i = 0; i < subfr_length + pre_length; i++ ) { + LTP_res_ptr[ i ] = x_ptr[ i ]; + + /* Long-term prediction */ + LTP_est = SKP_SMULBB( x_lag_ptr[ LTP_ORDER / 2 ], Btmp_Q14[ 0 ] ); + for( j = 1; j < LTP_ORDER; j++ ) { + LTP_est = SKP_SMLABB_ovflw( LTP_est, x_lag_ptr[ LTP_ORDER / 2 - j ], Btmp_Q14[ j ] ); + } + LTP_est = SKP_RSHIFT_ROUND( LTP_est, 14 ); // round and -> Q0 + + /* Subtract long-term prediction */ + LTP_res_ptr[ i ] = ( SKP_int16 )SKP_SAT16( ( SKP_int32 )x_ptr[ i ] - LTP_est ); + + /* Scale residual */ + LTP_res_ptr[ i ] = SKP_SMULWB( invGains_Q16[ k ], LTP_res_ptr[ i ] ); + + x_lag_ptr++; + } + + /* Update pointers */ + LTP_res_ptr += subfr_length + pre_length; + x_ptr += subfr_length; + } +} + diff --git a/pkg/silk/csilk/SKP_Silk_LTP_scale_ctrl_FIX.c b/pkg/silk/csilk/SKP_Silk_LTP_scale_ctrl_FIX.c new file mode 100644 index 0000000..51283b5 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_LTP_scale_ctrl_FIX.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. +***********************************************************************/ + +#include "SKP_Silk_main_FIX.h" + +#define NB_THRESHOLDS 11 + +/* Table containing trained thresholds for LTP scaling */ +static const SKP_int16 LTPScaleThresholds_Q15[ NB_THRESHOLDS ] = +{ + 31129, 26214, 16384, 13107, 9830, 6554, + 4915, 3276, 2621, 2458, 0 +}; + +void SKP_Silk_LTP_scale_ctrl_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O encoder state FIX */ + SKP_Silk_encoder_control_FIX *psEncCtrl /* I/O encoder control FIX */ +) +{ + SKP_int round_loss, frames_per_packet; + SKP_int g_out_Q5, g_limit_Q15, thrld1_Q15, thrld2_Q15; + + /* 1st order high-pass filter */ + psEnc->HPLTPredCodGain_Q7 = SKP_max_int( psEncCtrl->LTPredCodGain_Q7 - psEnc->prevLTPredCodGain_Q7, 0 ) + + SKP_RSHIFT_ROUND( psEnc->HPLTPredCodGain_Q7, 1 ); + + psEnc->prevLTPredCodGain_Q7 = psEncCtrl->LTPredCodGain_Q7; + + /* combine input and filtered input */ + g_out_Q5 = SKP_RSHIFT_ROUND( SKP_RSHIFT( psEncCtrl->LTPredCodGain_Q7, 1 ) + SKP_RSHIFT( psEnc->HPLTPredCodGain_Q7, 1 ), 3 ); + g_limit_Q15 = SKP_Silk_sigm_Q15( g_out_Q5 - ( 3 << 5 ) ); + + /* Default is minimum scaling */ + psEncCtrl->sCmn.LTP_scaleIndex = 0; + + /* Round the loss measure to whole pct */ + round_loss = ( SKP_int )psEnc->sCmn.PacketLoss_perc; + + /* Only scale if first frame in packet 0% */ + if( psEnc->sCmn.nFramesInPayloadBuf == 0 ) { + + frames_per_packet = SKP_DIV32_16( psEnc->sCmn.PacketSize_ms, FRAME_LENGTH_MS ); + + round_loss += frames_per_packet - 1; + thrld1_Q15 = LTPScaleThresholds_Q15[ SKP_min_int( round_loss, NB_THRESHOLDS - 1 ) ]; + thrld2_Q15 = LTPScaleThresholds_Q15[ SKP_min_int( round_loss + 1, NB_THRESHOLDS - 1 ) ]; + + if( g_limit_Q15 > thrld1_Q15 ) { + /* Maximum scaling */ + psEncCtrl->sCmn.LTP_scaleIndex = 2; + } else if( g_limit_Q15 > thrld2_Q15 ) { + /* Medium scaling */ + psEncCtrl->sCmn.LTP_scaleIndex = 1; + } + } + psEncCtrl->LTP_scale_Q14 = SKP_Silk_LTPScales_table_Q14[ psEncCtrl->sCmn.LTP_scaleIndex ]; +} diff --git a/pkg/silk/csilk/SKP_Silk_MA.c b/pkg/silk/csilk/SKP_Silk_MA.c new file mode 100644 index 0000000..fcdce14 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_MA.c @@ -0,0 +1,120 @@ +/*********************************************************************** +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" + +#if EMBEDDED_ARM<5 +/* 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 ); + } +} +#endif + +#if EMBEDDED_ARM<5 + +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 ]; + } +} +#endif + diff --git a/pkg/silk/csilk/SKP_Silk_NLSF2A.c b/pkg/silk/csilk/SKP_Silk_NLSF2A.c new file mode 100644 index 0000000..732b0f9 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_NLSF2A_stable.c b/pkg/silk/csilk/SKP_Silk_NLSF2A_stable.c new file mode 100644 index 0000000..63da339 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_NLSF_MSVQ_decode.c b/pkg/silk/csilk/SKP_Silk_NLSF_MSVQ_decode.c new file mode 100644 index 0000000..aa3983f --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_NLSF_MSVQ_encode_FIX.c b/pkg/silk/csilk/SKP_Silk_NLSF_MSVQ_encode_FIX.c new file mode 100644 index 0000000..5bae4de --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_NLSF_MSVQ_encode_FIX.c @@ -0,0 +1,239 @@ +/*********************************************************************** +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_FIX.h" + +/***********************/ +/* NLSF vector encoder */ +/***********************/ +void SKP_Silk_NLSF_MSVQ_encode_FIX( + SKP_int *NLSFIndices, /* O Codebook path vector [ CB_STAGES ] */ + SKP_int *pNLSF_Q15, /* I/O Quantized NLSF vector [ LPC_ORDER ] */ + const SKP_Silk_NLSF_CB_struct *psNLSF_CB, /* I Codebook object */ + const SKP_int *pNLSF_q_Q15_prev, /* I Prev. quantized NLSF vector [LPC_ORDER] */ + const SKP_int *pW_Q6, /* I NLSF weight vector [ LPC_ORDER ] */ + const SKP_int NLSF_mu_Q15, /* I Rate weight for the RD optimization */ + const SKP_int NLSF_mu_fluc_red_Q16, /* 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 = 0, prev_survivors, min_survivors, input_index, cb_index, bestIndex; + SKP_int32 rateDistThreshold_Q18; +#if( NLSF_MSVQ_FLUCTUATION_REDUCTION == 1 ) + SKP_int32 se_Q15, wsse_Q20, bestRateDist_Q20; +#endif + +#if( LOW_COMPLEXITY_ONLY == 1 ) + SKP_int32 pRateDist_Q18[ NLSF_MSVQ_TREE_SEARCH_MAX_VECTORS_EVALUATED_LC_MODE ]; + SKP_int32 pRate_Q5[ MAX_NLSF_MSVQ_SURVIVORS_LC_MODE ]; + SKP_int32 pRate_new_Q5[ 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_int pRes_Q15[ MAX_NLSF_MSVQ_SURVIVORS_LC_MODE * MAX_LPC_ORDER ]; + SKP_int pRes_new_Q15[ MAX_NLSF_MSVQ_SURVIVORS_LC_MODE * MAX_LPC_ORDER ]; +#else + SKP_int32 pRateDist_Q18[ NLSF_MSVQ_TREE_SEARCH_MAX_VECTORS_EVALUATED ]; + SKP_int32 pRate_Q5[ MAX_NLSF_MSVQ_SURVIVORS ]; + SKP_int32 pRate_new_Q5[ 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_int pRes_Q15[ MAX_NLSF_MSVQ_SURVIVORS * MAX_LPC_ORDER ]; + SKP_int pRes_new_Q15[ MAX_NLSF_MSVQ_SURVIVORS * MAX_LPC_ORDER ]; +#endif + + const SKP_int *pConstInt; + SKP_int *pInt; + const SKP_int16 *pCB_element; + const SKP_Silk_NLSF_CBS *pCurrentCBStage; + +#ifdef USE_UNQUANTIZED_LSFS + SKP_int NLSF_orig[ MAX_LPC_ORDER ]; + SKP_memcpy( NLSF_orig, pNLSF_Q15, LPC_order * sizeof( SKP_int ) ); +#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 ) ); + + + /****************************************************/ + /* Tree search for the multi-stage vector quantizer */ + /****************************************************/ + + /* Clear accumulated rates */ + SKP_memset( pRate_Q5, 0, NLSF_MSVQ_Survivors * sizeof( SKP_int32 ) ); + + /* Copy NLSFs into residual signal vector */ + for( i = 0; i < LPC_order; i++ ) { + pRes_Q15[ i ] = pNLSF_Q15[ i ]; + } + + /* 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->nStages; s++ ) { + + /* Set a pointer to the current stage codebook */ + pCurrentCBStage = &psNLSF_CB->CBStages[ s ]; + + /* Calculate the number of survivors in the current stage */ + cur_survivors = SKP_min_32( NLSF_MSVQ_Survivors, SKP_SMULBB( 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->nStages - 1 ) { + cur_survivors = 1; + } +#endif + + /* Nearest neighbor clustering for multiple input data vectors */ + SKP_Silk_NLSF_VQ_rate_distortion_FIX( pRateDist_Q18, pCurrentCBStage, pRes_Q15, pW_Q6, + pRate_Q5, NLSF_mu_Q15, prev_survivors, LPC_order ); + + /* Sort the rate-distortion errors */ + SKP_Silk_insertion_sort_increasing( pRateDist_Q18, pTempIndices, + prev_survivors * pCurrentCBStage->nVectors, cur_survivors ); + + /* Discard survivors with rate-distortion values too far above the best one */ + if( pRateDist_Q18[ 0 ] < SKP_int32_MAX / MAX_NLSF_MSVQ_SURVIVORS ) { + rateDistThreshold_Q18 = SKP_SMLAWB( pRateDist_Q18[ 0 ], + SKP_MUL( NLSF_MSVQ_Survivors, pRateDist_Q18[ 0 ] ), SKP_FIX_CONST( NLSF_MSVQ_SURV_MAX_REL_RD, 16 ) ); + while( pRateDist_Q18[ cur_survivors - 1 ] > rateDistThreshold_Q18 && 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 = SKP_DIV32_16( pTempIndices[ k ], pCurrentCBStage->nVectors ); + cb_index = pTempIndices[ k ] - SKP_SMULBB( 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' */ + pConstInt = &pRes_Q15[ SKP_SMULBB( input_index, LPC_order ) ]; + pCB_element = &pCurrentCBStage->CB_NLSF_Q15[ SKP_SMULBB( cb_index, LPC_order ) ]; + pInt = &pRes_new_Q15[ SKP_SMULBB( k, LPC_order ) ]; + for( i = 0; i < LPC_order; i++ ) { + pInt[ i ] = pConstInt[ i ] - ( SKP_int )pCB_element[ i ]; + } + + /* Update accumulated rate for stage 1 to the current */ + pRate_new_Q5[ k ] = pRate_Q5[ input_index ] + pCurrentCBStage->Rates_Q5[ cb_index ]; + + /* Copy paths from previous matrix, starting with the best path */ + pConstInt = &pPath[ SKP_SMULBB( input_index, psNLSF_CB->nStages ) ]; + pInt = &pPath_new[ SKP_SMULBB( k, psNLSF_CB->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->nStages - 1 ) { + /* Copy NLSF residual matrix for next stage */ + SKP_memcpy( pRes_Q15, pRes_new_Q15, SKP_SMULBB( cur_survivors, LPC_order ) * sizeof( SKP_int ) ); + + /* Copy rate vector for next stage */ + SKP_memcpy( pRate_Q5, pRate_new_Q5, cur_survivors * sizeof( SKP_int32 ) ); + + /* Copy best path matrix for next stage */ + SKP_memcpy( pPath, pPath_new, SKP_SMULBB( cur_survivors, psNLSF_CB->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_Q20 = SKP_int32_MAX; + for( s = 0; s < cur_survivors; s++ ) { + /* Decode survivor to compare with previous quantized NLSF vector */ + SKP_Silk_NLSF_MSVQ_decode( pNLSF_Q15, psNLSF_CB, &pPath_new[ SKP_SMULBB( s, psNLSF_CB->nStages ) ], LPC_order ); + + /* Compare decoded NLSF vector with the previously quantized vector */ + wsse_Q20 = 0; + for( i = 0; i < LPC_order; i += 2 ) { + /* Compute weighted squared quantization error for index i */ + se_Q15 = pNLSF_Q15[ i ] - pNLSF_q_Q15_prev[ i ]; // range: [ -32767 : 32767 ] + wsse_Q20 = SKP_SMLAWB( wsse_Q20, SKP_SMULBB( se_Q15, se_Q15 ), pW_Q6[ i ] ); + + /* Compute weighted squared quantization error for index i + 1 */ + se_Q15 = pNLSF_Q15[ i + 1 ] - pNLSF_q_Q15_prev[ i + 1 ]; // range: [ -32767 : 32767 ] + wsse_Q20 = SKP_SMLAWB( wsse_Q20, SKP_SMULBB( se_Q15, se_Q15 ), pW_Q6[ i + 1 ] ); + } + SKP_assert( wsse_Q20 >= 0 ); + + /* Add the fluctuation reduction penalty to the rate distortion error */ + wsse_Q20 = SKP_ADD_POS_SAT32( pRateDist_Q18[ s ], SKP_SMULWB( wsse_Q20, NLSF_mu_fluc_red_Q16 ) ); + + /* Keep index of best survivor */ + if( wsse_Q20 < bestRateDist_Q20 ) { + bestRateDist_Q20 = wsse_Q20; + bestIndex = s; + } + } + } +#endif + + /* Copy best path to output argument */ + SKP_memcpy( NLSFIndices, &pPath_new[ SKP_SMULBB( bestIndex, psNLSF_CB->nStages ) ], psNLSF_CB->nStages * sizeof( SKP_int ) ); + + /* Decode and stabilize the best survivor */ + SKP_Silk_NLSF_MSVQ_decode( pNLSF_Q15, psNLSF_CB, NLSFIndices, LPC_order ); + +#ifdef USE_UNQUANTIZED_LSFS + SKP_memcpy( pNLSF_Q15, NLSF_orig, LPC_order * sizeof( SKP_int ) ); +#endif + +} diff --git a/pkg/silk/csilk/SKP_Silk_NLSF_VQ_rate_distortion_FIX.c b/pkg/silk/csilk/SKP_Silk_NLSF_VQ_rate_distortion_FIX.c new file mode 100644 index 0000000..8b5704d --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_NLSF_VQ_rate_distortion_FIX.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. +***********************************************************************/ + +#include "SKP_Silk_main_FIX.h" + +/* Rate-Distortion calculations for multiple input data vectors */ +void SKP_Silk_NLSF_VQ_rate_distortion_FIX( + SKP_int32 *pRD_Q20, /* O Rate-distortion values [psNLSF_CBS->nVectors*N] */ + const SKP_Silk_NLSF_CBS *psNLSF_CBS, /* I NLSF codebook stage struct */ + const SKP_int *in_Q15, /* I Input vectors to be quantized */ + const SKP_int *w_Q6, /* I Weight vector */ + const SKP_int32 *rate_acc_Q5, /* I Accumulated rates from previous stage */ + const SKP_int mu_Q15, /* 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_int i, n; + SKP_int32 *pRD_vec_Q20; + + /* Compute weighted quantization errors for all input vectors over one codebook stage */ + SKP_Silk_NLSF_VQ_sum_error_FIX( pRD_Q20, in_Q15, w_Q6, psNLSF_CBS->CB_NLSF_Q15, + N, psNLSF_CBS->nVectors, LPC_order ); + + /* Loop over input vectors */ + pRD_vec_Q20 = pRD_Q20; + for( n = 0; n < N; n++ ) { + /* Add rate cost to error for each codebook vector */ + for( i = 0; i < psNLSF_CBS->nVectors; i++ ) { + SKP_assert( rate_acc_Q5[ n ] + psNLSF_CBS->Rates_Q5[ i ] >= 0 ); + SKP_assert( rate_acc_Q5[ n ] + psNLSF_CBS->Rates_Q5[ i ] <= SKP_int16_MAX ); + pRD_vec_Q20[ i ] = SKP_SMLABB( pRD_vec_Q20[ i ], rate_acc_Q5[ n ] + psNLSF_CBS->Rates_Q5[ i ], mu_Q15 ); + SKP_assert( pRD_vec_Q20[ i ] >= 0 ); + } + pRD_vec_Q20 += psNLSF_CBS->nVectors; + } +} diff --git a/pkg/silk/csilk/SKP_Silk_NLSF_VQ_sum_error_FIX.c b/pkg/silk/csilk/SKP_Silk_NLSF_VQ_sum_error_FIX.c new file mode 100644 index 0000000..05d90d0 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_NLSF_VQ_sum_error_FIX.c @@ -0,0 +1,83 @@ +/*********************************************************************** +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_FIX.h" + +#if (!defined(__mips__)) && (EMBEDDED_ARM < 6) + +/* Compute weighted quantization errors for an LPC_order element input vector, over one codebook stage */ +void SKP_Silk_NLSF_VQ_sum_error_FIX( + SKP_int32 *err_Q20, /* O Weighted quantization errors [N*K] */ + const SKP_int *in_Q15, /* I Input vectors to be quantized [N*LPC_order] */ + const SKP_int *w_Q6, /* I Weighting vectors [N*LPC_order] */ + const SKP_int16 *pCB_Q15, /* 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 Number of LPCs */ +) +{ + SKP_int i, n, m; + SKP_int32 diff_Q15, sum_error, Wtmp_Q6; + SKP_int32 Wcpy_Q6[ MAX_LPC_ORDER / 2 ]; + const SKP_int16 *cb_vec_Q15; + + SKP_assert( LPC_order <= 16 ); + SKP_assert( ( LPC_order & 1 ) == 0 ); + + /* Copy to local stack and pack two weights per int32 */ + for( m = 0; m < SKP_RSHIFT( LPC_order, 1 ); m++ ) { + Wcpy_Q6[ m ] = w_Q6[ 2 * m ] | SKP_LSHIFT( ( SKP_int32 )w_Q6[ 2 * m + 1 ], 16 ); + } + + /* Loop over input vectors */ + for( n = 0; n < N; n++ ) { + /* Loop over codebook */ + cb_vec_Q15 = pCB_Q15; + for( i = 0; i < K; i++ ) { + sum_error = 0; + for( m = 0; m < LPC_order; m += 2 ) { + /* Get two weights packed in an int32 */ + Wtmp_Q6 = Wcpy_Q6[ SKP_RSHIFT( m, 1 ) ]; + + /* Compute weighted squared quantization error for index m */ + diff_Q15 = in_Q15[ m ] - *cb_vec_Q15++; // range: [ -32767 : 32767 ] + sum_error = SKP_SMLAWB( sum_error, SKP_SMULBB( diff_Q15, diff_Q15 ), Wtmp_Q6 ); + + /* Compute weighted squared quantization error for index m + 1 */ + diff_Q15 = in_Q15[m + 1] - *cb_vec_Q15++; // range: [ -32767 : 32767 ] + sum_error = SKP_SMLAWT( sum_error, SKP_SMULBB( diff_Q15, diff_Q15 ), Wtmp_Q6 ); + } + SKP_assert( sum_error >= 0 ); + err_Q20[ i ] = sum_error; + } + err_Q20 += K; + in_Q15 += LPC_order; + } +} + +#endif + diff --git a/pkg/silk/csilk/SKP_Silk_NLSF_VQ_weights_laroia.c b/pkg/silk/csilk/SKP_Silk_NLSF_VQ_weights_laroia.c new file mode 100644 index 0000000..71c3f23 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_NLSF_VQ_weights_laroia.c @@ -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. +***********************************************************************/ + +#include "SKP_Silk_SigProc_FIX.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 Q_OUT 6 +#define MIN_NDELTA 3 + +/* 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) */ +) +{ + SKP_int k; + SKP_int32 tmp1_int, tmp2_int; + + /* Check that we are guaranteed to end up within the required range */ + SKP_assert( D > 0 ); + SKP_assert( ( D & 1 ) == 0 ); + + /* First value */ + tmp1_int = SKP_max_int( pNLSF_Q15[ 0 ], MIN_NDELTA ); + tmp1_int = SKP_DIV32_16( 1 << ( 15 + Q_OUT ), tmp1_int ); + tmp2_int = SKP_max_int( pNLSF_Q15[ 1 ] - pNLSF_Q15[ 0 ], MIN_NDELTA ); + tmp2_int = SKP_DIV32_16( 1 << ( 15 + Q_OUT ), tmp2_int ); + pNLSFW_Q6[ 0 ] = (SKP_int)SKP_min_int( tmp1_int + tmp2_int, SKP_int16_MAX ); + SKP_assert( pNLSFW_Q6[ 0 ] > 0 ); + + /* Main loop */ + for( k = 1; k < D - 1; k += 2 ) { + tmp1_int = SKP_max_int( pNLSF_Q15[ k + 1 ] - pNLSF_Q15[ k ], MIN_NDELTA ); + tmp1_int = SKP_DIV32_16( 1 << ( 15 + Q_OUT ), tmp1_int ); + pNLSFW_Q6[ k ] = (SKP_int)SKP_min_int( tmp1_int + tmp2_int, SKP_int16_MAX ); + SKP_assert( pNLSFW_Q6[ k ] > 0 ); + + tmp2_int = SKP_max_int( pNLSF_Q15[ k + 2 ] - pNLSF_Q15[ k + 1 ], MIN_NDELTA ); + tmp2_int = SKP_DIV32_16( 1 << ( 15 + Q_OUT ), tmp2_int ); + pNLSFW_Q6[ k + 1 ] = (SKP_int)SKP_min_int( tmp1_int + tmp2_int, SKP_int16_MAX ); + SKP_assert( pNLSFW_Q6[ k + 1 ] > 0 ); + } + + /* Last value */ + tmp1_int = SKP_max_int( ( 1 << 15 ) - pNLSF_Q15[ D - 1 ], MIN_NDELTA ); + tmp1_int = SKP_DIV32_16( 1 << ( 15 + Q_OUT ), tmp1_int ); + pNLSFW_Q6[ D - 1 ] = (SKP_int)SKP_min_int( tmp1_int + tmp2_int, SKP_int16_MAX ); + SKP_assert( pNLSFW_Q6[ D - 1 ] > 0 ); +} diff --git a/pkg/silk/csilk/SKP_Silk_NLSF_stabilize.c b/pkg/silk/csilk/SKP_Silk_NLSF_stabilize.c new file mode 100644 index 0000000..9fc2f61 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_NSQ.c b/pkg/silk/csilk/SKP_Silk_NSQ.c new file mode 100644 index 0000000..3655cfe --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_NSQ.c @@ -0,0 +1,454 @@ +/*********************************************************************** +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; +#if !defined(_SYSTEM_IS_BIG_ENDIAN) + SKP_int32 a_Q12_tmp[ MAX_LPC_ORDER / 2 ], Atmp; + /* Preload LPC coefficients to array on stack. Gives small performance gain */ + SKP_memcpy( a_Q12_tmp, a_Q12, predictLPCOrder * sizeof( SKP_int16 ) ); +#endif + + 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 */ +#if !defined(_SYSTEM_IS_BIG_ENDIAN) + /* NOTE: the code below loads two int16 values in an int32, and multiplies each using the */ + /* SMLAWB and SMLAWT instructions. On a big-endian CPU the two int16 variables would be */ + /* loaded in reverse order and the code will give the wrong result. In that case swapping */ + /* the SMLAWB and SMLAWT instructions should solve the problem. */ + /* Partially unrolled */ + Atmp = a_Q12_tmp[ 0 ]; /* read two coefficients at once */ + LPC_pred_Q10 = SKP_SMULWB( psLPC_Q14[ 0 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, psLPC_Q14[ -1 ], Atmp ); + Atmp = a_Q12_tmp[ 1 ]; + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -2 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, psLPC_Q14[ -3 ], Atmp ); + Atmp = a_Q12_tmp[ 2 ]; + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -4 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, psLPC_Q14[ -5 ], Atmp ); + Atmp = a_Q12_tmp[ 3 ]; + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -6 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, psLPC_Q14[ -7 ], Atmp ); + Atmp = a_Q12_tmp[ 4 ]; + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -8 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, psLPC_Q14[ -9 ], Atmp ); + for( j = 10; j < predictLPCOrder; j += 2 ) { + Atmp = a_Q12_tmp[ j >> 1 ]; /* read two coefficients at once */ + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -j ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, psLPC_Q14[ -j - 1 ], Atmp ); + } +#else + /* 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 ] ); + } +#endif + /* 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/pkg/silk/csilk/SKP_Silk_NSQ_del_dec.c b/pkg/silk/csilk/SKP_Silk_NSQ_del_dec.c new file mode 100644 index 0000000..16d0b20 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_NSQ_del_dec.c @@ -0,0 +1,733 @@ +/*********************************************************************** +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; +#if !defined(_SYSTEM_IS_BIG_ENDIAN) + SKP_int32 a_Q12_tmp[ MAX_LPC_ORDER / 2 ], Atmp; + + /* Preload LPC coeficients to array on stack. Gives small performance gain */ + SKP_memcpy( a_Q12_tmp, a_Q12, predictLPCOrder * sizeof( SKP_int16 ) ); +#endif + + 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 */ +#if !defined(_SYSTEM_IS_BIG_ENDIAN) + /* Partially unrolled */ + Atmp = a_Q12_tmp[ 0 ]; /* read two coefficients at once */ + LPC_pred_Q10 = SKP_SMULWB( psLPC_Q14[ 0 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, psLPC_Q14[ -1 ], Atmp ); + Atmp = a_Q12_tmp[ 1 ]; + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -2 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, psLPC_Q14[ -3 ], Atmp ); + Atmp = a_Q12_tmp[ 2 ]; + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -4 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, psLPC_Q14[ -5 ], Atmp ); + Atmp = a_Q12_tmp[ 3 ]; + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -6 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, psLPC_Q14[ -7 ], Atmp ); + Atmp = a_Q12_tmp[ 4 ]; + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -8 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, psLPC_Q14[ -9 ], Atmp ); + for( j = 10; j < predictLPCOrder; j += 2 ) { + Atmp = a_Q12_tmp[ j >> 1 ]; /* read two coefficients at once */ + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -j ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, psLPC_Q14[ -j - 1 ], Atmp ); + } +#else + /* 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 ] ); + } +#endif + + /* 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/pkg/silk/csilk/SKP_Silk_PLC.c b/pkg/silk/csilk/SKP_Silk_PLC.c new file mode 100644 index 0000000..8058610 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_PLC.c @@ -0,0 +1,418 @@ +/*********************************************************************** +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; +#if !defined(_SYSTEM_IS_BIG_ENDIAN) + SKP_int32 Atmp; +#endif + 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 */ +#if !defined(_SYSTEM_IS_BIG_ENDIAN) + /* NOTE: the code below loads two int16 values in an int32, and multiplies each using the */ + /* SMLAWB and SMLAWT instructions. On a big-endian CPU the two int16 variables would be */ + /* loaded in reverse order and the code will give the wrong result. In that case swapping */ + /* the SMLAWB and SMLAWT instructions should solve the problem. */ + Atmp = A_Q12_tmp.as_int32[ 0 ]; /* read two coefficients at once */ + LPC_pred_Q10 = SKP_SMULWB( psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 1 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 2 ], Atmp ); + Atmp = A_Q12_tmp.as_int32[ 1 ]; + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 3 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 4 ], Atmp ); + Atmp = A_Q12_tmp.as_int32[ 2 ]; + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 5 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 6 ], Atmp ); + Atmp = A_Q12_tmp.as_int32[ 3 ]; + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 7 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 8 ], Atmp ); + Atmp = A_Q12_tmp.as_int32[ 4 ]; + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 9 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 10 ], Atmp ); + for( j = 10 ; j < psDec->LPC_order ; j+=2 ) { + Atmp = A_Q12_tmp.as_int32[ j / 2 ]; + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 1 - j ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, psDec->sLPC_Q14[ MAX_LPC_ORDER + i - 2 - j ], Atmp ); + } +#else + 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 ] ); + } +#endif + /* 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/pkg/silk/csilk/SKP_Silk_PLC.h b/pkg/silk/csilk/SKP_Silk_PLC.h new file mode 100644 index 0000000..1723943 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_SDK_API.h b/pkg/silk/csilk/SKP_Silk_SDK_API.h new file mode 100644 index 0000000..0e9041b --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_SDK_API.h @@ -0,0 +1,152 @@ +/*********************************************************************** +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_SDK_API_H +#define SKP_SILK_SDK_API_H + +#include "SKP_Silk_control.h" +#include "SKP_Silk_typedef.h" +#include "SKP_Silk_errors.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define SILK_MAX_FRAMES_PER_PACKET 5 + +/* Struct for TOC (Table of Contents) */ +typedef struct { + SKP_int framesInPacket; /* Number of 20 ms frames in packet */ + SKP_int fs_kHz; /* Sampling frequency in packet */ + SKP_int inbandLBRR; /* Does packet contain LBRR information */ + SKP_int corrupt; /* Packet is corrupt */ + SKP_int vadFlags[ SILK_MAX_FRAMES_PER_PACKET ]; /* VAD flag for each frame in packet */ + SKP_int sigtypeFlags[ SILK_MAX_FRAMES_PER_PACKET ]; /* Signal type for each frame in packet */ +} SKP_Silk_TOC_struct; + +/****************************************/ +/* Encoder functions */ +/****************************************/ + +/***********************************************/ +/* Get size in bytes of the Silk encoder state */ +/***********************************************/ +SKP_int SKP_Silk_SDK_Get_Encoder_Size( + SKP_int32 *encSizeBytes /* O: Number of bytes in SILK encoder state */ +); + +/*************************/ +/* Init or reset encoder */ +/*************************/ +SKP_int SKP_Silk_SDK_InitEncoder( + void *encState, /* I/O: State */ + SKP_SILK_SDK_EncControlStruct *encStatus /* O: Encoder Status */ +); + +/***************************************/ +/* Read control structure from encoder */ +/***************************************/ +SKP_int SKP_Silk_SDK_QueryEncoder( + const void *encState, /* I: State */ + SKP_SILK_SDK_EncControlStruct *encStatus /* O: Encoder Status */ +); + +/**************************/ +/* Encode frame with Silk */ +/**************************/ +SKP_int SKP_Silk_SDK_Encode( + void *encState, /* I/O: State */ + const SKP_SILK_SDK_EncControlStruct *encControl, /* I: Control status */ + 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) */ +); + +/****************************************/ +/* Decoder functions */ +/****************************************/ + +/***********************************************/ +/* Get size in bytes of the Silk decoder state */ +/***********************************************/ +SKP_int SKP_Silk_SDK_Get_Decoder_Size( + SKP_int32 *decSizeBytes /* O: Number of bytes in SILK decoder state */ +); + +/*************************/ +/* Init or Reset decoder */ +/*************************/ +SKP_int SKP_Silk_SDK_InitDecoder( + void *decState /* I/O: State */ +); + +/******************/ +/* 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) */ +); + +/***************************************************************/ +/* Find Low Bit Rate Redundancy (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 */ +); + +/**************************************/ +/* Get table of contents 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: Table of contents */ +); + +/**************************/ +/* Get the version number */ +/**************************/ +/* Return a pointer to string specifying the version */ +const char *SKP_Silk_SDK_get_version(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/pkg/silk/csilk/SKP_Silk_SigProc_FIX.h b/pkg/silk/csilk/SKP_Silk_SigProc_FIX.h new file mode 100644 index 0000000..d53cb40 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_SigProc_FIX.h @@ -0,0 +1,663 @@ +/*********************************************************************** +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" + +#ifndef NO_ASM +# if defined (__ARM_ARCH_4__) || defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_5__) || defined (__ARM_ARCH_5T__) +# define EMBEDDED_ARM 4 +# define EMBEDDED_ARMv4 +# include "SKP_Silk_macros_arm.h" +# elif defined (__ARM_ARCH_5TE__) || defined (__ARM_ARCH_5TEJ__) +# define EMBEDDED_ARM 5 +# define EMBEDDED_ARMv5 +# include "SKP_Silk_macros_arm.h" +# elif defined (__ARM_ARCH_6__) ||defined (__ARM_ARCH_6J__) || defined (__ARM_ARCH_6Z__) || defined (__ARM_ARCH_6K__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) +# define EMBEDDED_ARM 6 +# define EMBEDDED_ARMv6 +# include "SKP_Silk_macros_arm.h" +# elif defined (__ARM_ARCH_7A__) && defined (__ARM_NEON__) +# define EMBEDDED_ARM 7 +# define EMBEDDED_ARMv6 +# include "SKP_Silk_macros_arm.h" +# elif defined (__ARM_ARCH_7A__) +# define EMBEDDED_ARM 6 +# define EMBEDDED_ARMv6 +# include "SKP_Silk_macros_arm.h" +# else +# include "SKP_Silk_macros.h" +# endif +#else +# define EMBEDDED_ARM 0 +# include "SKP_Silk_macros.h" +#endif + + + +/********************************************************************/ +/* 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/pkg/silk/csilk/SKP_Silk_VAD.c b/pkg/silk/csilk/SKP_Silk_VAD.c new file mode 100644 index 0000000..35a5a9d --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_VQ_nearest_neighbor_FIX.c b/pkg/silk/csilk/SKP_Silk_VQ_nearest_neighbor_FIX.c new file mode 100644 index 0000000..74a2653 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_VQ_nearest_neighbor_FIX.c @@ -0,0 +1,159 @@ +/*********************************************************************** +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_FIX.h" + +/* Entropy constrained MATRIX-weighted VQ, hard-coded to 5-element vectors, for a single input data vector */ +void SKP_Silk_VQ_WMat_EC_FIX( + SKP_int *ind, /* O index of best codebook vector */ + SKP_int32 *rate_dist_Q14, /* O best weighted quantization error + mu * rate*/ + const SKP_int16 *in_Q14, /* I input vector to be quantized */ + const SKP_int32 *W_Q18, /* I weighting matrix */ + const SKP_int16 *cb_Q14, /* I codebook */ + const SKP_int16 *cl_Q6, /* I code length for each codebook vector */ + const SKP_int mu_Q8, /* I tradeoff between weighted error and rate */ + SKP_int L /* I number of vectors in codebook */ +) +{ + SKP_int k; + const SKP_int16 *cb_row_Q14; +#if !defined(_SYSTEM_IS_BIG_ENDIAN) + SKP_int32 sum1_Q14, sum2_Q16, diff_Q14_01, diff_Q14_23, diff_Q14_4; +#else + SKP_int16 diff_Q14[ 5 ]; + SKP_int32 sum1_Q14, sum2_Q16; +#endif + + /* Loop over codebook */ + *rate_dist_Q14 = SKP_int32_MAX; + cb_row_Q14 = cb_Q14; + for( k = 0; k < L; k++ ) { +#if !defined(_SYSTEM_IS_BIG_ENDIAN) + /* Pack pairs of int16 values per int32 */ + diff_Q14_01 = ( SKP_uint16 )( in_Q14[ 0 ] - cb_row_Q14[ 0 ] ) | SKP_LSHIFT( ( SKP_int32 )in_Q14[ 1 ] - cb_row_Q14[ 1 ], 16 ); + diff_Q14_23 = ( SKP_uint16 )( in_Q14[ 2 ] - cb_row_Q14[ 2 ] ) | SKP_LSHIFT( ( SKP_int32 )in_Q14[ 3 ] - cb_row_Q14[ 3 ], 16 ); + diff_Q14_4 = in_Q14[ 4 ] - cb_row_Q14[ 4 ]; +#else + diff_Q14[ 0 ] = in_Q14[ 0 ] - cb_row_Q14[ 0 ]; + diff_Q14[ 1 ] = in_Q14[ 1 ] - cb_row_Q14[ 1 ]; + diff_Q14[ 2 ] = in_Q14[ 2 ] - cb_row_Q14[ 2 ]; + diff_Q14[ 3 ] = in_Q14[ 3 ] - cb_row_Q14[ 3 ]; + diff_Q14[ 4 ] = in_Q14[ 4 ] - cb_row_Q14[ 4 ]; +#endif + + /* Weighted rate */ + sum1_Q14 = SKP_SMULBB( mu_Q8, cl_Q6[ k ] ); + + SKP_assert( sum1_Q14 >= 0 ); + +#if !defined(_SYSTEM_IS_BIG_ENDIAN) + /* Add weighted quantization error, assuming W_Q18 is symmetric */ + /* NOTE: the code below loads two int16 values as one int32, and multiplies each using the */ + /* SMLAWB and SMLAWT instructions. On a big-endian CPU the two int16 variables would be */ + /* loaded in reverse order and the code will give the wrong result. In that case swapping */ + /* the SMLAWB and SMLAWT instructions should solve the problem. */ + /* first row of W_Q18 */ + sum2_Q16 = SKP_SMULWT( W_Q18[ 1 ], diff_Q14_01 ); + sum2_Q16 = SKP_SMLAWB( sum2_Q16, W_Q18[ 2 ], diff_Q14_23 ); + sum2_Q16 = SKP_SMLAWT( sum2_Q16, W_Q18[ 3 ], diff_Q14_23 ); + sum2_Q16 = SKP_SMLAWB( sum2_Q16, W_Q18[ 4 ], diff_Q14_4 ); + sum2_Q16 = SKP_LSHIFT( sum2_Q16, 1 ); + sum2_Q16 = SKP_SMLAWB( sum2_Q16, W_Q18[ 0 ], diff_Q14_01 ); + sum1_Q14 = SKP_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14_01 ); + + /* second row of W_Q18 */ + sum2_Q16 = SKP_SMULWB( W_Q18[ 7 ], diff_Q14_23 ); + sum2_Q16 = SKP_SMLAWT( sum2_Q16, W_Q18[ 8 ], diff_Q14_23 ); + sum2_Q16 = SKP_SMLAWB( sum2_Q16, W_Q18[ 9 ], diff_Q14_4 ); + sum2_Q16 = SKP_LSHIFT( sum2_Q16, 1 ); + sum2_Q16 = SKP_SMLAWT( sum2_Q16, W_Q18[ 6 ], diff_Q14_01 ); + sum1_Q14 = SKP_SMLAWT( sum1_Q14, sum2_Q16, diff_Q14_01 ); + + /* third row of W_Q18 */ + sum2_Q16 = SKP_SMULWT( W_Q18[ 13 ], diff_Q14_23 ); + sum2_Q16 = SKP_SMLAWB( sum2_Q16, W_Q18[ 14 ], diff_Q14_4 ); + sum2_Q16 = SKP_LSHIFT( sum2_Q16, 1 ); + sum2_Q16 = SKP_SMLAWB( sum2_Q16, W_Q18[ 12 ], diff_Q14_23 ); + sum1_Q14 = SKP_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14_23 ); + + /* fourth row of W_Q18 */ + sum2_Q16 = SKP_SMULWB( W_Q18[ 19 ], diff_Q14_4 ); + sum2_Q16 = SKP_LSHIFT( sum2_Q16, 1 ); + sum2_Q16 = SKP_SMLAWT( sum2_Q16, W_Q18[ 18 ], diff_Q14_23 ); + sum1_Q14 = SKP_SMLAWT( sum1_Q14, sum2_Q16, diff_Q14_23 ); + + /* last row of W_Q18 */ + sum2_Q16 = SKP_SMULWB( W_Q18[ 24 ], diff_Q14_4 ); + sum1_Q14 = SKP_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14_4 ); +#else + /* first row of W_Q18 */ + sum2_Q16 = SKP_SMULWB( W_Q18[ 1 ], diff_Q14[ 1 ] ); + sum2_Q16 = SKP_SMLAWB( sum2_Q16, W_Q18[ 2 ], diff_Q14[ 2 ] ); + sum2_Q16 = SKP_SMLAWB( sum2_Q16, W_Q18[ 3 ], diff_Q14[ 3 ] ); + sum2_Q16 = SKP_SMLAWB( sum2_Q16, W_Q18[ 4 ], diff_Q14[ 4 ] ); + sum2_Q16 = SKP_LSHIFT( sum2_Q16, 1 ); + sum2_Q16 = SKP_SMLAWB( sum2_Q16, W_Q18[ 0 ], diff_Q14[ 0 ] ); + sum1_Q14 = SKP_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 0 ] ); + + /* second row of W_Q18 */ + sum2_Q16 = SKP_SMULWB( W_Q18[ 7 ], diff_Q14[ 2 ] ); + sum2_Q16 = SKP_SMLAWB( sum2_Q16, W_Q18[ 8 ], diff_Q14[ 3 ] ); + sum2_Q16 = SKP_SMLAWB( sum2_Q16, W_Q18[ 9 ], diff_Q14[ 4 ] ); + sum2_Q16 = SKP_LSHIFT( sum2_Q16, 1 ); + sum2_Q16 = SKP_SMLAWB( sum2_Q16, W_Q18[ 6 ], diff_Q14[ 1 ] ); + sum1_Q14 = SKP_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 1 ] ); + + /* third row of W_Q18 */ + sum2_Q16 = SKP_SMULWB( W_Q18[ 13 ], diff_Q14[ 3 ] ); + sum2_Q16 = SKP_SMLAWB( sum2_Q16, W_Q18[ 14 ], diff_Q14[ 4 ] ); + sum2_Q16 = SKP_LSHIFT( sum2_Q16, 1 ); + sum2_Q16 = SKP_SMLAWB( sum2_Q16, W_Q18[ 12 ], diff_Q14[ 2 ] ); + sum1_Q14 = SKP_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 2 ] ); + + /* fourth row of W_Q18 */ + sum2_Q16 = SKP_SMULWB( W_Q18[ 19 ], diff_Q14[ 4 ] ); + sum2_Q16 = SKP_LSHIFT( sum2_Q16, 1 ); + sum2_Q16 = SKP_SMLAWB( sum2_Q16, W_Q18[ 18 ], diff_Q14[ 3 ] ); + sum1_Q14 = SKP_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 3 ] ); + + /* last row of W_Q18 */ + sum2_Q16 = SKP_SMULWB( W_Q18[ 24 ], diff_Q14[ 4 ] ); + sum1_Q14 = SKP_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 4 ] ); +#endif + + SKP_assert( sum1_Q14 >= 0 ); + + /* find best */ + if( sum1_Q14 < *rate_dist_Q14 ) { + *rate_dist_Q14 = sum1_Q14; + *ind = k; + } + + /* Go to next cbk vector */ + cb_row_Q14 += LTP_ORDER; + } +} diff --git a/pkg/silk/csilk/SKP_Silk_ana_filt_bank_1.c b/pkg/silk/csilk/SKP_Silk_ana_filt_bank_1.c new file mode 100644 index 0000000..206f3b5 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_ana_filt_bank_1.c @@ -0,0 +1,82 @@ +/*********************************************************************** +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" + +#if EMBEDDED_ARM<5 +/* 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 ] = { (SKP_int16) (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 ) ); + } +} +#endif diff --git a/pkg/silk/csilk/SKP_Silk_apply_sine_window.c b/pkg/silk/csilk/SKP_Silk_apply_sine_window.c new file mode 100644 index 0000000..b7706d7 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_apply_sine_window.c @@ -0,0 +1,120 @@ +/*********************************************************************** +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" + +/* 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. */ +/* Window length must be between 16 and 120 (incl) and a multiple of 4. */ + +/* Matlab code for table: + for k=16:9*4:16+2*9*4, fprintf(' %7.d,', -round(65536*pi ./ (k:4:k+8*4))); fprintf('\n'); end +*/ +static SKP_int16 freq_table_Q16[ 27 ] = { + 12111, 9804, 8235, 7100, 6239, 5565, 5022, 4575, 4202, + 3885, 3612, 3375, 3167, 2984, 2820, 2674, 2542, 2422, + 2313, 2214, 2123, 2038, 1961, 1889, 1822, 1760, 1702, +}; + +//#if EMBEDDED_ARM<6 +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 */ +) +{ + SKP_int k, f_Q16, c_Q16; + SKP_int32 S0_Q16, S1_Q16; +#if !defined(_SYSTEM_IS_BIG_ENDIAN) + SKP_int32 px32; +#endif + SKP_assert( win_type == 1 || win_type == 2 ); + + /* Length must be in a range from 16 to 120 and a multiple of 4 */ + SKP_assert( length >= 16 && length <= 120 ); + SKP_assert( ( length & 3 ) == 0 ); + + /* Input pointer must be 4-byte aligned */ + SKP_assert( ( ( SKP_int64 )( ( SKP_int8* )px - ( SKP_int8* )0 ) & 3 ) == 0 ); + + /* Frequency */ + k = ( length >> 2 ) - 4; + SKP_assert( k >= 0 && k <= 26 ); + f_Q16 = (SKP_int)freq_table_Q16[ k ]; + + /* Factor used for cosine approximation */ + c_Q16 = SKP_SMULWB( f_Q16, -f_Q16 ); + SKP_assert( c_Q16 >= -32768 ); + + /* initialize state */ + if( win_type == 1 ) { + /* start from 0 */ + S0_Q16 = 0; + /* approximation of sin(f) */ + S1_Q16 = f_Q16 + SKP_RSHIFT( length, 3 ); + } else { + /* start from 1 */ + S0_Q16 = ( 1 << 16 ); + /* approximation of cos(f) */ + S1_Q16 = ( 1 << 16 ) + SKP_RSHIFT( c_Q16, 1 ) + SKP_RSHIFT( length, 4 ); + } + + /* Uses the recursive equation: sin(n*f) = 2 * cos(f) * sin((n-1)*f) - sin((n-2)*f) */ + /* 4 samples at a time */ +#if !defined(_SYSTEM_IS_BIG_ENDIAN) + for( k = 0; k < length; k += 4 ) { + px32 = *( (SKP_int32 *)&px[ k ] ); /* load two values at once */ + px_win[ k ] = (SKP_int16)SKP_SMULWB( SKP_RSHIFT( S0_Q16 + S1_Q16, 1 ), px32 ); + px_win[ k + 1 ] = (SKP_int16)SKP_SMULWT( S1_Q16, px32 ); + S0_Q16 = SKP_SMULWB( S1_Q16, c_Q16 ) + SKP_LSHIFT( S1_Q16, 1 ) - S0_Q16 + 1; + S0_Q16 = SKP_min( S0_Q16, ( 1 << 16 ) ); + + px32 = *( (SKP_int32 *)&px[k + 2] ); /* load two values at once */ + px_win[ k + 2 ] = (SKP_int16)SKP_SMULWB( SKP_RSHIFT( S0_Q16 + S1_Q16, 1 ), px32 ); + px_win[ k + 3 ] = (SKP_int16)SKP_SMULWT( S0_Q16, px32 ); + S1_Q16 = SKP_SMULWB( S0_Q16, c_Q16 ) + SKP_LSHIFT( S0_Q16, 1 ) - S1_Q16; + S1_Q16 = SKP_min( S1_Q16, ( 1 << 16 ) ); + } +#else + for( k = 0; k < length; k += 4 ) { + px_win[ k ] = (SKP_int16)SKP_SMULWB( SKP_RSHIFT( S0_Q16 + S1_Q16, 1 ), px[ k ] ); + px_win[ k + 1 ] = (SKP_int16)SKP_SMULWB( S1_Q16, px[ k + 1] ); + S0_Q16 = SKP_SMULWB( S1_Q16, c_Q16 ) + SKP_LSHIFT( S1_Q16, 1 ) - S0_Q16 + 1; + S0_Q16 = SKP_min( S0_Q16, ( 1 << 16 ) ); + + px_win[ k + 2 ] = (SKP_int16)SKP_SMULWB( SKP_RSHIFT( S0_Q16 + S1_Q16, 1 ), px[ k + 2] ); + px_win[ k + 3 ] = (SKP_int16)SKP_SMULWB( S0_Q16, px[ k + 3 ] ); + S1_Q16 = SKP_SMULWB( S0_Q16, c_Q16 ) + SKP_LSHIFT( S0_Q16, 1 ) - S1_Q16; + S1_Q16 = SKP_min( S1_Q16, ( 1 << 16 ) ); + } +#endif +} +//#endif diff --git a/pkg/silk/csilk/SKP_Silk_array_maxabs.c b/pkg/silk/csilk/SKP_Silk_array_maxabs.c new file mode 100644 index 0000000..0d6be63 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_array_maxabs.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. +***********************************************************************/ + +/* * + * SKP_Silk_int16_array_maxabs.c * + * * + * Function that returns the maximum absolut value of * + * the input vector * + * * + * Copyright 2006 (c), Skype Limited * + * Date: 060221 * + * */ +#include "SKP_Silk_SigProc_FIX.h" + +/* Function that returns the maximum absolut value of the input vector */ +#if (EMBEDDED_ARM<4) +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 */ +) +{ + SKP_int32 max = 0, i, lvl = 0, ind; + if( len == 0 ) return 0; + + ind = len - 1; + max = SKP_SMULBB( vec[ ind ], vec[ ind ] ); + for( i = len - 2; i >= 0; i-- ) { + lvl = SKP_SMULBB( vec[ i ], vec[ i ] ); + if( lvl > max ) { + max = lvl; + ind = i; + } + } + + /* Do not return 32768, as it will not fit in an int16 so may lead to problems later on */ + if( max >= 1073676289 ) { // (2^15-1)^2 = 1073676289 + return( SKP_int16_MAX ); + } else { + if( vec[ ind ] < 0 ) { + return( -vec[ ind ] ); + } else { + return( vec[ ind ] ); + } + } +} +#endif diff --git a/pkg/silk/csilk/SKP_Silk_autocorr.c b/pkg/silk/csilk/SKP_Silk_autocorr.c new file mode 100644 index 0000000..39ca5ab --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_autocorr.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_autocorr.c * + * * + * Calculates the autocorrelation * + * The result has 29 non-zero bits for the first correlation, to leave * + * some room for adding white noise fractions etc. * + * * + * Copyright 2008 (c), Skype Limited * + * */ +#include "SKP_Silk_SigProc_FIX.h" + +/* 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 */ +) +{ + SKP_int i, lz, nRightShifts, corrCount; + SKP_int64 corr64; + + corrCount = SKP_min_int( inputDataSize, correlationCount ); + + /* compute energy (zero-lag correlation) */ + corr64 = SKP_Silk_inner_prod16_aligned_64( inputData, inputData, inputDataSize ); + + /* deal with all-zero input data */ + corr64 += 1; + + /* number of leading zeros */ + lz = SKP_Silk_CLZ64( corr64 ); + + /* scaling: number of right shifts applied to correlations */ + nRightShifts = 35 - lz; + *scale = nRightShifts; + + if( nRightShifts <= 0 ) { + results[ 0 ] = SKP_LSHIFT( (SKP_int32)SKP_CHECK_FIT32( corr64 ), -nRightShifts ); + + /* compute remaining correlations based on int32 inner product */ + for( i = 1; i < corrCount; i++ ) { + results[ i ] = SKP_LSHIFT( SKP_Silk_inner_prod_aligned( inputData, inputData + i, inputDataSize - i ), -nRightShifts ); + } + } else { + results[ 0 ] = (SKP_int32)SKP_CHECK_FIT32( SKP_RSHIFT64( corr64, nRightShifts ) ); + + /* compute remaining correlations based on int64 inner product */ + for( i = 1; i < corrCount; i++ ) { + results[ i ] = (SKP_int32)SKP_CHECK_FIT32( SKP_RSHIFT64( SKP_Silk_inner_prod16_aligned_64( inputData, inputData + i, inputDataSize - i ), nRightShifts ) ); + } + } +} diff --git a/pkg/silk/csilk/SKP_Silk_biquad.c b/pkg/silk/csilk/SKP_Silk_biquad.c new file mode 100644 index 0000000..f98de55 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_biquad_alt.c b/pkg/silk/csilk/SKP_Silk_biquad_alt.c new file mode 100644 index 0000000..90c27ac --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_burg_modified.c b/pkg/silk/csilk/SKP_Silk_burg_modified.c new file mode 100644 index 0000000..8708b8b --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_burg_modified.c @@ -0,0 +1,229 @@ +/*********************************************************************** +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: 100105 * + */ + +#include "SKP_Silk_SigProc_FIX.h" + +#define MAX_FRAME_SIZE 544 // subfr_length * nb_subfr = ( 0.005 * 24000 + 16 ) * 4 = 544 +#define MAX_NB_SUBFR 4 + +#undef QA +#define QA 25 +#define N_BITS_HEAD_ROOM 2 +#define MIN_RSHIFTS -16 +#define MAX_RSHIFTS (32 - QA) + +/* Compute reflection coefficients from input signal */ +void SKP_Silk_burg_modified( + SKP_int32 *res_nrg, /* O residual energy */ + SKP_int *res_nrg_Q, /* 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 */ +) +{ + SKP_int k, n, s, lz, rshifts, rshifts_extra; + SKP_int32 C0, num, nrg, rc_Q31, Atmp_QA, Atmp1, tmp1, tmp2, x1, x2; + const SKP_int16 *x_ptr; + + SKP_int32 C_first_row[ SKP_Silk_MAX_ORDER_LPC ]; + SKP_int32 C_last_row[ SKP_Silk_MAX_ORDER_LPC ]; + SKP_int32 Af_QA[ SKP_Silk_MAX_ORDER_LPC ]; + + SKP_int32 CAf[ SKP_Silk_MAX_ORDER_LPC + 1 ]; + SKP_int32 CAb[ SKP_Silk_MAX_ORDER_LPC + 1 ]; + + SKP_assert( subfr_length * nb_subfr <= MAX_FRAME_SIZE ); + SKP_assert( nb_subfr <= MAX_NB_SUBFR ); + + + /* Compute autocorrelations, added over subframes */ + SKP_Silk_sum_sqr_shift( &C0, &rshifts, x, nb_subfr * subfr_length ); + if( rshifts > MAX_RSHIFTS ) { + C0 = SKP_LSHIFT32( C0, rshifts - MAX_RSHIFTS ); + SKP_assert( C0 > 0 ); + rshifts = MAX_RSHIFTS; + } else { + lz = SKP_Silk_CLZ32( C0 ) - 1; + rshifts_extra = N_BITS_HEAD_ROOM - lz; + if( rshifts_extra > 0 ) { + rshifts_extra = SKP_min( rshifts_extra, MAX_RSHIFTS - rshifts ); + C0 = SKP_RSHIFT32( C0, rshifts_extra ); + } else { + rshifts_extra = SKP_max( rshifts_extra, MIN_RSHIFTS - rshifts ); + C0 = SKP_LSHIFT32( C0, -rshifts_extra ); + } + rshifts += rshifts_extra; + } + SKP_memset( C_first_row, 0, SKP_Silk_MAX_ORDER_LPC * sizeof( SKP_int32 ) ); + if( rshifts > 0 ) { + 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_int32)SKP_RSHIFT64( + SKP_Silk_inner_prod16_aligned_64( x_ptr, x_ptr + n, subfr_length - n ), rshifts ); + } + } + } else { + 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_LSHIFT32( + SKP_Silk_inner_prod_aligned( x_ptr, x_ptr + n, subfr_length - n ), -rshifts ); + } + } + } + SKP_memcpy( C_last_row, C_first_row, SKP_Silk_MAX_ORDER_LPC * sizeof( SKP_int32 ) ); + + /* Initialize */ + CAb[ 0 ] = CAf[ 0 ] = C0 + SKP_SMMUL( WhiteNoiseFrac_Q32, C0 ) + 1; // Q(-rshifts) + + 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) */ + if( rshifts > -2 ) { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + x1 = -SKP_LSHIFT32( (SKP_int32)x_ptr[ n ], 16 - rshifts ); // Q(16-rshifts) + x2 = -SKP_LSHIFT32( (SKP_int32)x_ptr[ subfr_length - n - 1 ], 16 - rshifts ); // Q(16-rshifts) + tmp1 = SKP_LSHIFT32( (SKP_int32)x_ptr[ n ], QA - 16 ); // Q(QA-16) + tmp2 = SKP_LSHIFT32( (SKP_int32)x_ptr[ subfr_length - n - 1 ], QA - 16 ); // Q(QA-16) + for( k = 0; k < n; k++ ) { + C_first_row[ k ] = SKP_SMLAWB( C_first_row[ k ], x1, x_ptr[ n - k - 1 ] ); // Q( -rshifts ) + C_last_row[ k ] = SKP_SMLAWB( C_last_row[ k ], x2, x_ptr[ subfr_length - n + k ] ); // Q( -rshifts ) + Atmp_QA = Af_QA[ k ]; + tmp1 = SKP_SMLAWB( tmp1, Atmp_QA, x_ptr[ n - k - 1 ] ); // Q(QA-16) + tmp2 = SKP_SMLAWB( tmp2, Atmp_QA, x_ptr[ subfr_length - n + k ] ); // Q(QA-16) + } + tmp1 = SKP_LSHIFT32( -tmp1, 32 - QA - rshifts ); // Q(16-rshifts) + tmp2 = SKP_LSHIFT32( -tmp2, 32 - QA - rshifts ); // Q(16-rshifts) + for( k = 0; k <= n; k++ ) { + CAf[ k ] = SKP_SMLAWB( CAf[ k ], tmp1, x_ptr[ n - k ] ); // Q( -rshift ) + CAb[ k ] = SKP_SMLAWB( CAb[ k ], tmp2, x_ptr[ subfr_length - n + k - 1 ] ); // Q( -rshift ) + } + } + } else { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + x1 = -SKP_LSHIFT32( (SKP_int32)x_ptr[ n ], -rshifts ); // Q( -rshifts ) + x2 = -SKP_LSHIFT32( (SKP_int32)x_ptr[ subfr_length - n - 1 ], -rshifts ); // Q( -rshifts ) + tmp1 = SKP_LSHIFT32( (SKP_int32)x_ptr[ n ], 17 ); // Q17 + tmp2 = SKP_LSHIFT32( (SKP_int32)x_ptr[ subfr_length - n - 1 ], 17 ); // Q17 + for( k = 0; k < n; k++ ) { + C_first_row[ k ] = SKP_MLA( C_first_row[ k ], x1, x_ptr[ n - k - 1 ] ); // Q( -rshifts ) + C_last_row[ k ] = SKP_MLA( C_last_row[ k ], x2, x_ptr[ subfr_length - n + k ] ); // Q( -rshifts ) + Atmp1 = SKP_RSHIFT_ROUND( Af_QA[ k ], QA - 17 ); // Q17 + tmp1 = SKP_MLA( tmp1, x_ptr[ n - k - 1 ], Atmp1 ); // Q17 + tmp2 = SKP_MLA( tmp2, x_ptr[ subfr_length - n + k ], Atmp1 ); // Q17 + } + tmp1 = -tmp1; // Q17 + tmp2 = -tmp2; // Q17 + for( k = 0; k <= n; k++ ) { + CAf[ k ] = SKP_SMLAWW( CAf[ k ], tmp1, + SKP_LSHIFT32( (SKP_int32)x_ptr[ n - k ], -rshifts - 1 ) ); // Q( -rshift ) + CAb[ k ] = SKP_SMLAWW( CAb[ k ], tmp2, + SKP_LSHIFT32( (SKP_int32)x_ptr[ subfr_length - n + k - 1 ], -rshifts - 1 ) );// Q( -rshift ) + } + } + } + + /* Calculate nominator and denominator for the next order reflection (parcor) coefficient */ + tmp1 = C_first_row[ n ]; // Q( -rshifts ) + tmp2 = C_last_row[ n ]; // Q( -rshifts ) + num = 0; // Q( -rshifts ) + nrg = SKP_ADD32( CAb[ 0 ], CAf[ 0 ] ); // Q( 1-rshifts ) + for( k = 0; k < n; k++ ) { + Atmp_QA = Af_QA[ k ]; + lz = SKP_Silk_CLZ32( SKP_abs( Atmp_QA ) ) - 1; + lz = SKP_min( 32 - QA, lz ); + Atmp1 = SKP_LSHIFT32( Atmp_QA, lz ); // Q( QA + lz ) + + tmp1 = SKP_ADD_LSHIFT32( tmp1, SKP_SMMUL( C_last_row[ n - k - 1 ], Atmp1 ), 32 - QA - lz ); // Q( -rshifts ) + tmp2 = SKP_ADD_LSHIFT32( tmp2, SKP_SMMUL( C_first_row[ n - k - 1 ], Atmp1 ), 32 - QA - lz ); // Q( -rshifts ) + num = SKP_ADD_LSHIFT32( num, SKP_SMMUL( CAb[ n - k ], Atmp1 ), 32 - QA - lz ); // Q( -rshifts ) + nrg = SKP_ADD_LSHIFT32( nrg, SKP_SMMUL( SKP_ADD32( CAb[ k + 1 ], CAf[ k + 1 ] ), + Atmp1 ), 32 - QA - lz ); // Q( 1-rshifts ) + } + CAf[ n + 1 ] = tmp1; // Q( -rshifts ) + CAb[ n + 1 ] = tmp2; // Q( -rshifts ) + num = SKP_ADD32( num, tmp2 ); // Q( -rshifts ) + num = SKP_LSHIFT32( -num, 1 ); // Q( 1-rshifts ) + + /* Calculate the next order reflection (parcor) coefficient */ + if( SKP_abs( num ) < nrg ) { + rc_Q31 = SKP_DIV32_varQ( num, nrg, 31 ); + } else { + /* Negative energy or ratio too high; set remaining coefficients to zero and exit loop */ + SKP_memset( &Af_QA[ n ], 0, ( D - n ) * sizeof( SKP_int32 ) ); + SKP_assert( 0 ); + break; + } + + /* Update the AR coefficients */ + for( k = 0; k < (n + 1) >> 1; k++ ) { + tmp1 = Af_QA[ k ]; // QA + tmp2 = Af_QA[ n - k - 1 ]; // QA + Af_QA[ k ] = SKP_ADD_LSHIFT32( tmp1, SKP_SMMUL( tmp2, rc_Q31 ), 1 ); // QA + Af_QA[ n - k - 1 ] = SKP_ADD_LSHIFT32( tmp2, SKP_SMMUL( tmp1, rc_Q31 ), 1 ); // QA + } + Af_QA[ n ] = SKP_RSHIFT32( rc_Q31, 31 - QA ); // QA + + /* Update C * Af and C * Ab */ + for( k = 0; k <= n + 1; k++ ) { + tmp1 = CAf[ k ]; // Q( -rshifts ) + tmp2 = CAb[ n - k + 1 ]; // Q( -rshifts ) + CAf[ k ] = SKP_ADD_LSHIFT32( tmp1, SKP_SMMUL( tmp2, rc_Q31 ), 1 ); // Q( -rshifts ) + CAb[ n - k + 1 ] = SKP_ADD_LSHIFT32( tmp2, SKP_SMMUL( tmp1, rc_Q31 ), 1 ); // Q( -rshifts ) + } + } + + /* Return residual energy */ + nrg = CAf[ 0 ]; // Q( -rshifts ) + tmp1 = 1 << 16; // Q16 + for( k = 0; k < D; k++ ) { + Atmp1 = SKP_RSHIFT_ROUND( Af_QA[ k ], QA - 16 ); // Q16 + nrg = SKP_SMLAWW( nrg, CAf[ k + 1 ], Atmp1 ); // Q( -rshifts ) + tmp1 = SKP_SMLAWW( tmp1, Atmp1, Atmp1 ); // Q16 + A_Q16[ k ] = -Atmp1; + } + *res_nrg = SKP_SMLAWW( nrg, SKP_SMMUL( WhiteNoiseFrac_Q32, C0 ), -tmp1 ); // Q( -rshifts ) + *res_nrg_Q = -rshifts; +} diff --git a/pkg/silk/csilk/SKP_Silk_bwexpander.c b/pkg/silk/csilk/SKP_Silk_bwexpander.c new file mode 100644 index 0000000..6affb6b --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_bwexpander_32.c b/pkg/silk/csilk/SKP_Silk_bwexpander_32.c new file mode 100644 index 0000000..0a83869 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_code_signs.c b/pkg/silk/csilk/SKP_Silk_code_signs.c new file mode 100644 index 0000000..3149f4a --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_common_pitch_est_defines.h b/pkg/silk/csilk/SKP_Silk_common_pitch_est_defines.h new file mode 100644 index 0000000..7ca23d3 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_control.h b/pkg/silk/csilk/SKP_Silk_control.h new file mode 100644 index 0000000..ef0eac2 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_control.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. +***********************************************************************/ + +#ifndef SKP_SILK_CONTROL_H +#define SKP_SILK_CONTROL_H + +#include "SKP_Silk_typedef.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/***********************************************/ +/* Structure for controlling encoder operation */ +/***********************************************/ +typedef struct { + /* I: Input signal sampling rate in Hertz; 8000/12000/16000/24000 */ + SKP_int32 API_sampleRate; + + /* I: Maximum internal sampling rate in Hertz; 8000/12000/16000/24000 */ + SKP_int32 maxInternalSampleRate; + + /* I: Number of samples per packet; must be equivalent of 20, 40, 60, 80 or 100 ms */ + SKP_int packetSize; + + /* I: Bitrate during active speech in bits/second; internally limited */ + SKP_int32 bitRate; + + /* I: Uplink packet loss in percent (0-100) */ + SKP_int packetLossPercentage; + + /* I: Complexity mode; 0 is lowest; 1 is medium and 2 is highest complexity */ + SKP_int complexity; + + /* I: Flag to enable in-band Forward Error Correction (FEC); 0/1 */ + SKP_int useInBandFEC; + + /* I: Flag to enable discontinuous transmission (DTX); 0/1 */ + SKP_int useDTX; +} SKP_SILK_SDK_EncControlStruct; + +/**************************************************************************/ +/* Structure for controlling decoder operation and reading decoder status */ +/**************************************************************************/ +typedef struct { + /* I: Output signal sampling rate in Hertz; 8000/12000/16000/24000 */ + SKP_int32 API_sampleRate; + + /* O: Number of samples per frame */ + SKP_int frameSize; + + /* O: Frames per packet 1, 2, 3, 4, 5 */ + SKP_int framesPerPacket; + + /* O: Flag to indicate that the decoder has remaining payloads internally */ + SKP_int moreInternalDecoderFrames; + + /* O: Distance between main payload and redundant payload in packets */ + SKP_int inBandFECOffset; +} SKP_SILK_SDK_DecControlStruct; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/pkg/silk/csilk/SKP_Silk_control_audio_bandwidth.c b/pkg/silk/csilk/SKP_Silk_control_audio_bandwidth.c new file mode 100644 index 0000000..e7bed0c --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_control_codec_FIX.c b/pkg/silk/csilk/SKP_Silk_control_codec_FIX.c new file mode 100644 index 0000000..a24853c --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_control_codec_FIX.c @@ -0,0 +1,402 @@ +/*********************************************************************** +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_FIX.h" +#include "SKP_Silk_setup_complexity.h" + +SKP_INLINE SKP_int SKP_Silk_setup_resamplers_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk encoder state FIX */ + SKP_int fs_kHz /* I Internal sampling rate (kHz) */ +); + +SKP_INLINE SKP_int SKP_Silk_setup_packetsize_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk encoder state FIX */ + SKP_int PacketSize_ms /* I Packet length (ms) */ +); + +SKP_INLINE SKP_int SKP_Silk_setup_fs_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk encoder state FIX */ + SKP_int fs_kHz /* I Internal sampling rate (kHz) */ +); + +SKP_INLINE SKP_int SKP_Silk_setup_rate_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk encoder state FIX */ + SKP_int32 TargetRate_bps /* I Target max bitrate (if SNR_dB == 0) */ +); + +SKP_INLINE SKP_int SKP_Silk_setup_LBRR_FIX( + SKP_Silk_encoder_state_FIX *psEnc /* I/O Pointer to Silk encoder state FIX */ +); + +/* Control encoder */ +SKP_int SKP_Silk_control_encoder_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk encoder state */ + 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_FIX( 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_FIX( psEnc, fs_kHz ); + + /********************************************/ + /* Set packet size */ + /********************************************/ + ret += SKP_Silk_setup_packetsize_FIX( psEnc, PacketSize_ms ); + + /********************************************/ + /* Set internal sampling frequency */ + /********************************************/ + ret += SKP_Silk_setup_fs_FIX( psEnc, fs_kHz ); + + /********************************************/ + /* Set encoding complexity */ + /********************************************/ + ret += SKP_Silk_setup_complexity( &psEnc->sCmn, Complexity ); + + /********************************************/ + /* Set bitrate/coding quality */ + /********************************************/ + ret += SKP_Silk_setup_rate_FIX( 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_FIX( 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_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I Encoder state FIX */ + SKP_Silk_encoder_control *psEncCtrlC /* 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_Q8 > SKP_FIX_CONST( LBRR_SPEECH_ACTIVITY_THRES, 8 ) && psEnc->sCmn.PacketLoss_perc > LBRR_LOSS_THRES ) { // nb! maybe multiply loss prob and speech activity + LBRR_usage = SKP_SILK_ADD_LBRR_TO_PLUS1; + } + psEncCtrlC->LBRR_usage = LBRR_usage; + } else { + psEncCtrlC->LBRR_usage = SKP_SILK_NO_LBRR; + } +} + +SKP_INLINE SKP_int SKP_Silk_setup_resamplers_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk encoder state FIX */ + 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_int32 nSamples_temp = SKP_LSHIFT( psEnc->sCmn.frame_length, 1 ) + LA_SHAPE_MS * psEnc->sCmn.fs_kHz; + + if( SKP_SMULBB( 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, SKP_SMULBB( 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, psEnc->x_buf, nSamples_temp ); + + /* Calculate number of samples that has been temporarily upsampled */ + nSamples_temp = SKP_DIV32_16( nSamples_temp * psEnc->sCmn.API_fs_Hz, SKP_SMULBB( 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, SKP_SMULBB( fs_kHz, 1000 ) ); + + } else { + /* Copy data */ + SKP_memcpy( x_buf_API_fs_Hz, psEnc->x_buf, 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, psEnc->x_buf, x_buf_API_fs_Hz, nSamples_temp ); + } + } + } + + psEnc->sCmn.prev_API_fs_Hz = psEnc->sCmn.API_fs_Hz; + + return(ret); +} + +SKP_INLINE SKP_int SKP_Silk_setup_packetsize_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk encoder state FIX */ + 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_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk encoder state FIX */ + 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_FIX ) ); + SKP_memset( &psEnc->sPrefilt, 0, sizeof( SKP_Silk_prefilter_state_FIX ) ); + SKP_memset( &psEnc->sPred, 0, sizeof( SKP_Silk_predict_state_FIX ) ); + 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_Q15, 0, MAX_LPC_ORDER * sizeof( SKP_int ) ); + + /* 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; + } 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->sCmn.frame_length = SKP_SMULBB( FRAME_LENGTH_MS, fs_kHz ); + psEnc->sCmn.subfr_length = SKP_DIV32_16( psEnc->sCmn.frame_length, NB_SUBFR ); + psEnc->sCmn.la_pitch = SKP_SMULBB( LA_PITCH_MS, fs_kHz ); + psEnc->sPred.min_pitch_lag = SKP_SMULBB( 3, fs_kHz ); + psEnc->sPred.max_pitch_lag = SKP_SMULBB( 18, fs_kHz ); + psEnc->sPred.pitch_LPC_win_length = SKP_SMULBB( FIND_PITCH_LPC_WIN_MS, fs_kHz ); + if( psEnc->sCmn.fs_kHz == 24 ) { + psEnc->mu_LTP_Q8 = SKP_FIX_CONST( MU_LTP_QUANT_SWB, 8 ); + 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_Q8 = SKP_FIX_CONST( MU_LTP_QUANT_WB, 8 ); + 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_Q8 = SKP_FIX_CONST( MU_LTP_QUANT_MB, 8 ); + psEnc->sCmn.bitrate_threshold_up = MB2WB_BITRATE_BPS; + psEnc->sCmn.bitrate_threshold_down = MB2NB_BITRATE_BPS; + } else { + psEnc->mu_LTP_Q8 = SKP_FIX_CONST( MU_LTP_QUANT_NB, 8 ); + 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_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk encoder state FIX */ + SKP_int32 TargetRate_bps /* I Target max bitrate (if SNR_dB == 0) */ +) +{ + SKP_int k, ret = SKP_SILK_NO_ERROR; + SKP_int32 frac_Q6; + 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_Q6 = SKP_DIV32( SKP_LSHIFT( TargetRate_bps - rateTable[ k - 1 ], 6 ), + rateTable[ k ] - rateTable[ k - 1 ] ); + psEnc->SNR_dB_Q7 = SKP_LSHIFT( SNR_table_Q1[ k - 1 ], 6 ) + SKP_MUL( frac_Q6, SNR_table_Q1[ k ] - SNR_table_Q1[ k - 1 ] ); + break; + } + } + } + return( ret ); +} + +SKP_INLINE SKP_int SKP_Silk_setup_LBRR_FIX( + SKP_Silk_encoder_state_FIX *psEnc /* I/O Pointer to Silk encoder state FIX */ +) +{ + 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_Q8 = SKP_FIX_CONST( 6.0f, 8 ) - SKP_LSHIFT( psEnc->sCmn.LBRR_GainIncreases, 7 ); + } else { + psEnc->inBandFEC_SNR_comp_Q8 = 0; + psEnc->sCmn.LBRR_enabled = 0; + } + } else { + psEnc->inBandFEC_SNR_comp_Q8 = 0; + 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/pkg/silk/csilk/SKP_Silk_corrMatrix_FIX.c b/pkg/silk/csilk/SKP_Silk_corrMatrix_FIX.c new file mode 100644 index 0000000..18b55c9 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_corrMatrix_FIX.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. +***********************************************************************/ + +/********************************************************************** + * Correlation Matrix Computations for LS estimate. + **********************************************************************/ + +#include "SKP_Silk_main_FIX.h" + +/* Calculates correlation vector X'*t */ +void SKP_Silk_corrVector_FIX( + const SKP_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */ + const SKP_int16 *t, /* I target vector [L] */ + const SKP_int L, /* I Length of vectors */ + const SKP_int order, /* I Max lag for correlation */ + SKP_int32 *Xt, /* O Pointer to X'*t correlation vector [order] */ + const SKP_int rshifts /* I Right shifts of correlations */ +) +{ + SKP_int lag, i; + const SKP_int16 *ptr1, *ptr2; + SKP_int32 inner_prod; + + ptr1 = &x[ order - 1 ]; /* Points to first sample of column 0 of X: X[:,0] */ + ptr2 = t; + /* Calculate X'*t */ + if( rshifts > 0 ) { + /* Right shifting used */ + for( lag = 0; lag < order; lag++ ) { + inner_prod = 0; + for( i = 0; i < L; i++ ) { + inner_prod += SKP_RSHIFT32( SKP_SMULBB( ptr1[ i ], ptr2[i] ), rshifts ); + } + Xt[ lag ] = inner_prod; /* X[:,lag]'*t */ + ptr1--; /* Go to next column of X */ + } + } else { + SKP_assert( rshifts == 0 ); + for( lag = 0; lag < order; lag++ ) { + Xt[ lag ] = SKP_Silk_inner_prod_aligned( ptr1, ptr2, L ); /* X[:,lag]'*t */ + ptr1--; /* Go to next column of X */ + } + } +} + +/* Calculates correlation matrix X'*X */ +void SKP_Silk_corrMatrix_FIX( + const SKP_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */ + const SKP_int L, /* I Length of vectors */ + const SKP_int order, /* I Max lag for correlation */ + const SKP_int head_room, /* I Desired headroom */ + SKP_int32 *XX, /* O Pointer to X'*X correlation matrix [ order x order ]*/ + SKP_int *rshifts /* I/O Right shifts of correlations */ +) +{ + SKP_int i, j, lag, rshifts_local, head_room_rshifts; + SKP_int32 energy; + const SKP_int16 *ptr1, *ptr2; + + /* Calculate energy to find shift used to fit in 32 bits */ + SKP_Silk_sum_sqr_shift( &energy, &rshifts_local, x, L + order - 1 ); + + /* Add shifts to get the desired head room */ + head_room_rshifts = SKP_max( head_room - SKP_Silk_CLZ32( energy ), 0 ); + + energy = SKP_RSHIFT32( energy, head_room_rshifts ); + rshifts_local += head_room_rshifts; + + /* Calculate energy of first column (0) of X: X[:,0]'*X[:,0] */ + /* Remove contribution of first order - 1 samples */ + for( i = 0; i < order - 1; i++ ) { + energy -= SKP_RSHIFT32( SKP_SMULBB( x[ i ], x[ i ] ), rshifts_local ); + } + if( rshifts_local < *rshifts ) { + /* Adjust energy */ + energy = SKP_RSHIFT32( energy, *rshifts - rshifts_local ); + rshifts_local = *rshifts; + } + + /* Calculate energy of remaining columns of X: X[:,j]'*X[:,j] */ + /* Fill out the diagonal of the correlation matrix */ + matrix_ptr( XX, 0, 0, order ) = energy; + ptr1 = &x[ order - 1 ]; /* First sample of column 0 of X */ + for( j = 1; j < order; j++ ) { + energy = SKP_SUB32( energy, SKP_RSHIFT32( SKP_SMULBB( ptr1[ L - j ], ptr1[ L - j ] ), rshifts_local ) ); + energy = SKP_ADD32( energy, SKP_RSHIFT32( SKP_SMULBB( ptr1[ -j ], ptr1[ -j ] ), rshifts_local ) ); + matrix_ptr( XX, j, j, order ) = energy; + } + + ptr2 = &x[ order - 2 ]; /* First sample of column 1 of X */ + /* Calculate the remaining elements of the correlation matrix */ + if( rshifts_local > 0 ) { + /* Right shifting used */ + for( lag = 1; lag < order; lag++ ) { + /* Inner product of column 0 and column lag: X[:,0]'*X[:,lag] */ + energy = 0; + for( i = 0; i < L; i++ ) { + energy += SKP_RSHIFT32( SKP_SMULBB( ptr1[ i ], ptr2[i] ), rshifts_local ); + } + /* Calculate remaining off diagonal: X[:,j]'*X[:,j + lag] */ + matrix_ptr( XX, lag, 0, order ) = energy; + matrix_ptr( XX, 0, lag, order ) = energy; + for( j = 1; j < ( order - lag ); j++ ) { + energy = SKP_SUB32( energy, SKP_RSHIFT32( SKP_SMULBB( ptr1[ L - j ], ptr2[ L - j ] ), rshifts_local ) ); + energy = SKP_ADD32( energy, SKP_RSHIFT32( SKP_SMULBB( ptr1[ -j ], ptr2[ -j ] ), rshifts_local ) ); + matrix_ptr( XX, lag + j, j, order ) = energy; + matrix_ptr( XX, j, lag + j, order ) = energy; + } + ptr2--; /* Update pointer to first sample of next column (lag) in X */ + } + } else { + for( lag = 1; lag < order; lag++ ) { + /* Inner product of column 0 and column lag: X[:,0]'*X[:,lag] */ + energy = SKP_Silk_inner_prod_aligned( ptr1, ptr2, L ); + matrix_ptr( XX, lag, 0, order ) = energy; + matrix_ptr( XX, 0, lag, order ) = energy; + /* Calculate remaining off diagonal: X[:,j]'*X[:,j + lag] */ + for( j = 1; j < ( order - lag ); j++ ) { + energy = SKP_SUB32( energy, SKP_SMULBB( ptr1[ L - j ], ptr2[ L - j ] ) ); + energy = SKP_SMLABB( energy, ptr1[ -j ], ptr2[ -j ] ); + matrix_ptr( XX, lag + j, j, order ) = energy; + matrix_ptr( XX, j, lag + j, order ) = energy; + } + ptr2--;/* Update pointer to first sample of next column (lag) in X */ + } + } + *rshifts = rshifts_local; +} + diff --git a/pkg/silk/csilk/SKP_Silk_create_init_destroy.c b/pkg/silk/csilk/SKP_Silk_create_init_destroy.c new file mode 100644 index 0000000..355ca85 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_dec_API.c b/pkg/silk/csilk/SKP_Silk_dec_API.c new file mode 100644 index 0000000..ca031e3 --- /dev/null +++ b/pkg/silk/csilk/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.6"; + return version; +} diff --git a/pkg/silk/csilk/SKP_Silk_decode_core.c b/pkg/silk/csilk/SKP_Silk_decode_core.c new file mode 100644 index 0000000..247f24d --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_decode_core.c @@ -0,0 +1,314 @@ +/*********************************************************************** +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 ) ); + +} + +#if EMBEDDED_ARM<5 +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; + #if !defined(_SYSTEM_IS_BIG_ENDIAN) + SKP_int32 Atmp; + /* Short term prediction */ + /* NOTE: the code below loads two int16 values in an int32, and multiplies each using the */ + /* SMLAWB and SMLAWT instructions. On a big-endian CPU the two int16 variables would be */ + /* loaded in reverse order and the code will give the wrong result. In that case swapping */ + /* the SMLAWB and SMLAWT instructions should solve the problem. */ + if( LPC_order == 16 ) { + for( i = 0; i < subfr_length; i++ ) { + /* unrolled */ + Atmp = *( ( SKP_int32* )&A_Q12_tmp[ 0 ] ); /* read two coefficients at once */ + LPC_pred_Q10 = SKP_SMULWB( sLPC_Q14[ MAX_LPC_ORDER + i - 1 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 2 ], Atmp ); + Atmp = *( ( SKP_int32* )&A_Q12_tmp[ 2 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 3 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 4 ], Atmp ); + Atmp = *( ( SKP_int32* )&A_Q12_tmp[ 4 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 5 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 6 ], Atmp ); + Atmp = *( ( SKP_int32* )&A_Q12_tmp[ 6 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 7 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 8 ], Atmp ); + Atmp = *( ( SKP_int32* )&A_Q12_tmp[ 8 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 9 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 10 ], Atmp ); + Atmp = *( ( SKP_int32* )&A_Q12_tmp[ 10 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 11 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 12 ], Atmp ); + Atmp = *( ( SKP_int32* )&A_Q12_tmp[ 12 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 13 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 14 ], Atmp ); + Atmp = *( ( SKP_int32* )&A_Q12_tmp[ 14 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 15 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 16 ], Atmp ); + + /* 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 ); + } + } else { + SKP_assert( LPC_order == 10 ); + for( i = 0; i < subfr_length; i++ ) { + /* unrolled */ + Atmp = *( ( SKP_int32* )&A_Q12_tmp[ 0 ] ); /* read two coefficients at once */ + LPC_pred_Q10 = SKP_SMULWB( sLPC_Q14[ MAX_LPC_ORDER + i - 1 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 2 ], Atmp ); + Atmp = *( ( SKP_int32* )&A_Q12_tmp[ 2 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 3 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 4 ], Atmp ); + Atmp = *( ( SKP_int32* )&A_Q12_tmp[ 4 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 5 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 6 ], Atmp ); + Atmp = *( ( SKP_int32* )&A_Q12_tmp[ 6 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 7 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 8 ], Atmp ); + Atmp = *( ( SKP_int32* )&A_Q12_tmp[ 8 ] ); + LPC_pred_Q10 = SKP_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 9 ], Atmp ); + LPC_pred_Q10 = SKP_SMLAWT( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 10 ], Atmp ); + + /* 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 ); + } + } +#else + 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 ); + } +#endif +} +#endif + + + diff --git a/pkg/silk/csilk/SKP_Silk_decode_frame.c b/pkg/silk/csilk/SKP_Silk_decode_frame.c new file mode 100644 index 0000000..c0ff322 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_decode_parameters.c b/pkg/silk/csilk/SKP_Silk_decode_parameters.c new file mode 100644 index 0000000..108a939 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_decode_pitch.c b/pkg/silk/csilk/SKP_Silk_decode_pitch.c new file mode 100644 index 0000000..38b7aa7 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_decode_pulses.c b/pkg/silk/csilk/SKP_Silk_decode_pulses.c new file mode 100644 index 0000000..119553f --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_decoder_set_fs.c b/pkg/silk/csilk/SKP_Silk_decoder_set_fs.c new file mode 100644 index 0000000..b4cd08b --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_define.h b/pkg/silk/csilk/SKP_Silk_define.h new file mode 100644 index 0000000..43e8e68 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_detect_SWB_input.c b/pkg/silk/csilk/SKP_Silk_detect_SWB_input.c new file mode 100644 index 0000000..eb3ee05 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_div_oabi.c b/pkg/silk/csilk/SKP_Silk_div_oabi.c new file mode 100644 index 0000000..327dcfa --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_div_oabi.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_typedef.h" + +SKP_int32 SKP_DIV32_arm( SKP_int32 a32, SKP_int32 b32 ) { + return ( ( SKP_int32 )( ( a32 ) / ( b32 ) ) ); +} + + + diff --git a/pkg/silk/csilk/SKP_Silk_enc_API.c b/pkg/silk/csilk/SKP_Silk_enc_API.c new file mode 100644 index 0000000..63657ab --- /dev/null +++ b/pkg/silk/csilk/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_FIX.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_FIX ); + + 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_FIX *psEnc; + SKP_int ret = 0; + + psEnc = ( SKP_Silk_encoder_state_FIX* )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_FIX *psEnc; + SKP_int ret = 0; + + + psEnc = ( SKP_Silk_encoder_state_FIX* )encState; + + /* Reset Encoder */ + if( ret += SKP_Silk_init_encoder_FIX( 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_FIX *psEnc = ( SKP_Silk_encoder_state_FIX* )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_FIX( 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_FIX( psEnc, outData, &MaxBytesOut, psEnc->sCmn.inputBuf ) ) != 0 ) { + SKP_assert( 0 ); + } + } else { + /* outData already contains a payload */ + if( ( ret = SKP_Silk_encode_frame_FIX( 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/pkg/silk/csilk/SKP_Silk_encode_frame_FIX.c b/pkg/silk/csilk/SKP_Silk_encode_frame_FIX.c new file mode 100644 index 0000000..c108289 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_encode_frame_FIX.c @@ -0,0 +1,413 @@ +/*********************************************************************** +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_FIX.h" +#include "SKP_Silk_tuning_parameters.h" + +/****************/ +/* Encode frame */ +/****************/ +SKP_int SKP_Silk_encode_frame_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */ + SKP_uint8 *pCode, /* O Pointer to payload */ + SKP_int16 *pnBytesOut, /* I/O Pointer to number of payload bytes */ + /* input: max length; output: used */ + const SKP_int16 *pIn /* I Pointer to input speech frame */ +) +{ + SKP_Silk_encoder_control_FIX sEncCtrl; + SKP_int nBytes, ret = 0; + SKP_int16 *x_frame, *res_pitch_frame; + SKP_int16 xfw[ MAX_FRAME_LENGTH ]; + SKP_int16 pIn_HP[ MAX_FRAME_LENGTH ]; + SKP_int16 res_pitch[ 2 * MAX_FRAME_LENGTH + LA_PITCH_MAX ]; + SKP_int LBRR_idx, frame_terminator, SNR_dB_Q7; + const SKP_uint16 *FrameTermination_CDF; + /* Low bitrate redundancy parameters */ + SKP_uint8 LBRRpayload[ MAX_ARITHM_BYTES ]; + SKP_int16 nBytesLBRR; + + + sEncCtrl.sCmn.Seed = psEnc->sCmn.frameCounter++ & 3; + /**************************************************************/ + /* Setup Input Pointers, and insert frame in input buffer */ + /*************************************************************/ + 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 */ + /****************************/ + ret = SKP_Silk_VAD_GetSA_Q8( &psEnc->sCmn.sVAD, &psEnc->speech_activity_Q8, &SNR_dB_Q7, + sEncCtrl.input_quality_bands_Q15, &sEncCtrl.input_tilt_Q15, + pIn,psEnc->sCmn.frame_length ); + + /*******************************************/ + /* High-pass filtering of the input signal */ + /*******************************************/ +#if HIGH_PASS_INPUT + /* Variable high-pass filter */ + SKP_Silk_HP_variable_cutoff_FIX( 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, x_frame + LA_SHAPE_MS * psEnc->sCmn.fs_kHz, pIn_HP, psEnc->sCmn.frame_length ); +#else + SKP_memcpy( x_frame + LA_SHAPE_MS * psEnc->sCmn.fs_kHz, pIn_HP,psEnc->sCmn.frame_length * sizeof( SKP_int16 ) ); +#endif + + /*****************************************/ + /* Find pitch lags, initial LPC analysis */ + /*****************************************/ + SKP_Silk_find_pitch_lags_FIX( psEnc, &sEncCtrl, res_pitch, x_frame ); + + /************************/ + /* Noise shape analysis */ + /************************/ + SKP_Silk_noise_shape_analysis_FIX( psEnc, &sEncCtrl, res_pitch_frame, x_frame ); + + /*****************************************/ + /* Prefiltering for noise shaper */ + /*****************************************/ + SKP_Silk_prefilter_FIX( psEnc, &sEncCtrl, xfw, x_frame ); + + /***************************************************/ + /* Find linear prediction coefficients (LPC + LTP) */ + /***************************************************/ + SKP_Silk_find_pred_coefs_FIX( psEnc, &sEncCtrl, res_pitch ); + + /****************************************/ + /* Process gains */ + /****************************************/ + SKP_Silk_process_gains_FIX( psEnc, &sEncCtrl ); + + + /****************************************/ + /* Low Bitrate Redundant Encoding */ + /****************************************/ + nBytesLBRR = MAX_ARITHM_BYTES; + SKP_Silk_LBRR_encode_FIX( psEnc, &sEncCtrl, LBRRpayload, &nBytesLBRR, xfw ); + + /*****************************************/ + /* Noise shaping quantization */ + /*****************************************/ + if( psEnc->sCmn.nStatesDelayedDecision > 1 || psEnc->sCmn.warping_Q16 > 0 ) { + SKP_Silk_NSQ_del_dec( &psEnc->sCmn, &sEncCtrl.sCmn, &psEnc->sCmn.sNSQ, xfw, + psEnc->sCmn.q, sEncCtrl.sCmn.NLSFInterpCoef_Q2, + sEncCtrl.PredCoef_Q12[ 0 ], sEncCtrl.LTPCoef_Q14, sEncCtrl.AR2_Q13, sEncCtrl.HarmShapeGain_Q14, + sEncCtrl.Tilt_Q14, sEncCtrl.LF_shp_Q14, sEncCtrl.Gains_Q16, sEncCtrl.Lambda_Q10, + sEncCtrl.LTP_scale_Q14 ); + } else { + SKP_Silk_NSQ( &psEnc->sCmn, &sEncCtrl.sCmn, &psEnc->sCmn.sNSQ, xfw, + psEnc->sCmn.q, sEncCtrl.sCmn.NLSFInterpCoef_Q2, + sEncCtrl.PredCoef_Q12[ 0 ], sEncCtrl.LTPCoef_Q14, sEncCtrl.AR2_Q13, sEncCtrl.HarmShapeGain_Q14, + sEncCtrl.Tilt_Q14, sEncCtrl.LF_shp_Q14, sEncCtrl.Gains_Q16, sEncCtrl.Lambda_Q10, + sEncCtrl.LTP_scale_Q14 ); + } + + /**************************************************/ + /* Convert speech activity into VAD and DTX flags */ + /**************************************************/ + if( psEnc->speech_activity_Q8 < SKP_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 ) ) { + 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_int16 ) ); + + /* 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 */ + SKP_assert( ( 8 * 1000 * ( (SKP_int64)nBytes - (SKP_int64)psEnc->sCmn.nBytesInPayloadBuf ) ) == + SKP_SAT32( 8 * 1000 * ( (SKP_int64)nBytes - (SKP_int64)psEnc->sCmn.nBytesInPayloadBuf ) ) ); + SKP_assert( psEnc->sCmn.TargetRate_bps > 0 ); + psEnc->BufferedInChannel_ms += SKP_DIV32( 8 * 1000 * ( nBytes - psEnc->sCmn.nBytesInPayloadBuf ), psEnc->sCmn.TargetRate_bps ); + psEnc->BufferedInChannel_ms -= FRAME_LENGTH_MS; + psEnc->BufferedInChannel_ms = SKP_LIMIT_int( psEnc->BufferedInChannel_ms, 0, 100 ); + psEnc->sCmn.nBytesInPayloadBuf = nBytes; + + if( psEnc->speech_activity_Q8 > SKP_FIX_CONST( WB_DETECT_ACTIVE_SPEECH_LEVEL_THRES, 8 ) ) { + psEnc->sCmn.sSWBdetect.ActiveSpeech_ms = SKP_ADD_POS_SAT32( psEnc->sCmn.sSWBdetect.ActiveSpeech_ms, FRAME_LENGTH_MS ); + } + + + return( ret ); +} + +/* Low BitRate Redundancy encoding functionality. Reuse all parameters but encode residual with lower bitrate */ +void SKP_Silk_LBRR_encode_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk encoder state */ + SKP_Silk_encoder_control_FIX *psEncCtrl, /* I/O Pointer to Silk encoder control struct */ + SKP_uint8 *pCode, /* O Pointer to payload */ + SKP_int16 *pnBytesOut, /* I/O Pointer to number of payload bytes */ + SKP_int16 xfw[] /* I Input signal */ +) +{ + SKP_int TempGainsIndices[ NB_SUBFR ], frame_terminator; + SKP_int nBytes, nFramesInPayloadBuf; + SKP_int32 TempGains_Q16[ NB_SUBFR ]; + SKP_int typeOffset, LTP_scaleIndex, Rate_only_parameters = 0; + /*******************************************/ + /* Control use of inband LBRR */ + /*******************************************/ + SKP_Silk_LBRR_ctrl_FIX( 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_Q16, psEncCtrl->Gains_Q16, NB_SUBFR * sizeof( SKP_int32 ) ); + + 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 ] = 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 */ + /* Overwrite unquantized gains with quantized gains */ + SKP_Silk_gains_dequant( psEncCtrl->Gains_Q16, psEncCtrl->sCmn.GainsIndices, + &psEnc->sCmn.LBRRprevLastGainIndex, psEnc->sCmn.nFramesInPayloadBuf ); + + /*****************************************/ + /* Noise shaping quantization */ + /*****************************************/ + if( psEnc->sCmn.nStatesDelayedDecision > 1 || psEnc->sCmn.warping_Q16 > 0 ) { + SKP_Silk_NSQ_del_dec( &psEnc->sCmn, &psEncCtrl->sCmn, &psEnc->sCmn.sNSQ_LBRR, xfw, psEnc->sCmn.q_LBRR, + psEncCtrl->sCmn.NLSFInterpCoef_Q2, psEncCtrl->PredCoef_Q12[ 0 ], psEncCtrl->LTPCoef_Q14, + psEncCtrl->AR2_Q13, psEncCtrl->HarmShapeGain_Q14, psEncCtrl->Tilt_Q14, psEncCtrl->LF_shp_Q14, + psEncCtrl->Gains_Q16, psEncCtrl->Lambda_Q10, psEncCtrl->LTP_scale_Q14 ); + } else { + SKP_Silk_NSQ( &psEnc->sCmn, &psEncCtrl->sCmn, &psEnc->sCmn.sNSQ_LBRR, xfw, psEnc->sCmn.q_LBRR, + psEncCtrl->sCmn.NLSFInterpCoef_Q2, psEncCtrl->PredCoef_Q12[ 0 ], psEncCtrl->LTPCoef_Q14, + psEncCtrl->AR2_Q13, psEncCtrl->HarmShapeGain_Q14, psEncCtrl->Tilt_Q14, psEncCtrl->LF_shp_Q14, + psEncCtrl->Gains_Q16, psEncCtrl->Lambda_Q10, psEncCtrl->LTP_scale_Q14 ); + } + } 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( SKP_SMULBB( 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_Q16, TempGains_Q16, NB_SUBFR * sizeof( SKP_int32 ) ); + + /* Restore LTP scale index and typeoffset */ + psEncCtrl->sCmn.LTP_scaleIndex = LTP_scaleIndex; + psEnc->sCmn.typeOffsetPrev = typeOffset; + } +} diff --git a/pkg/silk/csilk/SKP_Silk_encode_parameters.c b/pkg/silk/csilk/SKP_Silk_encode_parameters.c new file mode 100644 index 0000000..be50e01 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_encode_pulses.c b/pkg/silk/csilk/SKP_Silk_encode_pulses.c new file mode 100644 index 0000000..b0ea05e --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_errors.h b/pkg/silk/csilk/SKP_Silk_errors.h new file mode 100644 index 0000000..ee2a487 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_errors.h @@ -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. +***********************************************************************/ + +#ifndef SKP_SILK_ERRORS_H +#define SKP_SILK_ERRORS_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/******************/ +/* Error messages */ +/******************/ +#define SKP_SILK_NO_ERROR 0 + +/**************************/ +/* Encoder error messages */ +/**************************/ + +/* Input length is not a multiplum of 10 ms, or length is longer than the packet length */ +#define SKP_SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES -1 + +/* Sampling frequency not 8000, 12000, 16000 or 24000 Hertz */ +#define SKP_SILK_ENC_FS_NOT_SUPPORTED -2 + +/* Packet size not 20, 40, 60, 80 or 100 ms */ +#define SKP_SILK_ENC_PACKET_SIZE_NOT_SUPPORTED -3 + +/* Allocated payload buffer too short */ +#define SKP_SILK_ENC_PAYLOAD_BUF_TOO_SHORT -4 + +/* Loss rate not between 0 and 100 percent */ +#define SKP_SILK_ENC_INVALID_LOSS_RATE -5 + +/* Complexity setting not valid, use 0, 1 or 2 */ +#define SKP_SILK_ENC_INVALID_COMPLEXITY_SETTING -6 + +/* Inband FEC setting not valid, use 0 or 1 */ +#define SKP_SILK_ENC_INVALID_INBAND_FEC_SETTING -7 + +/* DTX setting not valid, use 0 or 1 */ +#define SKP_SILK_ENC_INVALID_DTX_SETTING -8 + +/* Internal encoder error */ +#define SKP_SILK_ENC_INTERNAL_ERROR -9 + +/**************************/ +/* Decoder error messages */ +/**************************/ + +/* Output sampling frequency lower than internal decoded sampling frequency */ +#define SKP_SILK_DEC_INVALID_SAMPLING_FREQUENCY -10 + +/* Payload size exceeded the maximum allowed 1024 bytes */ +#define SKP_SILK_DEC_PAYLOAD_TOO_LARGE -11 + +/* Payload has bit errors */ +#define SKP_SILK_DEC_PAYLOAD_ERROR -12 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/pkg/silk/csilk/SKP_Silk_find_LPC_FIX.c b/pkg/silk/csilk/SKP_Silk_find_LPC_FIX.c new file mode 100644 index 0000000..5a0c7c7 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_find_LPC_FIX.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_main_FIX.h" +#include "SKP_Silk_tuning_parameters.h" + +/* Finds LPC vector from correlations, and converts to NLSF */ +void SKP_Silk_find_LPC_FIX( + SKP_int NLSF_Q15[], /* O NLSFs */ + SKP_int *interpIndex, /* O NLSF interpolation index, only used for NLSF interpolation */ + const SKP_int prev_NLSFq_Q15[], /* I previous NLSFs, only used for NLSF interpolation */ + const SKP_int useInterpolatedNLSFs, /* I Flag */ + const SKP_int LPC_order, /* I LPC order */ + const SKP_int16 x[], /* I Input signal */ + const SKP_int subfr_length /* I Input signal subframe length including preceeding samples */ +) +{ + SKP_int k; + SKP_int32 a_Q16[ MAX_LPC_ORDER ]; + SKP_int isInterpLower, shift; + SKP_int16 S[ MAX_LPC_ORDER ]; + SKP_int32 res_nrg0, res_nrg1; + SKP_int rshift0, rshift1; + + /* Used only for LSF interpolation */ + SKP_int32 a_tmp_Q16[ MAX_LPC_ORDER ], res_nrg_interp, res_nrg, res_tmp_nrg; + SKP_int res_nrg_interp_Q, res_nrg_Q, res_tmp_nrg_Q; + SKP_int16 a_tmp_Q12[ MAX_LPC_ORDER ]; + SKP_int NLSF0_Q15[ MAX_LPC_ORDER ]; + SKP_int16 LPC_res[ ( MAX_FRAME_LENGTH + NB_SUBFR * MAX_LPC_ORDER ) / 2 ]; + + /* Default: no interpolation */ + *interpIndex = 4; + + /* Burg AR analysis for the full frame */ + SKP_Silk_burg_modified( &res_nrg, &res_nrg_Q, a_Q16, x, subfr_length, NB_SUBFR, SKP_FIX_CONST( FIND_LPC_COND_FAC, 32 ), LPC_order ); + + SKP_Silk_bwexpander_32( a_Q16, LPC_order, SKP_FIX_CONST( FIND_LPC_CHIRP, 16 ) ); + + if( useInterpolatedNLSFs == 1 ) { + + /* Optimal solution for last 10 ms */ + SKP_Silk_burg_modified( &res_tmp_nrg, &res_tmp_nrg_Q, a_tmp_Q16, x + ( NB_SUBFR >> 1 ) * subfr_length, + subfr_length, ( NB_SUBFR >> 1 ), SKP_FIX_CONST( FIND_LPC_COND_FAC, 32 ), LPC_order ); + + SKP_Silk_bwexpander_32( a_tmp_Q16, LPC_order, SKP_FIX_CONST( FIND_LPC_CHIRP, 16 ) ); + + /* 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 */ + shift = res_tmp_nrg_Q - res_nrg_Q; + if( shift >= 0 ) { + if( shift < 32 ) { + res_nrg = res_nrg - SKP_RSHIFT( res_tmp_nrg, shift ); + } + } else { + SKP_assert( shift > -32 ); + res_nrg = SKP_RSHIFT( res_nrg, -shift ) - res_tmp_nrg; + res_nrg_Q = res_tmp_nrg_Q; + } + + /* Convert to NLSFs */ + SKP_Silk_A2NLSF( NLSF_Q15, a_tmp_Q16, LPC_order ); + + /* Search over interpolation indices to find the one with lowest residual energy */ + for( k = 3; k >= 0; k-- ) { + /* Interpolate NLSFs for first half */ + SKP_Silk_interpolate( NLSF0_Q15, prev_NLSFq_Q15, NLSF_Q15, k, LPC_order ); + + /* Convert to LPC for residual energy evaluation */ + SKP_Silk_NLSF2A_stable( a_tmp_Q12, NLSF0_Q15, LPC_order ); + + /* Calculate residual energy with NLSF interpolation */ + SKP_memset( S, 0, LPC_order * sizeof( SKP_int16 ) ); + SKP_Silk_LPC_analysis_filter( x, a_tmp_Q12, S, LPC_res, 2 * subfr_length, LPC_order ); + + SKP_Silk_sum_sqr_shift( &res_nrg0, &rshift0, LPC_res + LPC_order, subfr_length - LPC_order ); + SKP_Silk_sum_sqr_shift( &res_nrg1, &rshift1, LPC_res + LPC_order + subfr_length, subfr_length - LPC_order ); + + /* Add subframe energies from first half frame */ + shift = rshift0 - rshift1; + if( shift >= 0 ) { + res_nrg1 = SKP_RSHIFT( res_nrg1, shift ); + res_nrg_interp_Q = -rshift0; + } else { + res_nrg0 = SKP_RSHIFT( res_nrg0, -shift ); + res_nrg_interp_Q = -rshift1; + } + res_nrg_interp = SKP_ADD32( res_nrg0, res_nrg1 ); + + /* Compare with first half energy without NLSF interpolation, or best interpolated value so far */ + shift = res_nrg_interp_Q - res_nrg_Q; + if( shift >= 0 ) { + if( SKP_RSHIFT( res_nrg_interp, shift ) < res_nrg ) { + isInterpLower = SKP_TRUE; + } else { + isInterpLower = SKP_FALSE; + } + } else { + if( -shift < 32 ) { + if( res_nrg_interp < SKP_RSHIFT( res_nrg, -shift ) ) { + isInterpLower = SKP_TRUE; + } else { + isInterpLower = SKP_FALSE; + } + } else { + isInterpLower = SKP_FALSE; + } + } + + /* Determine whether current interpolated NLSFs are best so far */ + if( isInterpLower == SKP_TRUE ) { + /* Interpolation has lower residual energy */ + res_nrg = res_nrg_interp; + res_nrg_Q = res_nrg_interp_Q; + *interpIndex = k; + } + } + } + + if( *interpIndex == 4 ) { + /* NLSF interpolation is currently inactive, calculate NLSFs from full frame AR coefficients */ + SKP_Silk_A2NLSF( NLSF_Q15, a_Q16, LPC_order ); + } +} diff --git a/pkg/silk/csilk/SKP_Silk_find_LTP_FIX.c b/pkg/silk/csilk/SKP_Silk_find_LTP_FIX.c new file mode 100644 index 0000000..4d047ff --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_find_LTP_FIX.c @@ -0,0 +1,243 @@ +/*********************************************************************** +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_FIX.h" +#include "SKP_Silk_tuning_parameters.h" + +/* Head room for correlations */ +#define LTP_CORRS_HEAD_ROOM 2 + +void SKP_Silk_fit_LTP( + SKP_int32 LTP_coefs_Q16[ LTP_ORDER ], + SKP_int16 LTP_coefs_Q14[ LTP_ORDER ] +); + +void SKP_Silk_find_LTP_FIX( + SKP_int16 b_Q14[ NB_SUBFR * LTP_ORDER ], /* O LTP coefs */ + SKP_int32 WLTP[ NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Weight for LTP quantization */ + SKP_int *LTPredCodGain_Q7, /* O LTP coding gain */ + const SKP_int16 r_first[], /* I residual signal after LPC signal + state for first 10 ms */ + const SKP_int16 r_last[], /* I residual signal after LPC signal + state for last 10 ms */ + const SKP_int lag[ NB_SUBFR ], /* I LTP lags */ + const SKP_int32 Wght_Q15[ 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 corr_rshifts[ NB_SUBFR ] /* O right shifts applied to correlations */ +) +{ + SKP_int i, k, lshift; + const SKP_int16 *r_ptr, *lag_ptr; + SKP_int16 *b_Q14_ptr; + + SKP_int32 regu; + SKP_int32 *WLTP_ptr; + SKP_int32 b_Q16[ LTP_ORDER ], delta_b_Q14[ LTP_ORDER ], d_Q14[ NB_SUBFR ], nrg[ NB_SUBFR ], g_Q26; + SKP_int32 w[ NB_SUBFR ], WLTP_max, max_abs_d_Q14, max_w_bits; + + SKP_int32 temp32, denom32; + SKP_int extra_shifts; + SKP_int rr_shifts, maxRshifts, maxRshifts_wxtra, LZs; + SKP_int32 LPC_res_nrg, LPC_LTP_res_nrg, div_Q16; + SKP_int32 Rr[ LTP_ORDER ], rr[ NB_SUBFR ]; + SKP_int32 wd, m_Q12; + + b_Q14_ptr = b_Q14; + 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_sum_sqr_shift( &rr[ k ], &rr_shifts, r_ptr, subfr_length ); /* rr[ k ] in Q( -rr_shifts ) */ + + /* Assure headroom */ + LZs = SKP_Silk_CLZ32( rr[k] ); + if( LZs < LTP_CORRS_HEAD_ROOM ) { + rr[ k ] = SKP_RSHIFT_ROUND( rr[ k ], LTP_CORRS_HEAD_ROOM - LZs ); + rr_shifts += ( LTP_CORRS_HEAD_ROOM - LZs ); + } + corr_rshifts[ k ] = rr_shifts; + SKP_Silk_corrMatrix_FIX( lag_ptr, subfr_length, LTP_ORDER, LTP_CORRS_HEAD_ROOM, WLTP_ptr, &corr_rshifts[ k ] ); /* WLTP_fix_ptr in Q( -corr_rshifts[ k ] ) */ + + /* The correlation vector always has lower max abs value than rr and/or RR so head room is assured */ + SKP_Silk_corrVector_FIX( lag_ptr, r_ptr, subfr_length, LTP_ORDER, Rr, corr_rshifts[ k ] ); /* Rr_fix_ptr in Q( -corr_rshifts[ k ] ) */ + if( corr_rshifts[ k ] > rr_shifts ) { + rr[ k ] = SKP_RSHIFT( rr[ k ], corr_rshifts[ k ] - rr_shifts ); /* rr[ k ] in Q( -corr_rshifts[ k ] ) */ + } + SKP_assert( rr[ k ] >= 0 ); + + regu = 1; + regu = SKP_SMLAWB( regu, rr[ k ], SKP_FIX_CONST( LTP_DAMPING/3, 16 ) ); + regu = SKP_SMLAWB( regu, matrix_ptr( WLTP_ptr, 0, 0, LTP_ORDER ), SKP_FIX_CONST( LTP_DAMPING/3, 16 ) ); + regu = SKP_SMLAWB( regu, matrix_ptr( WLTP_ptr, LTP_ORDER-1, LTP_ORDER-1, LTP_ORDER ), SKP_FIX_CONST( LTP_DAMPING/3, 16 ) ); + SKP_Silk_regularize_correlations_FIX( WLTP_ptr, &rr[k], regu, LTP_ORDER ); + + SKP_Silk_solve_LDL_FIX( WLTP_ptr, LTP_ORDER, Rr, b_Q16 ); /* WLTP_fix_ptr and Rr_fix_ptr both in Q(-corr_rshifts[k]) */ + + /* Limit and store in Q14 */ + SKP_Silk_fit_LTP( b_Q16, b_Q14_ptr ); + + /* Calculate residual energy */ + nrg[ k ] = SKP_Silk_residual_energy16_covar_FIX( b_Q14_ptr, WLTP_ptr, Rr, rr[ k ], LTP_ORDER, 14 ); /* nrg_fix in Q( -corr_rshifts[ k ] ) */ + + /* temp = Wght[ k ] / ( nrg[ k ] * Wght[ k ] + 0.01f * subfr_length ); */ + extra_shifts = SKP_min_int( corr_rshifts[ k ], LTP_CORRS_HEAD_ROOM ); + denom32 = SKP_LSHIFT_SAT32( SKP_SMULWB( nrg[ k ], Wght_Q15[ k ] ), 1 + extra_shifts ) + /* Q( -corr_rshifts[ k ] + extra_shifts ) */ + SKP_RSHIFT( SKP_SMULWB( subfr_length, 655 ), corr_rshifts[ k ] - extra_shifts ); /* Q( -corr_rshifts[ k ] + extra_shifts ) */ + denom32 = SKP_max( denom32, 1 ); + SKP_assert( ((SKP_int64)Wght_Q15[ k ] << 16 ) < SKP_int32_MAX ); /* Wght always < 0.5 in Q0 */ + temp32 = SKP_DIV32( SKP_LSHIFT( ( SKP_int32 )Wght_Q15[ k ], 16 ), denom32 ); /* Q( 15 + 16 + corr_rshifts[k] - extra_shifts ) */ + temp32 = SKP_RSHIFT( temp32, 31 + corr_rshifts[ k ] - extra_shifts - 26 ); /* Q26 */ + + /* Limit temp such that the below scaling never wraps around */ + WLTP_max = 0; + for( i = 0; i < LTP_ORDER * LTP_ORDER; i++ ) { + WLTP_max = SKP_max( WLTP_ptr[ i ], WLTP_max ); + } + lshift = SKP_Silk_CLZ32( WLTP_max ) - 1 - 3; /* keep 3 bits free for vq_nearest_neighbor_fix */ + SKP_assert( 26 - 18 + lshift >= 0 ); + if( 26 - 18 + lshift < 31 ) { + temp32 = SKP_min_32( temp32, SKP_LSHIFT( ( SKP_int32 )1, 26 - 18 + lshift ) ); + } + + SKP_Silk_scale_vector32_Q26_lshift_18( WLTP_ptr, temp32, LTP_ORDER * LTP_ORDER ); /* WLTP_ptr in Q( 18 - corr_rshifts[ k ] ) */ + + w[ k ] = matrix_ptr( WLTP_ptr, ( LTP_ORDER >> 1 ), ( LTP_ORDER >> 1 ), LTP_ORDER ); /* w in Q( 18 - corr_rshifts[ k ] ) */ + SKP_assert( w[k] >= 0 ); + + r_ptr += subfr_length; + b_Q14_ptr += LTP_ORDER; + WLTP_ptr += LTP_ORDER * LTP_ORDER; + } + + maxRshifts = 0; + for( k = 0; k < NB_SUBFR; k++ ) { + maxRshifts = SKP_max_int( corr_rshifts[ k ], maxRshifts ); + } + + /* Compute LTP coding gain */ + if( LTPredCodGain_Q7 != NULL ) { + LPC_LTP_res_nrg = 0; + LPC_res_nrg = 0; + SKP_assert( LTP_CORRS_HEAD_ROOM >= 2 ); /* Check that no overflow will happen when adding */ + for( k = 0; k < NB_SUBFR; k++ ) { + LPC_res_nrg = SKP_ADD32( LPC_res_nrg, SKP_RSHIFT( SKP_ADD32( SKP_SMULWB( rr[ k ], Wght_Q15[ k ] ), 1 ), 1 + ( maxRshifts - corr_rshifts[ k ] ) ) ); /* Q( -maxRshifts ) */ + LPC_LTP_res_nrg = SKP_ADD32( LPC_LTP_res_nrg, SKP_RSHIFT( SKP_ADD32( SKP_SMULWB( nrg[ k ], Wght_Q15[ k ] ), 1 ), 1 + ( maxRshifts - corr_rshifts[ k ] ) ) ); /* Q( -maxRshifts ) */ + } + LPC_LTP_res_nrg = SKP_max( LPC_LTP_res_nrg, 1 ); /* avoid division by zero */ + + div_Q16 = SKP_DIV32_varQ( LPC_res_nrg, LPC_LTP_res_nrg, 16 ); + *LTPredCodGain_Q7 = ( SKP_int )SKP_SMULBB( 3, SKP_Silk_lin2log( div_Q16 ) - ( 16 << 7 ) ); + + SKP_assert( *LTPredCodGain_Q7 == ( SKP_int )SKP_SAT16( SKP_MUL( 3, SKP_Silk_lin2log( div_Q16 ) - ( 16 << 7 ) ) ) ); + } + + /* smoothing */ + /* d = sum( B, 1 ); */ + b_Q14_ptr = b_Q14; + for( k = 0; k < NB_SUBFR; k++ ) { + d_Q14[ k ] = 0; + for( i = 0; i < LTP_ORDER; i++ ) { + d_Q14[ k ] += b_Q14_ptr[ i ]; + } + b_Q14_ptr += LTP_ORDER; + } + + /* m = ( w * d' ) / ( sum( w ) + 1e-3 ); */ + + /* Find maximum absolute value of d_Q14 and the bits used by w in Q0 */ + max_abs_d_Q14 = 0; + max_w_bits = 0; + for( k = 0; k < NB_SUBFR; k++ ) { + max_abs_d_Q14 = SKP_max_32( max_abs_d_Q14, SKP_abs( d_Q14[ k ] ) ); + /* w[ k ] is in Q( 18 - corr_rshifts[ k ] ) */ + /* Find bits needed in Q( 18 - maxRshifts ) */ + max_w_bits = SKP_max_32( max_w_bits, 32 - SKP_Silk_CLZ32( w[ k ] ) + corr_rshifts[ k ] - maxRshifts ); + } + + /* max_abs_d_Q14 = (5 << 15); worst case, i.e. LTP_ORDER * -SKP_int16_MIN */ + SKP_assert( max_abs_d_Q14 <= ( 5 << 15 ) ); + + /* How many bits is needed for w*d' in Q( 18 - maxRshifts ) in the worst case, of all d_Q14's being equal to max_abs_d_Q14 */ + extra_shifts = max_w_bits + 32 - SKP_Silk_CLZ32( max_abs_d_Q14 ) - 14; + + /* Subtract what we got available; bits in output var plus maxRshifts */ + extra_shifts -= ( 32 - 1 - 2 + maxRshifts ); /* Keep sign bit free as well as 2 bits for accumulation */ + extra_shifts = SKP_max_int( extra_shifts, 0 ); + + maxRshifts_wxtra = maxRshifts + extra_shifts; + + temp32 = SKP_RSHIFT( 262, maxRshifts + extra_shifts ) + 1; /* 1e-3f in Q( 18 - (maxRshifts + extra_shifts) ) */ + wd = 0; + for( k = 0; k < NB_SUBFR; k++ ) { + /* w has at least 2 bits of headroom so no overflow should happen */ + temp32 = SKP_ADD32( temp32, SKP_RSHIFT( w[ k ], maxRshifts_wxtra - corr_rshifts[ k ] ) ); /* Q( 18 - maxRshifts_wxtra ) */ + wd = SKP_ADD32( wd, SKP_LSHIFT( SKP_SMULWW( SKP_RSHIFT( w[ k ], maxRshifts_wxtra - corr_rshifts[ k ] ), d_Q14[ k ] ), 2 ) ); /* Q( 18 - maxRshifts_wxtra ) */ + } + m_Q12 = SKP_DIV32_varQ( wd, temp32, 12 ); + + b_Q14_ptr = b_Q14; + for( k = 0; k < NB_SUBFR; k++ ) { + /* w_fix[ k ] from Q( 18 - corr_rshifts[ k ] ) to Q( 16 ) */ + if( 2 - corr_rshifts[k] > 0 ) { + temp32 = SKP_RSHIFT( w[ k ], 2 - corr_rshifts[ k ] ); + } else { + temp32 = SKP_LSHIFT_SAT32( w[ k ], corr_rshifts[ k ] - 2 ); + } + + g_Q26 = SKP_MUL( + SKP_DIV32( + SKP_FIX_CONST( LTP_SMOOTHING, 26 ), + SKP_RSHIFT( SKP_FIX_CONST( LTP_SMOOTHING, 26 ), 10 ) + temp32 ), /* Q10 */ + SKP_LSHIFT_SAT32( SKP_SUB_SAT32( ( SKP_int32 )m_Q12, SKP_RSHIFT( d_Q14[ k ], 2 ) ), 4 ) ); /* Q16 */ + + temp32 = 0; + for( i = 0; i < LTP_ORDER; i++ ) { + delta_b_Q14[ i ] = SKP_max_16( b_Q14_ptr[ i ], 1638 ); /* 1638_Q14 = 0.1_Q0 */ + temp32 += delta_b_Q14[ i ]; /* Q14 */ + } + temp32 = SKP_DIV32( g_Q26, temp32 ); /* Q14->Q12 */ + for( i = 0; i < LTP_ORDER; i++ ) { + b_Q14_ptr[ i ] = SKP_LIMIT_32( ( SKP_int32 )b_Q14_ptr[ i ] + SKP_SMULWB( SKP_LSHIFT_SAT32( temp32, 4 ), delta_b_Q14[ i ] ), -16000, 28000 ); + } + b_Q14_ptr += LTP_ORDER; + } +} + +void SKP_Silk_fit_LTP( + SKP_int32 LTP_coefs_Q16[ LTP_ORDER ], + SKP_int16 LTP_coefs_Q14[ LTP_ORDER ] +) +{ + SKP_int i; + + for( i = 0; i < LTP_ORDER; i++ ) { + LTP_coefs_Q14[ i ] = ( SKP_int16 )SKP_SAT16( SKP_RSHIFT_ROUND( LTP_coefs_Q16[ i ], 2 ) ); + } +} diff --git a/pkg/silk/csilk/SKP_Silk_find_pitch_lags_FIX.c b/pkg/silk/csilk/SKP_Silk_find_pitch_lags_FIX.c new file mode 100644 index 0000000..a8fe42e --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_find_pitch_lags_FIX.c @@ -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. +***********************************************************************/ + +#include "SKP_Silk_main_FIX.h" +#include "SKP_Silk_tuning_parameters.h" + +/* Find pitch lags */ +void SKP_Silk_find_pitch_lags_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + SKP_Silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + SKP_int16 res[], /* O residual */ + const SKP_int16 x[] /* I Speech signal */ +) +{ + SKP_Silk_predict_state_FIX *psPredSt = &psEnc->sPred; + SKP_int buf_len, i, scale; + SKP_int32 thrhld_Q15, res_nrg; + const SKP_int16 *x_buf, *x_buf_ptr; + SKP_int16 Wsig[ FIND_PITCH_LPC_WIN_MAX ], *Wsig_ptr; + SKP_int32 auto_corr[ MAX_FIND_PITCH_LPC_ORDER + 1 ]; + SKP_int16 rc_Q15[ MAX_FIND_PITCH_LPC_ORDER ]; + SKP_int32 A_Q24[ MAX_FIND_PITCH_LPC_ORDER ]; + SKP_int32 FiltState[ MAX_FIND_PITCH_LPC_ORDER ]; + SKP_int16 A_Q12[ MAX_FIND_PITCH_LPC_ORDER ]; + + /******************************************/ + /* Setup buffer lengths etc based on Fs */ + /******************************************/ + buf_len = SKP_ADD_LSHIFT( psEnc->sCmn.la_pitch, psEnc->sCmn.frame_length, 1 ); + + /* Safty check */ + SKP_assert( buf_len >= psPredSt->pitch_LPC_win_length ); + + x_buf = x - psEnc->sCmn.frame_length; + + /*************************************/ + /* Estimate LPC AR coefficients */ + /*************************************/ + + /* 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( Wsig_ptr, x_buf_ptr, 1, psEnc->sCmn.la_pitch ); + + /* Middle un - 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 - SKP_LSHIFT( psEnc->sCmn.la_pitch, 1 ) ) * sizeof( SKP_int16 ) ); + + /* Last LA_LTP samples */ + Wsig_ptr += psPredSt->pitch_LPC_win_length - SKP_LSHIFT( psEnc->sCmn.la_pitch, 1 ); + x_buf_ptr += psPredSt->pitch_LPC_win_length - SKP_LSHIFT( psEnc->sCmn.la_pitch, 1 ); + SKP_Silk_apply_sine_window( Wsig_ptr, x_buf_ptr, 2, psEnc->sCmn.la_pitch ); + + /* Calculate autocorrelation sequence */ + SKP_Silk_autocorr( auto_corr, &scale, Wsig, psPredSt->pitch_LPC_win_length, psEnc->sCmn.pitchEstimationLPCOrder + 1 ); + + /* Add white noise, as fraction of energy */ + auto_corr[ 0 ] = SKP_SMLAWB( auto_corr[ 0 ], auto_corr[ 0 ], SKP_FIX_CONST( FIND_PITCH_WHITE_NOISE_FRACTION, 16 ) ); + + /* Calculate the reflection coefficients using schur */ + res_nrg = SKP_Silk_schur( rc_Q15, auto_corr, psEnc->sCmn.pitchEstimationLPCOrder ); + + /* Prediction gain */ + psEncCtrl->predGain_Q16 = SKP_DIV32_varQ( auto_corr[ 0 ], SKP_max_int( res_nrg, 1 ), 16 ); + + /* Convert reflection coefficients to prediction coefficients */ + SKP_Silk_k2a( A_Q24, rc_Q15, psEnc->sCmn.pitchEstimationLPCOrder ); + + /* Convert From 32 bit Q24 to 16 bit Q12 coefs */ + for( i = 0; i < psEnc->sCmn.pitchEstimationLPCOrder; i++ ) { + A_Q12[ i ] = ( SKP_int16 )SKP_SAT16( SKP_RSHIFT( A_Q24[ i ], 12 ) ); + } + + /* Do BWE */ + SKP_Silk_bwexpander( A_Q12, psEnc->sCmn.pitchEstimationLPCOrder, SKP_FIX_CONST( FIND_PITCH_BANDWITH_EXPANSION, 16 ) ); + + /*****************************************/ + /* LPC analysis filtering */ + /*****************************************/ + SKP_memset( FiltState, 0, psEnc->sCmn.pitchEstimationLPCOrder * sizeof( SKP_int32 ) ); /* Not really necessary, but Valgrind will complain otherwise */ + SKP_Silk_MA_Prediction( x_buf, A_Q12, FiltState, res, buf_len, psEnc->sCmn.pitchEstimationLPCOrder ); + SKP_memset( res, 0, psEnc->sCmn.pitchEstimationLPCOrder * sizeof( SKP_int16 ) ); + + /* Threshold for pitch estimator */ + thrhld_Q15 = SKP_FIX_CONST( 0.45, 15 ); + thrhld_Q15 = SKP_SMLABB( thrhld_Q15, SKP_FIX_CONST( -0.004, 15 ), psEnc->sCmn.pitchEstimationLPCOrder ); + thrhld_Q15 = SKP_SMLABB( thrhld_Q15, SKP_FIX_CONST( -0.1, 7 ), psEnc->speech_activity_Q8 ); + thrhld_Q15 = SKP_SMLABB( thrhld_Q15, SKP_FIX_CONST( 0.15, 15 ), psEnc->sCmn.prev_sigtype ); + thrhld_Q15 = SKP_SMLAWB( thrhld_Q15, SKP_FIX_CONST( -0.1, 16 ), psEncCtrl->input_tilt_Q15 ); + thrhld_Q15 = SKP_SAT16( thrhld_Q15 ); + + /*****************************************/ + /* Call pitch estimator */ + /*****************************************/ + psEncCtrl->sCmn.sigtype = SKP_Silk_pitch_analysis_core( res, psEncCtrl->sCmn.pitchL, &psEncCtrl->sCmn.lagIndex, + &psEncCtrl->sCmn.contourIndex, &psEnc->LTPCorr_Q15, psEnc->sCmn.prevLag, psEnc->sCmn.pitchEstimationThreshold_Q16, + ( SKP_int16 )thrhld_Q15, psEnc->sCmn.fs_kHz, psEnc->sCmn.pitchEstimationComplexity, SKP_FALSE ); +} diff --git a/pkg/silk/csilk/SKP_Silk_find_pred_coefs_FIX.c b/pkg/silk/csilk/SKP_Silk_find_pred_coefs_FIX.c new file mode 100644 index 0000000..11764a6 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_find_pred_coefs_FIX.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_FIX.h" + + +void SKP_Silk_find_pred_coefs_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + SKP_Silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + const SKP_int16 res_pitch[] /* I Residual from pitch analysis */ +) +{ + SKP_int i; + SKP_int32 WLTP[ NB_SUBFR * LTP_ORDER * LTP_ORDER ]; + SKP_int32 invGains_Q16[ NB_SUBFR ], local_gains[ NB_SUBFR ], Wght_Q15[ NB_SUBFR ]; + SKP_int NLSF_Q15[ MAX_LPC_ORDER ]; + const SKP_int16 *x_ptr; + SKP_int16 *x_pre_ptr, LPC_in_pre[ NB_SUBFR * MAX_LPC_ORDER + MAX_FRAME_LENGTH ]; + SKP_int32 tmp, min_gain_Q16; + SKP_int LTP_corrs_rshift[ NB_SUBFR ]; + + + /* weighting for weighted least squares */ + min_gain_Q16 = SKP_int32_MAX >> 6; + for( i = 0; i < NB_SUBFR; i++ ) { + min_gain_Q16 = SKP_min( min_gain_Q16, psEncCtrl->Gains_Q16[ i ] ); + } + for( i = 0; i < NB_SUBFR; i++ ) { + /* Divide to Q16 */ + SKP_assert( psEncCtrl->Gains_Q16[ i ] > 0 ); + /* Invert and normalize gains, and ensure that maximum invGains_Q16 is within range of a 16 bit int */ + invGains_Q16[ i ] = SKP_DIV32_varQ( min_gain_Q16, psEncCtrl->Gains_Q16[ i ], 16 - 2 ); + + /* Ensure Wght_Q15 a minimum value 1 */ + invGains_Q16[ i ] = SKP_max( invGains_Q16[ i ], 363 ); + + /* Square the inverted gains */ + SKP_assert( invGains_Q16[ i ] == SKP_SAT16( invGains_Q16[ i ] ) ); + tmp = SKP_SMULWB( invGains_Q16[ i ], invGains_Q16[ i ] ); + Wght_Q15[ i ] = SKP_RSHIFT( tmp, 1 ); + + /* Invert the inverted and normalized gains */ + local_gains[ i ] = SKP_DIV32( ( 1 << 16 ), invGains_Q16[ 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_FIX( psEncCtrl->LTPCoef_Q14, WLTP, &psEncCtrl->LTPredCodGain_Q7, res_pitch, + res_pitch + SKP_RSHIFT( psEnc->sCmn.frame_length, 1 ), psEncCtrl->sCmn.pitchL, Wght_Q15, + psEnc->sCmn.subfr_length, psEnc->sCmn.frame_length, LTP_corrs_rshift ); + + + /* Quantize LTP gain parameters */ + SKP_Silk_quant_LTP_gains_FIX( psEncCtrl->LTPCoef_Q14, psEncCtrl->sCmn.LTPIndex, &psEncCtrl->sCmn.PERIndex, + WLTP, psEnc->mu_LTP_Q8, psEnc->sCmn.LTPQuantLowComplexity ); + + /* Control LTP scaling */ + SKP_Silk_LTP_scale_ctrl_FIX( psEnc, psEncCtrl ); + + /* Create LTP residual */ + SKP_Silk_LTP_analysis_filter_FIX( LPC_in_pre, psEnc->x_buf + psEnc->sCmn.frame_length - psEnc->sCmn.predictLPCOrder, + psEncCtrl->LTPCoef_Q14, psEncCtrl->sCmn.pitchL, invGains_Q16, 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_vector16( x_pre_ptr, x_ptr, invGains_Q16[ 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_Q14, 0, NB_SUBFR * LTP_ORDER * sizeof( SKP_int16 ) ); + psEncCtrl->LTPredCodGain_Q7 = 0; + } + + /* LPC_in_pre contains the LTP-filtered input for voiced, and the unfiltered input for unvoiced */ + TIC(FIND_LPC) + SKP_Silk_find_LPC_FIX( NLSF_Q15, &psEncCtrl->sCmn.NLSFInterpCoef_Q2, psEnc->sPred.prev_NLSFq_Q15, + psEnc->sCmn.useInterpolatedNLSFs * ( 1 - psEnc->sCmn.first_frame_after_reset ), psEnc->sCmn.predictLPCOrder, + LPC_in_pre, psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder ); + TOC(FIND_LPC) + + + /* Quantize LSFs */ + TIC(PROCESS_LSFS) + SKP_Silk_process_NLSFs_FIX( psEnc, psEncCtrl, NLSF_Q15 ); + TOC(PROCESS_LSFS) + + /* Calculate residual energy using quantized LPC coefficients */ + SKP_Silk_residual_energy_FIX( psEncCtrl->ResNrg, psEncCtrl->ResNrgQ, LPC_in_pre, psEncCtrl->PredCoef_Q12, local_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_Q15, NLSF_Q15, psEnc->sCmn.predictLPCOrder * sizeof( SKP_int ) ); + +} + diff --git a/pkg/silk/csilk/SKP_Silk_gain_quant.c b/pkg/silk/csilk/SKP_Silk_gain_quant.c new file mode 100644 index 0000000..c33fe49 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_init_encoder_FIX.c b/pkg/silk/csilk/SKP_Silk_init_encoder_FIX.c new file mode 100644 index 0000000..7fa445c --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_init_encoder_FIX.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_main_FIX.h" + +/*********************************/ +/* Initialize Silk Encoder state */ +/*********************************/ +SKP_int SKP_Silk_init_encoder_FIX( + SKP_Silk_encoder_state_FIX *psEnc /* I/O Pointer to Silk FIX encoder state */ +) { + SKP_int ret = 0; + /* Clear the entire encoder state */ + SKP_memset( psEnc, 0, sizeof( SKP_Silk_encoder_state_FIX ) ); + +#if HIGH_PASS_INPUT + psEnc->variable_HP_smth1_Q15 = 200844; /* = SKP_Silk_log2(70)_Q0; */ + psEnc->variable_HP_smth2_Q15 = 200844; /* = SKP_Silk_log2(70)_Q0; */ +#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/pkg/silk/csilk/SKP_Silk_inner_prod_aligned.c b/pkg/silk/csilk/SKP_Silk_inner_prod_aligned.c new file mode 100644 index 0000000..8e738f2 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_inner_prod_aligned.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_inner_prod_aligned.c * + * * + * * + * Copyright 2008-2010 (c), Skype Limited * + * Date: 080601 * + * */ +#include "SKP_Silk_SigProc_FIX.h" + +/* sum= for(i=0;i6, memory access can be reduced by half. */ + +#if (EMBEDDED_ARM<5) +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_int i; + SKP_int32 sum = 0; + for( i = 0; i < len; i++ ) { + sum = SKP_SMLABB( sum, inVec1[ i ], inVec2[ i ] ); + } + return sum; +} +#endif + +#if (EMBEDDED_ARM<5) +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 */ +) +{ + SKP_int i; + SKP_int64 sum = 0; + for( i = 0; i < len; i++ ) { + sum = SKP_SMLALBB( sum, inVec1[ i ], inVec2[ i ] ); + } + return sum; +} +#endif diff --git a/pkg/silk/csilk/SKP_Silk_interpolate.c b/pkg/silk/csilk/SKP_Silk_interpolate.c new file mode 100644 index 0000000..73b9eb5 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_k2a.c b/pkg/silk/csilk/SKP_Silk_k2a.c new file mode 100644 index 0000000..3d3d19a --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_k2a.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_FIX.h" + +/* 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 */ +) +{ + SKP_int k, n; + SKP_int32 Atmp[ SKP_Silk_MAX_ORDER_LPC ]; + + for( k = 0; k < order; k++ ) { + for( n = 0; n < k; n++ ) { + Atmp[ n ] = A_Q24[ n ]; + } + for( n = 0; n < k; n++ ) { + A_Q24[ n ] = SKP_SMLAWB( A_Q24[ n ], SKP_LSHIFT( Atmp[ k - n - 1 ], 1 ), rc_Q15[ k ] ); + } + A_Q24[ k ] = -SKP_LSHIFT( (SKP_int32)rc_Q15[ k ], 9 ); + } +} diff --git a/pkg/silk/csilk/SKP_Silk_k2a_Q16.c b/pkg/silk/csilk/SKP_Silk_k2a_Q16.c new file mode 100644 index 0000000..176f24e --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_k2a_Q16.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_FIX.h" + +/* 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 */ +) +{ + SKP_int k, n; + SKP_int32 Atmp[ SKP_Silk_MAX_ORDER_LPC ]; + + for( k = 0; k < order; k++ ) { + for( n = 0; n < k; n++ ) { + Atmp[ n ] = A_Q24[ n ]; + } + for( n = 0; n < k; n++ ) { + A_Q24[ n ] = SKP_SMLAWW( A_Q24[ n ], Atmp[ k - n - 1 ], rc_Q16[ k ] ); + } + A_Q24[ k ] = -SKP_LSHIFT( rc_Q16[ k ], 8 ); + } +} diff --git a/pkg/silk/csilk/SKP_Silk_lin2log.c b/pkg/silk/csilk/SKP_Silk_lin2log.c new file mode 100644 index 0000000..b917c97 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_lin2log.c @@ -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. +***********************************************************************/ + +/* * + * 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" +#if EMBEDDED_ARM<4 +/* 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 ) ); +} +#endif + diff --git a/pkg/silk/csilk/SKP_Silk_log2lin.c b/pkg/silk/csilk/SKP_Silk_log2lin.c new file mode 100644 index 0000000..0124c30 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_macros.h b/pkg/silk/csilk/SKP_Silk_macros.h new file mode 100644 index 0000000..9ccd750 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_macros_arm.h b/pkg/silk/csilk/SKP_Silk_macros_arm.h new file mode 100644 index 0000000..4e9d3c2 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_macros_arm.h @@ -0,0 +1,248 @@ +/*********************************************************************** +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_ARM_H_ +#define _SKP_SILK_API_ARM_H_ + +// This is an inline header file for embedded arm platform. + +#if EMBEDDED_ARM==4 +extern SKP_int32 SKP_Silk_CLZ16(SKP_int16 in16); +extern SKP_int32 SKP_Silk_CLZ32(SKP_int32 in32); + +// (a32 * (SKP_int32)((SKP_int16)(b32))) >> 16 +#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 +#define SKP_SMLAWB(a32, b32, c32) ((a32) + ((((b32) >> 16) * (SKP_int32)((SKP_int16)(c32))) + ((((b32) & 0x0000FFFF) * (SKP_int32)((SKP_int16)(c32))) >> 16))) + +/*SKP_INLINE SKP_int32 SKP_SMULWT(SKP_int32 a32, SKP_int32 b32) +{ + SKP_int32 out32, tmp; + SKP_int32 tmp32=0xFFFF0000; + asm volatile("and %1, %3, %4 \n\t smull %3, %0, %2, %1" : "=&r" (out32), "=&r" (tmp) : "r" (a32), "r" (b32), "r" (tmp32)); + return(out32); +}*/ + +// (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)) +#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)) +#define SKP_SMLABB(a32, b32, c32) ((a32) + ((SKP_int32)((SKP_int16)(b32))) * (SKP_int32)((SKP_int16)(c32))) + +// a32 + (SKP_int32)((SKP_int16)(b32)) * (SKP_int32)((SKP_int16)(c32)) +#define SKP_SMLABB_ovflw(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)) + +SKP_INLINE SKP_int64 SKP_SMLAL(SKP_int64 a64, SKP_int32 b32, SKP_int32 c32) +{ +#ifdef IPHONE + // IPHONE LLVM compiler doesn't understand Q/R representation. + a64 = (SKP_int64)b32 * c32; + return(a64); +#else + __asm__ __volatile__ ("smlal %Q0, %R0, %2, %3" : "=r" (a64) : "0" (a64), "r" (b32), "r" (c32)); + return(a64); +#endif +} + +// (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)) + +/* 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)) ) + +#define SKP_SMMUL(a32, b32) (SKP_int32)SKP_RSHIFT64(SKP_SMULL((a32), (b32)), 32) + + +#else +SKP_INLINE SKP_int32 SKP_SMULWB(SKP_int32 a32, SKP_int32 b32) { + SKP_int32 out32; + __asm__ __volatile__ ("smulwb %0, %1, %2" : "=r" (out32) : "r" (a32), "r" (b32)); + return(out32); +} + + +SKP_INLINE SKP_int32 SKP_SMLAWB(SKP_int32 a32, SKP_int32 b32, SKP_int32 c32) { + SKP_int32 out32; + __asm__ __volatile__ ("smlawb %0, %2, %3, %1" : "=r" (out32) : "r" (a32), "r" (b32), "r" (c32)); + return(out32); +} + +SKP_INLINE SKP_int32 SKP_SMULWT(SKP_int32 a32, SKP_int32 b32) +{ + SKP_int32 out32; + __asm__ __volatile__ ("smulwt %0, %1, %2" : "=r" (out32) : "r" (a32), "r" (b32)); + return(out32); +} + +SKP_INLINE SKP_int32 SKP_SMLAWT(SKP_int32 a32, SKP_int32 b32, SKP_int32 c32) +{ + SKP_int32 out32; + __asm__ __volatile__ ("smlawt %0, %2, %3, %1" : "=r" (out32) : "r" (a32), "r" (b32), "r" (c32)); + return(out32); +} + +SKP_INLINE SKP_int32 SKP_SMULBB(SKP_int32 a32, SKP_int32 b32) { + SKP_int32 out32; + __asm__ __volatile__ ("smulbb %0, %1, %2" : "=r" (out32) : "r" (a32), "r" (b32)); + return(out32); +} + +SKP_INLINE SKP_int32 SKP_SMLABB(SKP_int32 a32, SKP_int32 b32, SKP_int32 c32) { + SKP_int32 out32; + __asm__ __volatile__ ("smlabb %0, %2, %3, %1" : "=r" (out32) : "r" (a32), "r" (b32), "r" (c32)); + return(out32); +} + +SKP_INLINE SKP_int32 SKP_SMLABB_ovflw(SKP_int32 a32, SKP_int32 b32, SKP_int32 c32) { + SKP_int32 out32; + __asm__ __volatile__ ("smlabb %0, %2, %3, %1" : "=r" (out32) : "r" (a32), "r" (b32), "r" (c32)); + return(out32); +} + +SKP_INLINE SKP_int32 SKP_SMULBT(SKP_int32 a32, SKP_int32 b32) { + SKP_int32 out32; + __asm__ __volatile__ ("smulbt %0, %1, %2" : "=r" (out32) : "r" (a32), "r" (b32)); + return(out32); +} + +SKP_INLINE SKP_int32 SKP_SMLABT(SKP_int32 a32, SKP_int32 b32, SKP_int32 c32) { + SKP_int32 out32; + __asm__ __volatile__ ("smlabt %0, %2, %3, %1" : "=r" (out32) : "r" (a32), "r" (b32), "r" (c32)); + return(out32); +} + +SKP_INLINE SKP_int64 SKP_SMLAL(SKP_int64 a64, SKP_int32 b32, SKP_int32 c32) +{ +#ifdef IPHONE + // IPHONE LLVM compiler doesn't understand Q/R representation. + a64 = (SKP_int64)b32 * c32; + return(a64); +#else + __asm__ __volatile__ ("smlal %Q0, %R0, %2, %3" : "=r" (a64) : "0" (a64), "r" (b32), "r" (c32)); + return(a64); +#endif +} + +#define SKP_SMULWW(a32, b32) SKP_MLA(SKP_SMULWB((a32), (b32)), (a32), SKP_RSHIFT_ROUND((b32), 16)) + +/*SKP_INLINE SKP_int32 SKP_SMULWW(SKP_int32 a32, SKP_int32 b32) +{ + SKP_int64 tmp; + SKP_int32 out32; + __asm__ __volatile__ ("smull %Q1, %R1, %2, %3 \n\t mov %0, %R1, lsl #16 \n\t add %0, %0, %Q1, lsr #16" : "=&r" (out32), "=&r" (tmp) : "r" (a32), "r" (b32)); + return(out32); +}*/ +#define SKP_SMLAWW(a32, b32, c32) SKP_MLA(SKP_SMLAWB((a32), (b32), (c32)), (b32), SKP_RSHIFT_ROUND((c32), 16)) +/*SKP_INLINE SKP_int32 SKP_SMLAWW(a32, b32, c32){ + SKP_int64 tmp; + SKP_int32 out32; + __asm__ __volatile__ ("smull %Q1, %R1, %3, %4 \n\t add %0, %2, %R1, lsl #16 \n\t add %0, %0, %Q1, lsr #16" : "=&r" (out32), "=&r" (tmp) : "r" (a32), "r" (b32), "r" (c32)); + return(out32); +}*/ + +SKP_INLINE SKP_int32 SKP_ADD_SAT32(SKP_int32 a32, SKP_int32 b32) { + SKP_int32 out32; + __asm__ __volatile__ ("qadd %0, %1, %2" : "=r" (out32) : "r" (a32), "r" (b32)); + return(out32); +} + +SKP_INLINE SKP_int32 SKP_SUB_SAT32(SKP_int32 a32, SKP_int32 b32) { + SKP_int32 out32; + __asm__ __volatile__ ("qsub %0, %1, %2" : "=r" (out32) : "r" (a32), "r" (b32)); + return(out32); +} + +SKP_INLINE SKP_int32 SKP_Silk_CLZ16(SKP_int16 in16) +{ + SKP_int32 out32; + __asm__ __volatile__ ("movs %0, %1, lsl #16 \n\tclz %0, %0 \n\t it eq \n\t moveq %0, #16" : "=r" (out32) : "r" (in16) : "cc"); + return(out32); +} + +SKP_INLINE SKP_int32 SKP_Silk_CLZ32(SKP_int32 in32) +{ + SKP_int32 out32; + __asm__ __volatile__ ("clz %0, %1" : "=r" (out32) : "r" (in32)); + return(out32); +} +#if EMBEDDED_ARM < 6 +#define SKP_SMMUL(a32, b32) (SKP_int32)SKP_RSHIFT64(SKP_SMULL((a32), (b32)), 32) +#endif +#endif + +// Some ARMv6 specific instructions: + +#if EMBEDDED_ARM>=6 + +SKP_INLINE SKP_int32 SKP_SMMUL(SKP_int32 a32, SKP_int32 b32){ + SKP_int32 out32; + __asm__ __volatile__ ("smmul %0, %1, %2" : "=r" (out32) : "r" (a32), "r" (b32)); + return(out32); +} + +SKP_INLINE SKP_int32 SKP_SMUAD(SKP_int32 a32, SKP_int32 b32) +{ + SKP_int32 out32; + __asm__ __volatile__ ("smuad %0, %1, %2" : "=r" (out32) : "r" (a32), "r" (b32)); + return(out32); +} + +SKP_INLINE SKP_int32 SKP_SMLAD(SKP_int32 a32, SKP_int32 b32, SKP_int32 c32) +{ + SKP_int32 out32; + __asm__ __volatile__ ("smlad %0, %2, %3, %1" : "=r" (out32) : "r" (a32), "r" (b32), "r" (c32)); + return(out32); +} + +#endif + +#endif // _SKP_SILK_API_ARM_H_ + + + diff --git a/pkg/silk/csilk/SKP_Silk_main.h b/pkg/silk/csilk/SKP_Silk_main.h new file mode 100644 index 0000000..bba7fa7 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_main_FIX.h b/pkg/silk/csilk/SKP_Silk_main_FIX.h new file mode 100644 index 0000000..4d760a4 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_main_FIX.h @@ -0,0 +1,338 @@ +/*********************************************************************** +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_FIX_H +#define SKP_SILK_MAIN_FIX_H + +#include +#include "SKP_Silk_SigProc_FIX.h" +#include "SKP_Silk_structs_FIX.h" +#include "SKP_Silk_main.h" +#include "SKP_Silk_PLC.h" +#define TIC(TAG_NAME) +#define TOC(TAG_NAME) + +#ifndef FORCE_CPP_BUILD +#ifdef __cplusplus +extern "C" +{ +#endif +#endif + +/*********************/ +/* Encoder Functions */ +/*********************/ + +/* Initializes the Silk encoder state */ +SKP_int SKP_Silk_init_encoder_FIX( + SKP_Silk_encoder_state_FIX *psEnc /* I/O Pointer to Silk FIX encoder state */ +); + +/* Control the Silk encoder */ +SKP_int SKP_Silk_control_encoder_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk encoder state */ + 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) */ +); + +/* Encoder main function */ +SKP_int SKP_Silk_encode_frame_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */ + SKP_uint8 *pCode, /* O Pointer to payload */ + SKP_int16 *pnBytesOut, /* I/O Pointer to number of payload bytes; */ + /* input: max length; output: used */ + const SKP_int16 *pIn /* I Pointer to input speech frame */ +); + +/* Low BitRate Redundancy encoding functionality. Reuse all parameters but encode with lower bitrate */ +void SKP_Silk_LBRR_encode_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */ + SKP_Silk_encoder_control_FIX *psEncCtrl, /* I/O Pointer to Silk FIX encoder control struct */ + SKP_uint8 *pCode, /* O Pointer to payload */ + SKP_int16 *pnBytesOut, /* I/O Pointer to number of payload bytes */ + SKP_int16 xfw[] /* I Input signal */ +); + +/* High-pass filter with cutoff frequency adaptation based on pitch lag statistics */ +void SKP_Silk_HP_variable_cutoff_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Encoder state */ + SKP_Silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control */ + SKP_int16 *out, /* O high-pass filtered output signal */ + const SKP_int16 *in /* I input signal */ +); + +/****************/ +/* Prefiltering */ +/****************/ +void SKP_Silk_prefilter_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Encoder state */ + const SKP_Silk_encoder_control_FIX *psEncCtrl, /* I Encoder control */ + SKP_int16 xw[], /* O Weighted signal */ + const SKP_int16 x[] /* I Speech signal */ +); + +/**************************************************************/ +/* Compute noise shaping coefficients and initial gain values */ +/**************************************************************/ +void SKP_Silk_noise_shape_analysis_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Encoder state FIX */ + SKP_Silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control FIX */ + const SKP_int16 *pitch_res, /* I LPC residual from pitch analysis */ + const SKP_int16 *x /* I Input signal [ frame_length + la_shape ] */ +); + +/* Autocorrelations for a warped frequency axis */ +void SKP_Silk_warped_autocorrelation_FIX( + SKP_int32 *corr, /* O Result [order + 1] */ + SKP_int *scale, /* O Scaling of the correlation vector */ + const SKP_int16 *input, /* I Input data to correlate */ + const SKP_int16 warping_Q16, /* I Warping coefficient */ + const SKP_int length, /* I Length of input */ + const SKP_int order /* I Correlation order (even) */ +); + +/* Processing of gains */ +void SKP_Silk_process_gains_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Encoder state */ + SKP_Silk_encoder_control_FIX *psEncCtrl /* I/O Encoder control */ +); + +/* Control low bitrate redundancy usage */ +void SKP_Silk_LBRR_ctrl_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + SKP_Silk_encoder_control *psEncCtrlC /* I/O encoder control */ +); + +/* Calculation of LTP state scaling */ +void SKP_Silk_LTP_scale_ctrl_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + SKP_Silk_encoder_control_FIX *psEncCtrl /* I/O encoder control */ +); + +/**********************************************/ +/* Prediction Analysis */ +/**********************************************/ + +/* Find pitch lags */ +void SKP_Silk_find_pitch_lags_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + SKP_Silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + SKP_int16 res[], /* O residual */ + const SKP_int16 x[] /* I Speech signal */ +); + +void SKP_Silk_find_pred_coefs_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + SKP_Silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + const SKP_int16 res_pitch[] /* I Residual from pitch analysis */ +); + +void SKP_Silk_find_LPC_FIX( + SKP_int NLSF_Q15[], /* O NLSFs */ + SKP_int *interpIndex, /* O NLSF interpolation index, only used for NLSF interpolation */ + const SKP_int prev_NLSFq_Q15[], /* I previous NLSFs, only used for NLSF interpolation */ + const SKP_int useInterpolatedLSFs, /* I Flag */ + const SKP_int LPC_order, /* I LPC order */ + const SKP_int16 x[], /* I Input signal */ + const SKP_int subfr_length /* I Input signal subframe length including preceeding samples */ +); + +void SKP_Silk_warped_LPC_analysis_filter_FIX( + SKP_int32 state[], /* I/O State [order + 1] */ + SKP_int16 res[], /* O Residual signal [length] */ + const SKP_int16 coef_Q13[], /* I Coefficients [order] */ + const SKP_int16 input[], /* I Input signal [length] */ + const SKP_int16 lambda_Q16, /* I Warping factor */ + const SKP_int length, /* I Length of input signal */ + const SKP_int order /* I Filter order (even) */ +); + +void SKP_Silk_LTP_analysis_filter_FIX( + SKP_int16 *LTP_res, /* O: LTP residual signal of length NB_SUBFR * ( pre_length + subfr_length ) */ + const SKP_int16 *x, /* I: Pointer to input signal with at least max( pitchL ) preceeding samples */ + const SKP_int16 LTPCoef_Q14[ LTP_ORDER * NB_SUBFR ],/* I: LTP_ORDER LTP coefficients for each NB_SUBFR subframe */ + const SKP_int pitchL[ NB_SUBFR ], /* I: Pitch lag, one for each subframe */ + const SKP_int32 invGains_Q16[ NB_SUBFR ], /* I: Inverse quantization gains, one for each subframe */ + const SKP_int subfr_length, /* I: Length of each subframe */ + const SKP_int pre_length /* I: Length of the preceeding samples starting at &x[0] for each subframe */ +); + +/* Finds LTP vector from correlations */ +void SKP_Silk_find_LTP_FIX( + SKP_int16 b_Q14[ NB_SUBFR * LTP_ORDER ], /* O LTP coefs */ + SKP_int32 WLTP[ NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Weight for LTP quantization */ + SKP_int *LTPredCodGain_Q7, /* O LTP coding gain */ + const SKP_int16 r_first[], /* I residual signal after LPC signal + state for first 10 ms */ + const SKP_int16 r_last[], /* I residual signal after LPC signal + state for last 10 ms */ + const SKP_int lag[ NB_SUBFR ], /* I LTP lags */ + const SKP_int32 Wght_Q15[ 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 corr_rshifts[ NB_SUBFR ] /* O right shifts applied to correlations */ +); + +/* LTP tap quantizer */ +void SKP_Silk_quant_LTP_gains_FIX( + SKP_int16 B_Q14[], /* I/O (un)quantized LTP gains */ + SKP_int cbk_index[], /* O Codebook Index */ + SKP_int *periodicity_index, /* O Periodicity Index */ + const SKP_int32 W_Q18[], /* I Error Weights in Q18 */ + SKP_int mu_Q8, /* I Mu value (R/D tradeoff) */ + SKP_int lowComplexity /* I Flag for low complexity */ +); + +/******************/ +/* NLSF Quantizer */ +/******************/ + +/* Limit, stabilize, convert and quantize NLSFs. */ +void SKP_Silk_process_NLSFs_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + SKP_Silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + SKP_int *pNLSF_Q15 /* I/O Normalized LSFs (quant out) (0 - (2^15-1)) */ +); + +/* NLSF vector encoder */ +void SKP_Silk_NLSF_MSVQ_encode_FIX( + SKP_int *NLSFIndices, /* O Codebook path vector [ CB_STAGES ] */ + SKP_int *pNLSF_Q15, /* I/O Quantized NLSF vector [ LPC_ORDER ] */ + const SKP_Silk_NLSF_CB_struct *psNLSF_CB, /* I Codebook object */ + const SKP_int *pNLSF_q_Q15_prev, /* I Prev. quantized NLSF vector [LPC_ORDER] */ + const SKP_int *pW_Q6, /* I NLSF weight vector [ LPC_ORDER ] */ + const SKP_int NLSF_mu_Q15, /* I Rate weight for the RD optimization */ + const SKP_int NLSF_mu_fluc_red_Q16, /* 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 */ +); + +/* Rate-Distortion calculations for multiple input data vectors */ +void SKP_Silk_NLSF_VQ_rate_distortion_FIX( + SKP_int32 *pRD_Q20, /* O Rate-distortion values [psNLSF_CBS->nVectors*N] */ + const SKP_Silk_NLSF_CBS *psNLSF_CBS, /* I NLSF codebook stage struct */ + const SKP_int *in_Q15, /* I Input vectors to be quantized */ + const SKP_int *w_Q6, /* I Weight vector */ + const SKP_int32 *rate_acc_Q5, /* I Accumulated rates from previous stage */ + const SKP_int mu_Q15, /* 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 an LPC_order element input vector, over one codebook stage */ +void SKP_Silk_NLSF_VQ_sum_error_FIX( + SKP_int32 *err_Q20, /* O Weighted quantization errors [N*K] */ + const SKP_int *in_Q15, /* I Input vectors to be quantized [N*LPC_order] */ + const SKP_int *w_Q6, /* I Weighting vectors [N*LPC_order] */ + const SKP_int16 *pCB_Q15, /* 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 Number of LPCs */ +); + +/* Entropy constrained MATRIX-weighted VQ, for a single input data vector */ +void SKP_Silk_VQ_WMat_EC_FIX( + SKP_int *ind, /* O index of best codebook vector */ + SKP_int32 *rate_dist_Q14, /* O best weighted quantization error + mu * rate*/ + const SKP_int16 *in_Q14, /* I input vector to be quantized */ + const SKP_int32 *W_Q18, /* I weighting matrix */ + const SKP_int16 *cb_Q14, /* I codebook */ + const SKP_int16 *cl_Q6, /* I code length for each codebook vector */ + const SKP_int mu_Q8, /* I tradeoff between weighted error and rate */ + SKP_int L /* I number of vectors in codebook */ +); + +/******************/ +/* Linear Algebra */ +/******************/ + +/* Calculates correlation matrix X'*X */ +void SKP_Silk_corrMatrix_FIX( + const SKP_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */ + const SKP_int L, /* I Length of vectors */ + const SKP_int order, /* I Max lag for correlation */ + const SKP_int head_room, /* I Desired headroom */ + SKP_int32 *XX, /* O Pointer to X'*X correlation matrix [ order x order ]*/ + SKP_int *rshifts /* I/O Right shifts of correlations */ +); + +/* Calculates correlation vector X'*t */ +void SKP_Silk_corrVector_FIX( + const SKP_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */ + const SKP_int16 *t, /* I Target vector [L] */ + const SKP_int L, /* I Length of vectors */ + const SKP_int order, /* I Max lag for correlation */ + SKP_int32 *Xt, /* O Pointer to X'*t correlation vector [order] */ + const SKP_int rshifts /* I Right shifts of correlations */ +); + +/* Add noise to matrix diagonal */ +void SKP_Silk_regularize_correlations_FIX( + SKP_int32 *XX, /* I/O Correlation matrices */ + SKP_int32 *xx, /* I/O Correlation values */ + SKP_int32 noise, /* I Noise to add */ + SKP_int D /* I Dimension of XX */ +); + +/* Solves Ax = b, assuming A is symmetric */ +void SKP_Silk_solve_LDL_FIX( + SKP_int32 *A, /* I Pointer to symetric square matrix A */ + SKP_int M, /* I Size of matrix */ + const SKP_int32 *b, /* I Pointer to b vector */ + SKP_int32 *x_Q16 /* O Pointer to x solution vector */ +); + +/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */ +SKP_int32 SKP_Silk_residual_energy16_covar_FIX( + const SKP_int16 *c, /* I Prediction vector */ + const SKP_int32 *wXX, /* I Correlation matrix */ + const SKP_int32 *wXx, /* I Correlation vector */ + SKP_int32 wxx, /* I Signal energy */ + SKP_int D, /* I Dimension */ + SKP_int cQ /* I Q value for c vector 0 - 15 */ +); + +/* Calculates residual energies of input subframes where all subframes have LPC_order */ +/* of preceeding samples */ +void SKP_Silk_residual_energy_FIX( + SKP_int32 nrgs[ NB_SUBFR ], /* O Residual energy per subframe */ + SKP_int nrgsQ[ NB_SUBFR ], /* O Q value per subframe */ + const SKP_int16 x[], /* I Input signal */ + SKP_int16 a_Q12[ 2 ][ MAX_LPC_ORDER ],/* I AR coefs for each frame half */ + const SKP_int32 gains[ NB_SUBFR ], /* I Quantization gains */ + const SKP_int subfr_length, /* I Subframe length */ + const SKP_int LPC_order /* I LPC order */ +); + +#ifndef FORCE_CPP_BUILD +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* FORCE_CPP_BUILD */ +#endif /* SKP_SILK_MAIN_FIX_H */ diff --git a/pkg/silk/csilk/SKP_Silk_noise_shape_analysis_FIX.c b/pkg/silk/csilk/SKP_Silk_noise_shape_analysis_FIX.c new file mode 100644 index 0000000..459cc69 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_noise_shape_analysis_FIX.c @@ -0,0 +1,477 @@ +/*********************************************************************** +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_FIX.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_int32 warped_gain( // gain in Q16 + const SKP_int32 *coefs_Q24, + SKP_int lambda_Q16, + SKP_int order +) { + SKP_int i; + SKP_int32 gain_Q24; + + lambda_Q16 = -lambda_Q16; + gain_Q24 = coefs_Q24[ order - 1 ]; + for( i = order - 2; i >= 0; i-- ) { + gain_Q24 = SKP_SMLAWB( coefs_Q24[ i ], gain_Q24, lambda_Q16 ); + } + gain_Q24 = SKP_SMLAWB( SKP_FIX_CONST( 1.0, 24 ), gain_Q24, -lambda_Q16 ); + return SKP_INVERSE32_varQ( gain_Q24, 40 ); +} + +/* 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 limit_warped_coefs( + SKP_int32 *coefs_syn_Q24, + SKP_int32 *coefs_ana_Q24, + SKP_int lambda_Q16, + SKP_int32 limit_Q24, + SKP_int order +) { + SKP_int i, iter, ind = 0; + SKP_int32 tmp, maxabs_Q24, chirp_Q16, gain_syn_Q16, gain_ana_Q16; + SKP_int32 nom_Q16, den_Q24; + + /* Convert to monic coefficients */ + lambda_Q16 = -lambda_Q16; + for( i = order - 1; i > 0; i-- ) { + coefs_syn_Q24[ i - 1 ] = SKP_SMLAWB( coefs_syn_Q24[ i - 1 ], coefs_syn_Q24[ i ], lambda_Q16 ); + coefs_ana_Q24[ i - 1 ] = SKP_SMLAWB( coefs_ana_Q24[ i - 1 ], coefs_ana_Q24[ i ], lambda_Q16 ); + } + lambda_Q16 = -lambda_Q16; + nom_Q16 = SKP_SMLAWB( SKP_FIX_CONST( 1.0, 16 ), -lambda_Q16, lambda_Q16 ); + den_Q24 = SKP_SMLAWB( SKP_FIX_CONST( 1.0, 24 ), coefs_syn_Q24[ 0 ], lambda_Q16 ); + gain_syn_Q16 = SKP_DIV32_varQ( nom_Q16, den_Q24, 24 ); + den_Q24 = SKP_SMLAWB( SKP_FIX_CONST( 1.0, 24 ), coefs_ana_Q24[ 0 ], lambda_Q16 ); + gain_ana_Q16 = SKP_DIV32_varQ( nom_Q16, den_Q24, 24 ); + for( i = 0; i < order; i++ ) { + coefs_syn_Q24[ i ] = SKP_SMULWW( gain_syn_Q16, coefs_syn_Q24[ i ] ); + coefs_ana_Q24[ i ] = SKP_SMULWW( gain_ana_Q16, coefs_ana_Q24[ i ] ); + } + + for( iter = 0; iter < 10; iter++ ) { + /* Find maximum absolute value */ + maxabs_Q24 = -1; + for( i = 0; i < order; i++ ) { + tmp = SKP_max( SKP_abs_int32( coefs_syn_Q24[ i ] ), SKP_abs_int32( coefs_ana_Q24[ i ] ) ); + if( tmp > maxabs_Q24 ) { + maxabs_Q24 = tmp; + ind = i; + } + } + if( maxabs_Q24 <= limit_Q24 ) { + /* Coefficients are within range - done */ + return; + } + + /* Convert back to true warped coefficients */ + for( i = 1; i < order; i++ ) { + coefs_syn_Q24[ i - 1 ] = SKP_SMLAWB( coefs_syn_Q24[ i - 1 ], coefs_syn_Q24[ i ], lambda_Q16 ); + coefs_ana_Q24[ i - 1 ] = SKP_SMLAWB( coefs_ana_Q24[ i - 1 ], coefs_ana_Q24[ i ], lambda_Q16 ); + } + gain_syn_Q16 = SKP_INVERSE32_varQ( gain_syn_Q16, 32 ); + gain_ana_Q16 = SKP_INVERSE32_varQ( gain_ana_Q16, 32 ); + for( i = 0; i < order; i++ ) { + coefs_syn_Q24[ i ] = SKP_SMULWW( gain_syn_Q16, coefs_syn_Q24[ i ] ); + coefs_ana_Q24[ i ] = SKP_SMULWW( gain_ana_Q16, coefs_ana_Q24[ i ] ); + } + + /* Apply bandwidth expansion */ + chirp_Q16 = SKP_FIX_CONST( 0.99, 16 ) - SKP_DIV32_varQ( + SKP_SMULWB( maxabs_Q24 - limit_Q24, SKP_SMLABB( SKP_FIX_CONST( 0.8, 10 ), SKP_FIX_CONST( 0.1, 10 ), iter ) ), + SKP_MUL( maxabs_Q24, ind + 1 ), 22 ); + SKP_Silk_bwexpander_32( coefs_syn_Q24, order, chirp_Q16 ); + SKP_Silk_bwexpander_32( coefs_ana_Q24, order, chirp_Q16 ); + + /* Convert to monic warped coefficients */ + lambda_Q16 = -lambda_Q16; + for( i = order - 1; i > 0; i-- ) { + coefs_syn_Q24[ i - 1 ] = SKP_SMLAWB( coefs_syn_Q24[ i - 1 ], coefs_syn_Q24[ i ], lambda_Q16 ); + coefs_ana_Q24[ i - 1 ] = SKP_SMLAWB( coefs_ana_Q24[ i - 1 ], coefs_ana_Q24[ i ], lambda_Q16 ); + } + lambda_Q16 = -lambda_Q16; + nom_Q16 = SKP_SMLAWB( SKP_FIX_CONST( 1.0, 16 ), -lambda_Q16, lambda_Q16 ); + den_Q24 = SKP_SMLAWB( SKP_FIX_CONST( 1.0, 24 ), coefs_syn_Q24[ 0 ], lambda_Q16 ); + gain_syn_Q16 = SKP_DIV32_varQ( nom_Q16, den_Q24, 24 ); + den_Q24 = SKP_SMLAWB( SKP_FIX_CONST( 1.0, 24 ), coefs_ana_Q24[ 0 ], lambda_Q16 ); + gain_ana_Q16 = SKP_DIV32_varQ( nom_Q16, den_Q24, 24 ); + for( i = 0; i < order; i++ ) { + coefs_syn_Q24[ i ] = SKP_SMULWW( gain_syn_Q16, coefs_syn_Q24[ i ] ); + coefs_ana_Q24[ i ] = SKP_SMULWW( gain_ana_Q16, coefs_ana_Q24[ i ] ); + } + } + SKP_assert( 0 ); +} + +/**************************************************************/ +/* Compute noise shaping coefficients and initial gain values */ +/**************************************************************/ +void SKP_Silk_noise_shape_analysis_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Encoder state FIX */ + SKP_Silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control FIX */ + const SKP_int16 *pitch_res, /* I LPC residual from pitch analysis */ + const SKP_int16 *x /* I Input signal [ frame_length + la_shape ] */ +) +{ + SKP_Silk_shape_state_FIX *psShapeSt = &psEnc->sShape; + SKP_int k, i, nSamples, Qnrg, b_Q14, warping_Q16, scale = 0; + SKP_int32 SNR_adj_dB_Q7, HarmBoost_Q16, HarmShapeGain_Q16, Tilt_Q16, tmp32; + SKP_int32 nrg, pre_nrg_Q30, log_energy_Q7, log_energy_prev_Q7, energy_variation_Q7; + SKP_int32 delta_Q16, BWExp1_Q16, BWExp2_Q16, gain_mult_Q16, gain_add_Q16, strength_Q16, b_Q8; + SKP_int32 auto_corr[ MAX_SHAPE_LPC_ORDER + 1 ]; + SKP_int32 refl_coef_Q16[ MAX_SHAPE_LPC_ORDER ]; + SKP_int32 AR1_Q24[ MAX_SHAPE_LPC_ORDER ]; + SKP_int32 AR2_Q24[ MAX_SHAPE_LPC_ORDER ]; + SKP_int16 x_windowed[ SHAPE_LPC_WIN_MAX ]; + const SKP_int16 *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_Q7 = psEnc->SNR_dB_Q7 - SKP_SMULWB( SKP_LSHIFT( ( SKP_int32 )psEnc->BufferedInChannel_ms, 7 ), + SKP_FIX_CONST( 0.05, 16 ) ); + + /* Reduce SNR_dB if inband FEC used */ + if( psEnc->speech_activity_Q8 > SKP_FIX_CONST( LBRR_SPEECH_ACTIVITY_THRES, 8 ) ) { + psEncCtrl->current_SNR_dB_Q7 -= SKP_RSHIFT( psEnc->inBandFEC_SNR_comp_Q8, 1 ); + } + + /****************/ + /* GAIN CONTROL */ + /****************/ + /* Input quality is the average of the quality in the lowest two VAD bands */ + psEncCtrl->input_quality_Q14 = ( SKP_int )SKP_RSHIFT( ( SKP_int32 )psEncCtrl->input_quality_bands_Q15[ 0 ] + + psEncCtrl->input_quality_bands_Q15[ 1 ], 2 ); + + /* Coding quality level, between 0.0_Q0 and 1.0_Q0, but in Q14 */ + psEncCtrl->coding_quality_Q14 = SKP_RSHIFT( SKP_Silk_sigm_Q15( SKP_RSHIFT_ROUND( psEncCtrl->current_SNR_dB_Q7 - + SKP_FIX_CONST( 18.0, 7 ), 4 ) ), 1 ); + + /* Reduce coding SNR during low speech activity */ + b_Q8 = SKP_FIX_CONST( 1.0, 8 ) - psEnc->speech_activity_Q8; + b_Q8 = SKP_SMULWB( SKP_LSHIFT( b_Q8, 8 ), b_Q8 ); + SNR_adj_dB_Q7 = SKP_SMLAWB( psEncCtrl->current_SNR_dB_Q7, + SKP_SMULBB( SKP_FIX_CONST( -BG_SNR_DECR_dB, 7 ) >> ( 4 + 1 ), b_Q8 ), // Q11 + SKP_SMULWB( SKP_FIX_CONST( 1.0, 14 ) + psEncCtrl->input_quality_Q14, psEncCtrl->coding_quality_Q14 ) ); // Q12 + + if( psEncCtrl->sCmn.sigtype == SIG_TYPE_VOICED ) { + /* Reduce gains for periodic signals */ + SNR_adj_dB_Q7 = SKP_SMLAWB( SNR_adj_dB_Q7, SKP_FIX_CONST( HARM_SNR_INCR_dB, 8 ), psEnc->LTPCorr_Q15 ); + } else { + /* For unvoiced signals and low-quality input, adjust the quality slower than SNR_dB setting */ + SNR_adj_dB_Q7 = SKP_SMLAWB( SNR_adj_dB_Q7, + SKP_SMLAWB( SKP_FIX_CONST( 6.0, 9 ), -SKP_FIX_CONST( 0.4, 18 ), psEncCtrl->current_SNR_dB_Q7 ), + SKP_FIX_CONST( 1.0, 14 ) - psEncCtrl->input_quality_Q14 ); + } + + /*************************/ + /* 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_Q8 = 0; + } else { + /* Sparseness measure, based on relative fluctuations of energy per 2 milliseconds */ + nSamples = SKP_LSHIFT( psEnc->sCmn.fs_kHz, 1 ); + energy_variation_Q7 = 0; + log_energy_prev_Q7 = 0; + pitch_res_ptr = pitch_res; + for( k = 0; k < FRAME_LENGTH_MS / 2; k++ ) { + SKP_Silk_sum_sqr_shift( &nrg, &scale, pitch_res_ptr, nSamples ); + nrg += SKP_RSHIFT( nSamples, scale ); // Q(-scale) + + log_energy_Q7 = SKP_Silk_lin2log( nrg ); + if( k > 0 ) { + energy_variation_Q7 += SKP_abs( log_energy_Q7 - log_energy_prev_Q7 ); + } + log_energy_prev_Q7 = log_energy_Q7; + pitch_res_ptr += nSamples; + } + + psEncCtrl->sparseness_Q8 = SKP_RSHIFT( SKP_Silk_sigm_Q15( SKP_SMULWB( energy_variation_Q7 - + SKP_FIX_CONST( 5.0, 7 ), SKP_FIX_CONST( 0.1, 16 ) ) ), 7 ); + + /* Set quantization offset depending on sparseness measure */ + if( psEncCtrl->sparseness_Q8 > SKP_FIX_CONST( SPARSENESS_THRESHOLD_QNT_OFFSET, 8 ) ) { + psEncCtrl->sCmn.QuantOffsetType = 0; + } else { + psEncCtrl->sCmn.QuantOffsetType = 1; + } + + /* Increase coding SNR for sparse signals */ + SNR_adj_dB_Q7 = SKP_SMLAWB( SNR_adj_dB_Q7, SKP_FIX_CONST( SPARSE_SNR_INCR_dB, 15 ), psEncCtrl->sparseness_Q8 - SKP_FIX_CONST( 0.5, 8 ) ); + } + + /*******************************/ + /* Control bandwidth expansion */ + /*******************************/ + /* More BWE for signals with high prediction gain */ + strength_Q16 = SKP_SMULWB( psEncCtrl->predGain_Q16, SKP_FIX_CONST( FIND_PITCH_WHITE_NOISE_FRACTION, 16 ) ); + BWExp1_Q16 = BWExp2_Q16 = SKP_DIV32_varQ( SKP_FIX_CONST( BANDWIDTH_EXPANSION, 16 ), + SKP_SMLAWW( SKP_FIX_CONST( 1.0, 16 ), strength_Q16, strength_Q16 ), 16 ); + delta_Q16 = SKP_SMULWB( SKP_FIX_CONST( 1.0, 16 ) - SKP_SMULBB( 3, psEncCtrl->coding_quality_Q14 ), + SKP_FIX_CONST( LOW_RATE_BANDWIDTH_EXPANSION_DELTA, 16 ) ); + BWExp1_Q16 = SKP_SUB32( BWExp1_Q16, delta_Q16 ); + BWExp2_Q16 = SKP_ADD32( BWExp2_Q16, delta_Q16 ); + /* BWExp1 will be applied after BWExp2, so make it relative */ + BWExp1_Q16 = SKP_DIV32_16( SKP_LSHIFT( BWExp1_Q16, 14 ), SKP_RSHIFT( BWExp2_Q16, 2 ) ); + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Slightly more warping in analysis will move quantization noise up in frequency, where it's better masked */ + warping_Q16 = SKP_SMLAWB( psEnc->sCmn.warping_Q16, psEncCtrl->coding_quality_Q14, SKP_FIX_CONST( 0.01, 18 ) ); + } else { + warping_Q16 = 0; + } + + /********************************************/ + /* 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 = SKP_RSHIFT( psEnc->sCmn.shapeWinLength - flat_part, 1 ); + + SKP_Silk_apply_sine_window( x_windowed, x_ptr, 1, slope_part ); + shift = slope_part; + SKP_memcpy( x_windowed + shift, x_ptr + shift, flat_part * sizeof(SKP_int16) ); + shift += flat_part; + SKP_Silk_apply_sine_window( 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_FIX( auto_corr, &scale, x_windowed, warping_Q16, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder ); + } else { + /* Calculate regular auto correlation */ + SKP_Silk_autocorr( auto_corr, &scale, x_windowed, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder + 1 ); + } + + /* Add white noise, as a fraction of energy */ + auto_corr[0] = SKP_ADD32( auto_corr[0], SKP_max_32( SKP_SMULWB( SKP_RSHIFT( auto_corr[ 0 ], 4 ), + SKP_FIX_CONST( SHAPE_WHITE_NOISE_FRACTION, 20 ) ), 1 ) ); + + /* Calculate the reflection coefficients using schur */ + nrg = SKP_Silk_schur64( refl_coef_Q16, auto_corr, psEnc->sCmn.shapingLPCOrder ); + SKP_assert( nrg >= 0 ); + + /* Convert reflection coefficients to prediction coefficients */ + SKP_Silk_k2a_Q16( AR2_Q24, refl_coef_Q16, psEnc->sCmn.shapingLPCOrder ); + + Qnrg = -scale; // range: -12...30 + SKP_assert( Qnrg >= -12 ); + SKP_assert( Qnrg <= 30 ); + + /* Make sure that Qnrg is an even number */ + if( Qnrg & 1 ) { + Qnrg -= 1; + nrg >>= 1; + } + + tmp32 = SKP_Silk_SQRT_APPROX( nrg ); + Qnrg >>= 1; // range: -6...15 + + psEncCtrl->Gains_Q16[ k ] = SKP_LSHIFT_SAT32( tmp32, 16 - Qnrg ); + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Adjust gain for warping */ + gain_mult_Q16 = warped_gain( AR2_Q24, warping_Q16, psEnc->sCmn.shapingLPCOrder ); + SKP_assert( psEncCtrl->Gains_Q16[ k ] >= 0 ); + psEncCtrl->Gains_Q16[ k ] = SKP_SMULWW( psEncCtrl->Gains_Q16[ k ], gain_mult_Q16 ); + if( psEncCtrl->Gains_Q16[ k ] < 0 ) { + psEncCtrl->Gains_Q16[ k ] = SKP_int32_MAX; + } + } + + /* Bandwidth expansion for synthesis filter shaping */ + SKP_Silk_bwexpander_32( AR2_Q24, psEnc->sCmn.shapingLPCOrder, BWExp2_Q16 ); + + /* Compute noise shaping filter coefficients */ + SKP_memcpy( AR1_Q24, AR2_Q24, psEnc->sCmn.shapingLPCOrder * sizeof( SKP_int32 ) ); + + /* Bandwidth expansion for analysis filter shaping */ + SKP_assert( BWExp1_Q16 <= SKP_FIX_CONST( 1.0, 16 ) ); + SKP_Silk_bwexpander_32( AR1_Q24, psEnc->sCmn.shapingLPCOrder, BWExp1_Q16 ); + + /* Ratio of prediction gains, in energy domain */ + SKP_Silk_LPC_inverse_pred_gain_Q24( &pre_nrg_Q30, AR2_Q24, psEnc->sCmn.shapingLPCOrder ); + SKP_Silk_LPC_inverse_pred_gain_Q24( &nrg, AR1_Q24, psEnc->sCmn.shapingLPCOrder ); + + //psEncCtrl->GainsPre[ k ] = 1.0f - 0.7f * ( 1.0f - pre_nrg / nrg ) = 0.3f + 0.7f * pre_nrg / nrg; + pre_nrg_Q30 = SKP_LSHIFT32( SKP_SMULWB( pre_nrg_Q30, SKP_FIX_CONST( 0.7, 15 ) ), 1 ); + psEncCtrl->GainsPre_Q14[ k ] = ( SKP_int ) SKP_FIX_CONST( 0.3, 14 ) + SKP_DIV32_varQ( pre_nrg_Q30, nrg, 14 ); + + /* Convert to monic warped prediction coefficients and limit absolute values */ + limit_warped_coefs( AR2_Q24, AR1_Q24, warping_Q16, SKP_FIX_CONST( 3.999, 24 ), psEnc->sCmn.shapingLPCOrder ); + + /* Convert from Q24 to Q13 and store in int16 */ + for( i = 0; i < psEnc->sCmn.shapingLPCOrder; i++ ) { + psEncCtrl->AR1_Q13[ k * MAX_SHAPE_LPC_ORDER + i ] = (SKP_int16)SKP_SAT16( SKP_RSHIFT_ROUND( AR1_Q24[ i ], 11 ) ); + psEncCtrl->AR2_Q13[ k * MAX_SHAPE_LPC_ORDER + i ] = (SKP_int16)SKP_SAT16( SKP_RSHIFT_ROUND( AR2_Q24[ i ], 11 ) ); + } + } + + /*****************/ + /* Gain tweaking */ + /*****************/ + /* Increase gains during low speech activity and put lower limit on gains */ + gain_mult_Q16 = SKP_Silk_log2lin( -SKP_SMLAWB( -SKP_FIX_CONST( 16.0, 7 ), SNR_adj_dB_Q7, SKP_FIX_CONST( 0.16, 16 ) ) ); + gain_add_Q16 = SKP_Silk_log2lin( SKP_SMLAWB( SKP_FIX_CONST( 16.0, 7 ), SKP_FIX_CONST( NOISE_FLOOR_dB, 7 ), SKP_FIX_CONST( 0.16, 16 ) ) ); + tmp32 = SKP_Silk_log2lin( SKP_SMLAWB( SKP_FIX_CONST( 16.0, 7 ), SKP_FIX_CONST( RELATIVE_MIN_GAIN_dB, 7 ), SKP_FIX_CONST( 0.16, 16 ) ) ); + tmp32 = SKP_SMULWW( psEnc->avgGain_Q16, tmp32 ); + gain_add_Q16 = SKP_ADD_SAT32( gain_add_Q16, tmp32 ); + SKP_assert( gain_mult_Q16 >= 0 ); + + for( k = 0; k < NB_SUBFR; k++ ) { + psEncCtrl->Gains_Q16[ k ] = SKP_SMULWW( psEncCtrl->Gains_Q16[ k ], gain_mult_Q16 ); + if( psEncCtrl->Gains_Q16[ k ] < 0 ) { + psEncCtrl->Gains_Q16[ k ] = SKP_int32_MAX; + } + } + + for( k = 0; k < NB_SUBFR; k++ ) { + psEncCtrl->Gains_Q16[ k ] = SKP_ADD_POS_SAT32( psEncCtrl->Gains_Q16[ k ], gain_add_Q16 ); + psEnc->avgGain_Q16 = SKP_ADD_SAT32( + psEnc->avgGain_Q16, + SKP_SMULWB( + psEncCtrl->Gains_Q16[ k ] - psEnc->avgGain_Q16, + SKP_RSHIFT_ROUND( SKP_SMULBB( psEnc->speech_activity_Q8, SKP_FIX_CONST( GAIN_SMOOTHING_COEF, 10 ) ), 2 ) + ) ); + } + + /************************************************/ + /* Decrease level during fricatives (de-essing) */ + /************************************************/ + gain_mult_Q16 = SKP_FIX_CONST( 1.0, 16 ) + SKP_RSHIFT_ROUND( SKP_MLA( SKP_FIX_CONST( INPUT_TILT, 26 ), + psEncCtrl->coding_quality_Q14, SKP_FIX_CONST( HIGH_RATE_INPUT_TILT, 12 ) ), 10 ); + + if( psEncCtrl->input_tilt_Q15 <= 0 && psEncCtrl->sCmn.sigtype == SIG_TYPE_UNVOICED ) { + if( psEnc->sCmn.fs_kHz == 24 ) { + SKP_int32 essStrength_Q15 = SKP_SMULWW( -psEncCtrl->input_tilt_Q15, + SKP_SMULBB( psEnc->speech_activity_Q8, SKP_FIX_CONST( 1.0, 8 ) - psEncCtrl->sparseness_Q8 ) ); + tmp32 = SKP_Silk_log2lin( SKP_FIX_CONST( 16.0, 7 ) - SKP_SMULWB( essStrength_Q15, + SKP_SMULWB( SKP_FIX_CONST( DE_ESSER_COEF_SWB_dB, 7 ), SKP_FIX_CONST( 0.16, 17 ) ) ) ); + gain_mult_Q16 = SKP_SMULWW( gain_mult_Q16, tmp32 ); + } else if( psEnc->sCmn.fs_kHz == 16 ) { + SKP_int32 essStrength_Q15 = SKP_SMULWW(-psEncCtrl->input_tilt_Q15, + SKP_SMULBB( psEnc->speech_activity_Q8, SKP_FIX_CONST( 1.0, 8 ) - psEncCtrl->sparseness_Q8 )); + tmp32 = SKP_Silk_log2lin( SKP_FIX_CONST( 16.0, 7 ) - SKP_SMULWB( essStrength_Q15, + SKP_SMULWB( SKP_FIX_CONST( DE_ESSER_COEF_WB_dB, 7 ), SKP_FIX_CONST( 0.16, 17 ) ) ) ); + gain_mult_Q16 = SKP_SMULWW( gain_mult_Q16, tmp32 ); + } else { + SKP_assert( psEnc->sCmn.fs_kHz == 12 || psEnc->sCmn.fs_kHz == 8 ); + } + } + + for( k = 0; k < NB_SUBFR; k++ ) { + psEncCtrl->GainsPre_Q14[ k ] = SKP_SMULWB( gain_mult_Q16, psEncCtrl->GainsPre_Q14[ k ] ); + } + + /************************************************/ + /* Control low-frequency shaping and noise tilt */ + /************************************************/ + /* Less low frequency shaping for noisy inputs */ + strength_Q16 = SKP_MUL( SKP_FIX_CONST( LOW_FREQ_SHAPING, 0 ), SKP_FIX_CONST( 1.0, 16 ) + + SKP_SMULBB( SKP_FIX_CONST( LOW_QUALITY_LOW_FREQ_SHAPING_DECR, 1 ), psEncCtrl->input_quality_bands_Q15[ 0 ] - SKP_FIX_CONST( 1.0, 15 ) ) ); + 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])*/ + SKP_int fs_kHz_inv = SKP_DIV32_16( SKP_FIX_CONST( 0.2, 14 ), psEnc->sCmn.fs_kHz ); + for( k = 0; k < NB_SUBFR; k++ ) { + b_Q14 = fs_kHz_inv + SKP_DIV32_16( SKP_FIX_CONST( 3.0, 14 ), psEncCtrl->sCmn.pitchL[ k ] ); + /* Pack two coefficients in one int32 */ + psEncCtrl->LF_shp_Q14[ k ] = SKP_LSHIFT( SKP_FIX_CONST( 1.0, 14 ) - b_Q14 - SKP_SMULWB( strength_Q16, b_Q14 ), 16 ); + psEncCtrl->LF_shp_Q14[ k ] |= (SKP_uint16)( b_Q14 - SKP_FIX_CONST( 1.0, 14 ) ); + } + SKP_assert( SKP_FIX_CONST( HARM_HP_NOISE_COEF, 24 ) < SKP_FIX_CONST( 0.5, 24 ) ); // Guarantees that second argument to SMULWB() is within range of an SKP_int16 + Tilt_Q16 = - SKP_FIX_CONST( HP_NOISE_COEF, 16 ) - + SKP_SMULWB( SKP_FIX_CONST( 1.0, 16 ) - SKP_FIX_CONST( HP_NOISE_COEF, 16 ), + SKP_SMULWB( SKP_FIX_CONST( HARM_HP_NOISE_COEF, 24 ), psEnc->speech_activity_Q8 ) ); + } else { + b_Q14 = SKP_DIV32_16( 21299, psEnc->sCmn.fs_kHz ); // 1.3_Q0 = 21299_Q14 + /* Pack two coefficients in one int32 */ + psEncCtrl->LF_shp_Q14[ 0 ] = SKP_LSHIFT( SKP_FIX_CONST( 1.0, 14 ) - b_Q14 - + SKP_SMULWB( strength_Q16, SKP_SMULWB( SKP_FIX_CONST( 0.6, 16 ), b_Q14 ) ), 16 ); + psEncCtrl->LF_shp_Q14[ 0 ] |= (SKP_uint16)( b_Q14 - SKP_FIX_CONST( 1.0, 14 ) ); + for( k = 1; k < NB_SUBFR; k++ ) { + psEncCtrl->LF_shp_Q14[ k ] = psEncCtrl->LF_shp_Q14[ 0 ]; + } + Tilt_Q16 = -SKP_FIX_CONST( HP_NOISE_COEF, 16 ); + } + + /****************************/ + /* HARMONIC SHAPING CONTROL */ + /****************************/ + /* Control boosting of harmonic frequencies */ + HarmBoost_Q16 = SKP_SMULWB( SKP_SMULWB( SKP_FIX_CONST( 1.0, 17 ) - SKP_LSHIFT( psEncCtrl->coding_quality_Q14, 3 ), + psEnc->LTPCorr_Q15 ), SKP_FIX_CONST( LOW_RATE_HARMONIC_BOOST, 16 ) ); + + /* More harmonic boost for noisy input signals */ + HarmBoost_Q16 = SKP_SMLAWB( HarmBoost_Q16, + SKP_FIX_CONST( 1.0, 16 ) - SKP_LSHIFT( psEncCtrl->input_quality_Q14, 2 ), SKP_FIX_CONST( LOW_INPUT_QUALITY_HARMONIC_BOOST, 16 ) ); + + if( USE_HARM_SHAPING && psEncCtrl->sCmn.sigtype == SIG_TYPE_VOICED ) { + /* More harmonic noise shaping for high bitrates or noisy input */ + HarmShapeGain_Q16 = SKP_SMLAWB( SKP_FIX_CONST( HARMONIC_SHAPING, 16 ), + SKP_FIX_CONST( 1.0, 16 ) - SKP_SMULWB( SKP_FIX_CONST( 1.0, 18 ) - SKP_LSHIFT( psEncCtrl->coding_quality_Q14, 4 ), + psEncCtrl->input_quality_Q14 ), SKP_FIX_CONST( HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING, 16 ) ); + + /* Less harmonic noise shaping for less periodic signals */ + HarmShapeGain_Q16 = SKP_SMULWB( SKP_LSHIFT( HarmShapeGain_Q16, 1 ), + SKP_Silk_SQRT_APPROX( SKP_LSHIFT( psEnc->LTPCorr_Q15, 15 ) ) ); + } else { + HarmShapeGain_Q16 = 0; + } + + /*************************/ + /* Smooth over subframes */ + /*************************/ + for( k = 0; k < NB_SUBFR; k++ ) { + psShapeSt->HarmBoost_smth_Q16 = + SKP_SMLAWB( psShapeSt->HarmBoost_smth_Q16, HarmBoost_Q16 - psShapeSt->HarmBoost_smth_Q16, SKP_FIX_CONST( SUBFR_SMTH_COEF, 16 ) ); + psShapeSt->HarmShapeGain_smth_Q16 = + SKP_SMLAWB( psShapeSt->HarmShapeGain_smth_Q16, HarmShapeGain_Q16 - psShapeSt->HarmShapeGain_smth_Q16, SKP_FIX_CONST( SUBFR_SMTH_COEF, 16 ) ); + psShapeSt->Tilt_smth_Q16 = + SKP_SMLAWB( psShapeSt->Tilt_smth_Q16, Tilt_Q16 - psShapeSt->Tilt_smth_Q16, SKP_FIX_CONST( SUBFR_SMTH_COEF, 16 ) ); + + psEncCtrl->HarmBoost_Q14[ k ] = ( SKP_int )SKP_RSHIFT_ROUND( psShapeSt->HarmBoost_smth_Q16, 2 ); + psEncCtrl->HarmShapeGain_Q14[ k ] = ( SKP_int )SKP_RSHIFT_ROUND( psShapeSt->HarmShapeGain_smth_Q16, 2 ); + psEncCtrl->Tilt_Q14[ k ] = ( SKP_int )SKP_RSHIFT_ROUND( psShapeSt->Tilt_smth_Q16, 2 ); + } +} diff --git a/pkg/silk/csilk/SKP_Silk_pitch_analysis_core.c b/pkg/silk/csilk/SKP_Silk_pitch_analysis_core.c new file mode 100644 index 0000000..7000ff4 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_pitch_analysis_core.c @@ -0,0 +1,706 @@ +/*********************************************************************** +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_pitch_est_defines.h" +#include "SKP_Silk_common_pitch_est_defines.h" + +#define SCRATCH_SIZE 22 + +/************************************************************/ +/* Internally used functions */ +/************************************************************/ +void SKP_FIX_P_Ana_calc_corr_st3( + SKP_int32 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_int16 signal[], /* I vector to correlate */ + SKP_int start_lag, /* I lag offset to search around */ + SKP_int sf_length, /* I length of a 5 ms subframe */ + SKP_int complexity /* I Complexity setting */ +); + +void SKP_FIX_P_Ana_calc_energy_st3( + SKP_int32 energies_st3[PITCH_EST_NB_SUBFR][PITCH_EST_NB_CBKS_STAGE3_MAX][PITCH_EST_NB_STAGE3_LAGS],/* (O) 3 DIM energy array */ + const SKP_int16 signal[], /* I vector to calc energy in */ + SKP_int start_lag, /* I lag offset to search around */ + SKP_int sf_length, /* I length of one 5 ms subframe */ + SKP_int complexity /* I Complexity setting */ +); + +SKP_int32 SKP_FIX_P_Ana_find_scaling( + const SKP_int16 *signal, + const SKP_int signal_length, + const SKP_int sum_sqr_len +); + +/*************************************************************/ +/* FIXED POINT CORE PITCH ANALYSIS FUNCTION */ +/*************************************************************/ +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. */ +) +{ + SKP_int16 signal_8kHz[ PITCH_EST_MAX_FRAME_LENGTH_ST_2 ]; + SKP_int16 signal_4kHz[ PITCH_EST_MAX_FRAME_LENGTH_ST_1 ]; + SKP_int32 scratch_mem[ 3 * PITCH_EST_MAX_FRAME_LENGTH ]; + SKP_int16 *input_signal_ptr; + SKP_int32 filt_state[ PITCH_EST_MAX_DECIMATE_STATE_LENGTH ]; + SKP_int i, k, d, j; + SKP_int16 C[ PITCH_EST_NB_SUBFR ][ ( PITCH_EST_MAX_LAG >> 1 ) + 5 ]; + const SKP_int16 *target_ptr, *basis_ptr; + SKP_int32 cross_corr, normalizer, energy, shift, energy_basis, energy_target; + SKP_int d_srch[ PITCH_EST_D_SRCH_LENGTH ]; + SKP_int16 d_comp[ ( PITCH_EST_MAX_LAG >> 1 ) + 5 ]; + SKP_int Cmax, length_d_srch, length_d_comp; + SKP_int32 sum, threshold, temp32; + SKP_int CBimax, CBimax_new, CBimax_old, lag, start_lag, end_lag, lag_new; + SKP_int32 CC[ PITCH_EST_NB_CBKS_STAGE2_EXT ], CCmax, CCmax_b, CCmax_new_b, CCmax_new; + SKP_int32 energies_st3[ PITCH_EST_NB_SUBFR ][ PITCH_EST_NB_CBKS_STAGE3_MAX ][ PITCH_EST_NB_STAGE3_LAGS ]; + SKP_int32 crosscorr_st3[ PITCH_EST_NB_SUBFR ][ PITCH_EST_NB_CBKS_STAGE3_MAX ][ PITCH_EST_NB_STAGE3_LAGS ]; + SKP_int32 lag_counter; + SKP_int frame_length, frame_length_8kHz, frame_length_4kHz, max_sum_sq_length; + 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_int32 contour_bias, diff; + SKP_int32 lz, lshift; + SKP_int cbk_offset, cbk_size, nb_cbks_stage2; + SKP_int32 delta_lag_log2_sqr_Q7, lag_log2_Q7, prevLag_log2_Q7, prev_lag_bias_Q15, corr_thres_Q15; + + /* 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_Q16 >= 0 && search_thres1_Q16 <= (1<<16) ); + SKP_assert( search_thres2_Q15 >= 0 && search_thres2_Q15 <= (1<<15) ); + + /* 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_int16 ) * PITCH_EST_NB_SUBFR * ( ( PITCH_EST_MAX_LAG >> 1 ) + 5) ); + + /* Resample from input sampled at Fs_kHz to 8 kHz */ + if( Fs_kHz == 16 ) { + SKP_memset( filt_state, 0, 2 * sizeof( SKP_int32 ) ); + SKP_Silk_resampler_down2( filt_state, signal_8kHz, signal, frame_length ); + } else if ( Fs_kHz == 12 ) { + SKP_int32 R23[ 6 ]; + SKP_memset( R23, 0, 6 * sizeof( SKP_int32 ) ); + SKP_Silk_resampler_down2_3( R23, signal_8kHz, signal, PITCH_EST_FRAME_LENGTH_MS * 12 ); + } else if( Fs_kHz == 24 ) { + SKP_int32 filt_state_fix[ 8 ]; + SKP_memset( filt_state_fix, 0, 8 * sizeof(SKP_int32) ); + SKP_Silk_resampler_down3( filt_state_fix, signal_8kHz, signal, 24 * PITCH_EST_FRAME_LENGTH_MS ); + } else { + SKP_assert( Fs_kHz == 8 ); + SKP_memcpy( signal_8kHz, signal, frame_length_8kHz * sizeof(SKP_int16) ); + } + /* Decimate again to 4 kHz */ + SKP_memset( filt_state, 0, 2 * sizeof( SKP_int32 ) );/* Set state to zero */ + SKP_Silk_resampler_down2( filt_state, signal_4kHz, signal_8kHz, frame_length_8kHz ); + + /* Low-pass filter */ + for( i = frame_length_4kHz - 1; i > 0; i-- ) { + signal_4kHz[ i ] = SKP_ADD_SAT16( signal_4kHz[ i ], signal_4kHz[ i - 1 ] ); + } + + /******************************************************************************* + ** Scale 4 kHz signal down to prevent correlations measures from overflowing + ** find scaling as max scaling for each 8kHz(?) subframe + *******************************************************************************/ + + /* Inner product is calculated with different lengths, so scale for the worst case */ + max_sum_sq_length = SKP_max_32( sf_length_8kHz, SKP_RSHIFT( frame_length_4kHz, 1 ) ); + shift = SKP_FIX_P_Ana_find_scaling( signal_4kHz, frame_length_4kHz, max_sum_sq_length ); + if( shift > 0 ) { + for( i = 0; i < frame_length_4kHz; i++ ) { + signal_4kHz[ i ] = SKP_RSHIFT( signal_4kHz[ i ], shift ); + } + } + + /****************************************************************************** + * 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 ); + + normalizer = 0; + cross_corr = 0; + /* Calculate first vector products before loop */ + cross_corr = SKP_Silk_inner_prod_aligned( target_ptr, basis_ptr, sf_length_8kHz ); + normalizer = SKP_Silk_inner_prod_aligned( basis_ptr, basis_ptr, sf_length_8kHz ); + normalizer = SKP_ADD_SAT32( normalizer, SKP_SMULBB( sf_length_8kHz, 4000 ) ); + + temp32 = SKP_DIV32( cross_corr, SKP_Silk_SQRT_APPROX( normalizer ) + 1 ); + C[ k ][ min_lag_4kHz ] = (SKP_int16)SKP_SAT16( temp32 ); /* Q0 */ + + /* 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_prod_aligned( target_ptr, basis_ptr, sf_length_8kHz ); + + /* Add contribution of new sample and remove contribution from oldest sample */ + normalizer += + SKP_SMULBB( basis_ptr[ 0 ], basis_ptr[ 0 ] ) - + SKP_SMULBB( basis_ptr[ sf_length_8kHz ], basis_ptr[ sf_length_8kHz ] ); + + temp32 = SKP_DIV32( cross_corr, SKP_Silk_SQRT_APPROX( normalizer ) + 1 ); + C[ k ][ d ] = (SKP_int16)SKP_SAT16( temp32 ); /* Q0 */ + } + /* Update target pointer */ + target_ptr += sf_length_8kHz; + } + + /* Combine two subframes into single correlation measure and apply short-lag bias */ + for( i = max_lag_4kHz; i >= min_lag_4kHz; i-- ) { + sum = (SKP_int32)C[ 0 ][ i ] + (SKP_int32)C[ 1 ][ i ]; /* Q0 */ + SKP_assert( SKP_RSHIFT( sum, 1 ) == SKP_SAT16( SKP_RSHIFT( sum, 1 ) ) ); + sum = SKP_RSHIFT( sum, 1 ); /* Q-1 */ + SKP_assert( SKP_LSHIFT( (SKP_int32)-i, 4 ) == SKP_SAT16( SKP_LSHIFT( (SKP_int32)-i, 4 ) ) ); + sum = SKP_SMLAWB( sum, sum, SKP_LSHIFT( -i, 4 ) ); /* Q-1 */ + SKP_assert( sum == SKP_SAT16( sum ) ); + C[ 0 ][ i ] = (SKP_int16)sum; /* Q-1 */ + } + + /* Sort */ + length_d_srch = 4 + 2 * complexity; + SKP_assert( 3 * length_d_srch <= PITCH_EST_D_SRCH_LENGTH ); + SKP_Silk_insertion_sort_decreasing_int16( &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 */ + target_ptr = &signal_4kHz[ SKP_RSHIFT( frame_length_4kHz, 1 ) ]; + energy = SKP_Silk_inner_prod_aligned( target_ptr, target_ptr, SKP_RSHIFT( frame_length_4kHz, 1 ) ); + energy = SKP_ADD_POS_SAT32( energy, 1000 ); /* Q0 */ + Cmax = (SKP_int)C[ 0 ][ min_lag_4kHz ]; /* Q-1 */ + threshold = SKP_SMULBB( Cmax, Cmax ); /* Q-2 */ + /* Compare in Q-2 domain */ + if( SKP_RSHIFT( energy, 4 + 2 ) > threshold ) { + SKP_memset( pitch_out, 0, PITCH_EST_NB_SUBFR * sizeof( SKP_int ) ); + *LTPCorr_Q15 = 0; + *lagIndex = 0; + *contourIndex = 0; + return 1; + } + + threshold = SKP_SMULWB( search_thres1_Q16, 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 ] = ( 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 + *************************************************************************************/ + + /****************************************************************************** + ** Scale signal down to avoid correlations measures from overflowing + *******************************************************************************/ + /* find scaling as max scaling for each subframe */ + shift = SKP_FIX_P_Ana_find_scaling( signal_8kHz, frame_length_8kHz, sf_length_8kHz ); + if( shift > 0 ) { + for( i = 0; i < frame_length_8kHz; i++ ) { + signal_8kHz[ i ] = SKP_RSHIFT( signal_8kHz[ i ], shift ); + } + } + + /********************************************************************************* + * 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_int16 ) ); + + 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_target = SKP_Silk_inner_prod_aligned( target_ptr, target_ptr, sf_length_8kHz ); + // ToDo: Calculate 1 / energy_target here and save one division inside next for loop + 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_prod_aligned( target_ptr, basis_ptr, sf_length_8kHz ); + energy_basis = SKP_Silk_inner_prod_aligned( basis_ptr, basis_ptr, sf_length_8kHz ); + if( cross_corr > 0 ) { + energy = SKP_max( energy_target, energy_basis ); /* Find max to make sure first division < 1.0 */ + lz = SKP_Silk_CLZ32( cross_corr ); + lshift = SKP_LIMIT_32( lz - 1, 0, 15 ); + temp32 = SKP_DIV32( SKP_LSHIFT( cross_corr, lshift ), SKP_RSHIFT( energy, 15 - lshift ) + 1 ); /* Q15 */ + SKP_assert( temp32 == SKP_SAT16( temp32 ) ); + temp32 = SKP_SMULWB( cross_corr, temp32 ); /* Q(-1), cc * ( cc / max(b, t) ) */ + temp32 = SKP_ADD_SAT32( temp32, temp32 ); /* Q(0) */ + lz = SKP_Silk_CLZ32( temp32 ); + lshift = SKP_LIMIT_32( lz - 1, 0, 15 ); + energy = SKP_min( energy_target, energy_basis ); + C[ k ][ d ] = SKP_DIV32( SKP_LSHIFT( temp32, lshift ), SKP_RSHIFT( energy, 15 - lshift ) + 1 ); // Q15 + } else { + C[ k ][ d ] = 0; + } + } + target_ptr += sf_length_8kHz; + } + + /* search over lag range and lags codebook */ + /* scale factor for lag codebook, as a function of center lag */ + + CCmax = SKP_int32_MIN; + CCmax_b = SKP_int32_MIN; + + 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_DIV32_16( SKP_LSHIFT( prevLag, 1 ), 3 ); + } else if( Fs_kHz == 16 ) { + prevLag = SKP_RSHIFT( prevLag, 1 ); + } else if( Fs_kHz == 24 ) { + prevLag = SKP_DIV32_16( prevLag, 3 ); + } + prevLag_log2_Q7 = SKP_Silk_lin2log( (SKP_int32)prevLag ); + } else { + prevLag_log2_Q7 = 0; + } + SKP_assert( search_thres2_Q15 == SKP_SAT16( search_thres2_Q15 ) ); + corr_thres_Q15 = SKP_RSHIFT( SKP_SMULBB( search_thres2_Q15, search_thres2_Q15 ), 13 ); + + /* 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; + for( i = 0; i < PITCH_EST_NB_SUBFR; i++ ) { + /* Try all codebooks */ + CC[ j ] = CC[ j ] + (SKP_int32)C[ i ][ d + SKP_Silk_CB_lags_stage2[ i ][ j ] ]; + } + } + /* Find best codebook */ + CCmax_new = SKP_int32_MIN; + CBimax_new = 0; + for( i = 0; i < nb_cbks_stage2; i++ ) { + if( CC[ i ] > CCmax_new ) { + CCmax_new = CC[ i ]; + CBimax_new = i; + } + } + + /* Bias towards shorter lags */ + lag_log2_Q7 = SKP_Silk_lin2log( (SKP_int32)d ); /* Q7 */ + SKP_assert( lag_log2_Q7 == SKP_SAT16( lag_log2_Q7 ) ); + SKP_assert( PITCH_EST_NB_SUBFR * PITCH_EST_SHORTLAG_BIAS_Q15 == SKP_SAT16( PITCH_EST_NB_SUBFR * PITCH_EST_SHORTLAG_BIAS_Q15 ) ); + + if (forLJC) { + CCmax_new_b = CCmax_new; + } else { + CCmax_new_b = CCmax_new - SKP_RSHIFT( SKP_SMULBB( PITCH_EST_NB_SUBFR * PITCH_EST_SHORTLAG_BIAS_Q15, lag_log2_Q7 ), 7 ); /* Q15 */ + } + + /* Bias towards previous lag */ + SKP_assert( PITCH_EST_NB_SUBFR * PITCH_EST_PREVLAG_BIAS_Q15 == SKP_SAT16( PITCH_EST_NB_SUBFR * PITCH_EST_PREVLAG_BIAS_Q15 ) ); + if( prevLag > 0 ) { + delta_lag_log2_sqr_Q7 = lag_log2_Q7 - prevLag_log2_Q7; + SKP_assert( delta_lag_log2_sqr_Q7 == SKP_SAT16( delta_lag_log2_sqr_Q7 ) ); + delta_lag_log2_sqr_Q7 = SKP_RSHIFT( SKP_SMULBB( delta_lag_log2_sqr_Q7, delta_lag_log2_sqr_Q7 ), 7 ); + prev_lag_bias_Q15 = SKP_RSHIFT( SKP_SMULBB( PITCH_EST_NB_SUBFR * PITCH_EST_PREVLAG_BIAS_Q15, ( *LTPCorr_Q15 ) ), 15 ); /* Q15 */ + prev_lag_bias_Q15 = SKP_DIV32( SKP_MUL( prev_lag_bias_Q15, delta_lag_log2_sqr_Q7 ), delta_lag_log2_sqr_Q7 + ( 1 << 6 ) ); + CCmax_new_b -= prev_lag_bias_Q15; /* Q15 */ + } + + if ( CCmax_new_b > CCmax_b && /* Find maximum biased correlation */ + CCmax_new > corr_thres_Q15 && /* 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_Q15 = 0; + *lagIndex = 0; + *contourIndex = 0; + return 1; + } + + if( Fs_kHz > 8 ) { + + /****************************************************************************** + ** Scale input signal down to avoid correlations measures from overflowing + *******************************************************************************/ + /* find scaling as max scaling for each subframe */ + shift = SKP_FIX_P_Ana_find_scaling( signal, frame_length, sf_length ); + if( shift > 0 ) { + /* Move signal to scratch mem because the input signal should be unchanged */ + /* Reuse the 32 bit scratch mem vector, use a 16 bit pointer from now */ + input_signal_ptr = (SKP_int16*)scratch_mem; + for( i = 0; i < frame_length; i++ ) { + input_signal_ptr[ i ] = SKP_RSHIFT( signal[ i ], shift ); + } + } else { + input_signal_ptr = (SKP_int16*)signal; + } + /*********************************************************************************/ + + /* Search in original signal */ + + CBimax_old = CBimax; + /* Compensate for decimation */ + SKP_assert( lag == SKP_SAT16( lag ) ); + if( Fs_kHz == 12 ) { + lag = SKP_RSHIFT( 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( SKP_LSHIFT( CCmax, 13 ) >= 0 ); + *LTPCorr_Q15 = (SKP_int)SKP_Silk_SQRT_APPROX( SKP_LSHIFT( CCmax, 13 ) ); /* Output normalized correlation */ + + CCmax = SKP_int32_MIN; + /* pitch lags according to second stage */ + for( k = 0; k < PITCH_EST_NB_SUBFR; k++ ) { + pitch_out[ k ] = lag + 2 * SKP_Silk_CB_lags_stage2[ k ][ CBimax_old ]; + } + /* Calculate the correlations and energies needed in stage 3 */ + SKP_FIX_P_Ana_calc_corr_st3( crosscorr_st3, input_signal_ptr, start_lag, sf_length, complexity ); + SKP_FIX_P_Ana_calc_energy_st3( energies_st3, input_signal_ptr, start_lag, sf_length, complexity ); + + lag_counter = 0; + SKP_assert( lag == SKP_SAT16( lag ) ); + contour_bias = SKP_DIV32_16( PITCH_EST_FLATCONTOUR_BIAS_Q20, 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; + energy = 0; + for( k = 0; k < PITCH_EST_NB_SUBFR; k++ ) { + SKP_assert( PITCH_EST_NB_SUBFR == 4 ); + energy += SKP_RSHIFT( energies_st3[ k ][ j ][ lag_counter ], 2 ); /* use mean, to avoid overflow */ + SKP_assert( energy >= 0 ); + cross_corr += SKP_RSHIFT( crosscorr_st3[ k ][ j ][ lag_counter ], 2 ); /* use mean, to avoid overflow */ + } + if( cross_corr > 0 ) { + /* Divide cross_corr / energy and get result in Q15 */ + lz = SKP_Silk_CLZ32( cross_corr ); + /* Divide with result in Q13, cross_corr could be larger than energy */ + lshift = SKP_LIMIT_32( lz - 1, 0, 13 ); + CCmax_new = SKP_DIV32( SKP_LSHIFT( cross_corr, lshift ), SKP_RSHIFT( energy, 13 - lshift ) + 1 ); + CCmax_new = SKP_SAT16( CCmax_new ); + CCmax_new = SKP_SMULWB( cross_corr, CCmax_new ); + /* Saturate */ + if( CCmax_new > SKP_RSHIFT( SKP_int32_MAX, 3 ) ) { + CCmax_new = SKP_int32_MAX; + } else { + CCmax_new = SKP_LSHIFT( CCmax_new, 3 ); + } + /* Reduce depending on flatness of contour */ + diff = j - SKP_RSHIFT( PITCH_EST_NB_CBKS_STAGE3_MAX, 1 ); + diff = SKP_MUL( diff, diff ); + diff = SKP_int16_MAX - SKP_RSHIFT( SKP_MUL( contour_bias, diff ), 5 ); /* Q20 -> Q15 */ + SKP_assert( diff == SKP_SAT16( diff ) ); + CCmax_new = SKP_LSHIFT( SKP_SMULWB( CCmax_new, diff ), 1 ); + } else { + CCmax_new = 0; + } + + 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_Silk_CB_lags_stage3[ k ][ CBimax ]; + } + *lagIndex = lag_new - min_lag; + *contourIndex = CBimax; + } else { + /* Save Lags and correlation */ + CCmax = SKP_max( CCmax, 0 ); + *LTPCorr_Q15 = (SKP_int)SKP_Silk_SQRT_APPROX( SKP_LSHIFT( CCmax, 13 ) ); /* 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_8kHz; + *contourIndex = CBimax; + } + SKP_assert( *lagIndex >= 0 ); + /* return as voiced */ + return 0; +} + +/*************************************************************************/ +/* Calculates the correlations used in stage 3 search. In order to cover */ +/* the whole lag codebook for all the searched offset lags (lag +- 2), */ +/*************************************************************************/ +void SKP_FIX_P_Ana_calc_corr_st3( + SKP_int32 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_int16 signal[], /* I vector to correlate */ + SKP_int start_lag, /* I lag offset to search around */ + SKP_int sf_length, /* I length of a 5 ms subframe */ + SKP_int complexity /* I Complexity setting */ +) +{ + const SKP_int16 *target_ptr, *basis_ptr; + SKP_int32 cross_corr; + SKP_int i, j, k, lag_counter; + SKP_int cbk_offset, cbk_size, delta, idx; + SKP_int32 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 ); + cross_corr = SKP_Silk_inner_prod_aligned( (SKP_int16*)target_ptr, (SKP_int16*)basis_ptr, sf_length ); + SKP_assert( lag_counter < SCRATCH_SIZE ); + scratch_mem[ lag_counter ] = cross_corr; + 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; + } +} + +/********************************************************************/ +/* Calculate the energies for first two subframes. The energies are */ +/* calculated recursively. */ +/********************************************************************/ +void SKP_FIX_P_Ana_calc_energy_st3( + SKP_int32 energies_st3[ PITCH_EST_NB_SUBFR ][ PITCH_EST_NB_CBKS_STAGE3_MAX ][ PITCH_EST_NB_STAGE3_LAGS ],/* (O) 3 DIM energy array */ + const SKP_int16 signal[], /* I vector to calc energy in */ + SKP_int start_lag, /* I lag offset to search around */ + SKP_int sf_length, /* I length of one 5 ms subframe */ + SKP_int complexity /* I Complexity setting */ +) +{ + const SKP_int16 *target_ptr, *basis_ptr; + SKP_int32 energy; + SKP_int k, i, j, lag_counter; + SKP_int cbk_offset, cbk_size, delta, idx; + SKP_int32 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_inner_prod_aligned( basis_ptr, basis_ptr, sf_length ); + SKP_assert( energy >= 0 ); + scratch_mem[ lag_counter ] = 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 -= SKP_SMULBB( basis_ptr[ sf_length - i ], basis_ptr[ sf_length - i ] ); + SKP_assert( energy >= 0 ); + + /* add part that comes into window */ + energy = SKP_ADD_SAT32( energy, SKP_SMULBB( basis_ptr[ -i ], basis_ptr[ -i ] ) ); + SKP_assert( energy >= 0 ); + SKP_assert( lag_counter < SCRATCH_SIZE ); + scratch_mem[ lag_counter ] = energy; + 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; + } +} + +SKP_int32 SKP_FIX_P_Ana_find_scaling( + const SKP_int16 *signal, + const SKP_int signal_length, + const SKP_int sum_sqr_len +) +{ + SKP_int32 nbits, x_max; + + x_max = SKP_Silk_int16_array_maxabs( signal, signal_length ); + + if( x_max < SKP_int16_MAX ) { + /* Number of bits needed for the sum of the squares */ + nbits = 32 - SKP_Silk_CLZ32( SKP_SMULBB( x_max, x_max ) ); + } else { + /* Here we don't know if x_max should have been SKP_int16_MAX + 1, so we expect the worst case */ + nbits = 30; + } + nbits += 17 - SKP_Silk_CLZ16( sum_sqr_len ); + + /* Without a guarantee of saturation, we need to keep the 31st bit free */ + if( nbits < 31 ) { + return 0; + } else { + return( nbits - 30 ); + } +} diff --git a/pkg/silk/csilk/SKP_Silk_pitch_est_defines.h b/pkg/silk/csilk/SKP_Silk_pitch_est_defines.h new file mode 100644 index 0000000..df299b4 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_pitch_est_tables.c b/pkg/silk/csilk/SKP_Silk_pitch_est_tables.c new file mode 100644 index 0000000..26902b3 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_prefilter_FIX.c b/pkg/silk/csilk/SKP_Silk_prefilter_FIX.c new file mode 100644 index 0000000..7b626b9 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_prefilter_FIX.c @@ -0,0 +1,224 @@ +/*********************************************************************** +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_FIX.h" +#include "SKP_Silk_tuning_parameters.h" + +/* SKP_Silk_prefilter. Prefilter for finding Quantizer input signal */ +SKP_INLINE void SKP_Silk_prefilt_FIX( + SKP_Silk_prefilter_state_FIX *P, /* I/O state */ + SKP_int32 st_res_Q12[], /* I short term residual signal */ + SKP_int16 xw[], /* O prefiltered signal */ + SKP_int32 HarmShapeFIRPacked_Q12, /* I Harmonic shaping coeficients */ + SKP_int Tilt_Q14, /* I Tilt shaping coeficient */ + SKP_int32 LF_shp_Q14, /* I Low-frequancy shaping coeficients*/ + SKP_int lag, /* I Lag for harmonic shaping */ + SKP_int length /* I Length of signals */ +); +#if EMBEDDED_ARM<6 +void SKP_Silk_warped_LPC_analysis_filter_FIX( + SKP_int32 state[], /* I/O State [order + 1] */ + SKP_int16 res[], /* O Residual signal [length] */ + const SKP_int16 coef_Q13[], /* I Coefficients [order] */ + const SKP_int16 input[], /* I Input signal [length] */ + const SKP_int16 lambda_Q16, /* 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_int32 acc_Q11, tmp1, tmp2; + + /* Order must be even */ + SKP_assert( ( order & 1 ) == 0 ); + + for( n = 0; n < length; n++ ) { + /* Output of lowpass section */ + tmp2 = SKP_SMLAWB( state[ 0 ], state[ 1 ], lambda_Q16 ); + state[ 0 ] = SKP_LSHIFT( input[ n ], 14 ); + /* Output of allpass section */ + tmp1 = SKP_SMLAWB( state[ 1 ], state[ 2 ] - tmp2, lambda_Q16 ); + state[ 1 ] = tmp2; + acc_Q11 = SKP_SMULWB( tmp2, coef_Q13[ 0 ] ); + /* Loop over allpass sections */ + for( i = 2; i < order; i += 2 ) { + /* Output of allpass section */ + tmp2 = SKP_SMLAWB( state[ i ], state[ i + 1 ] - tmp1, lambda_Q16 ); + state[ i ] = tmp1; + acc_Q11 = SKP_SMLAWB( acc_Q11, tmp1, coef_Q13[ i - 1 ] ); + /* Output of allpass section */ + tmp1 = SKP_SMLAWB( state[ i + 1 ], state[ i + 2 ] - tmp2, lambda_Q16 ); + state[ i + 1 ] = tmp2; + acc_Q11 = SKP_SMLAWB( acc_Q11, tmp2, coef_Q13[ i ] ); + } + state[ order ] = tmp1; + acc_Q11 = SKP_SMLAWB( acc_Q11, tmp1, coef_Q13[ order - 1 ] ); + res[ n ] = ( SKP_int16 )SKP_SAT16( ( SKP_int32 )input[ n ] - SKP_RSHIFT_ROUND( acc_Q11, 11 ) ); + } +} +#endif + +void SKP_Silk_prefilter_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Encoder state FIX */ + const SKP_Silk_encoder_control_FIX *psEncCtrl, /* I Encoder control FIX */ + SKP_int16 xw[], /* O Weighted signal */ + const SKP_int16 x[] /* I Speech signal */ +) +{ + SKP_Silk_prefilter_state_FIX *P = &psEnc->sPrefilt; + SKP_int j, k, lag; + SKP_int32 tmp_32; + const SKP_int16 *AR1_shp_Q13; + const SKP_int16 *px; + SKP_int16 *pxw; + SKP_int HarmShapeGain_Q12, Tilt_Q14; + SKP_int32 HarmShapeFIRPacked_Q12, LF_shp_Q14; + SKP_int32 x_filt_Q12[ MAX_FRAME_LENGTH / NB_SUBFR ]; + SKP_int16 st_res[ ( MAX_FRAME_LENGTH / NB_SUBFR ) + MAX_SHAPE_LPC_ORDER ]; +#if !defined(_SYSTEM_IS_BIG_ENDIAN) + SKP_int32 B_Q12; +#else + SKP_int16 B_Q12[ 2 ]; +#endif + + /* Setup 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_Q12 = SKP_SMULWB( psEncCtrl->HarmShapeGain_Q14[ k ], 16384 - psEncCtrl->HarmBoost_Q14[ k ] ); + SKP_assert( HarmShapeGain_Q12 >= 0 ); + HarmShapeFIRPacked_Q12 = SKP_RSHIFT( HarmShapeGain_Q12, 2 ); + HarmShapeFIRPacked_Q12 |= SKP_LSHIFT( ( SKP_int32 )SKP_RSHIFT( HarmShapeGain_Q12, 1 ), 16 ); + Tilt_Q14 = psEncCtrl->Tilt_Q14[ k ]; + LF_shp_Q14 = psEncCtrl->LF_shp_Q14[ k ]; + AR1_shp_Q13 = &psEncCtrl->AR1_Q13[ k * MAX_SHAPE_LPC_ORDER ]; + + /* Short term FIR filtering*/ + SKP_Silk_warped_LPC_analysis_filter_FIX( P->sAR_shp, st_res, AR1_shp_Q13, px, + psEnc->sCmn.warping_Q16, psEnc->sCmn.subfr_length, psEnc->sCmn.shapingLPCOrder ); + + /* reduce (mainly) low frequencies during harmonic emphasis */ +#if !defined(_SYSTEM_IS_BIG_ENDIAN) + /* NOTE: the code below loads two int16 values in an int32, and multiplies each using the */ + /* SMLABB and SMLABT instructions. On a big-endian CPU the two int16 variables would be */ + /* loaded in reverse order and the code will give the wrong result. In that case swapping */ + /* the SMLABB and SMLABT instructions should solve the problem. */ + B_Q12 = SKP_RSHIFT_ROUND( psEncCtrl->GainsPre_Q14[ k ], 2 ); + tmp_32 = SKP_SMLABB( SKP_FIX_CONST( INPUT_TILT, 26 ), psEncCtrl->HarmBoost_Q14[ k ], HarmShapeGain_Q12 ); /* Q26 */ + tmp_32 = SKP_SMLABB( tmp_32, psEncCtrl->coding_quality_Q14, SKP_FIX_CONST( HIGH_RATE_INPUT_TILT, 12 ) ); /* Q26 */ + tmp_32 = SKP_SMULWB( tmp_32, -psEncCtrl->GainsPre_Q14[ k ] ); /* Q24 */ + tmp_32 = SKP_RSHIFT_ROUND( tmp_32, 12 ); /* Q12 */ + B_Q12 |= SKP_LSHIFT( SKP_SAT16( tmp_32 ), 16 ); + + x_filt_Q12[ 0 ] = SKP_SMLABT( SKP_SMULBB( st_res[ 0 ], B_Q12 ), P->sHarmHP, B_Q12 ); + for( j = 1; j < psEnc->sCmn.subfr_length; j++ ) { + x_filt_Q12[ j ] = SKP_SMLABT( SKP_SMULBB( st_res[ j ], B_Q12 ), st_res[ j - 1 ], B_Q12 ); + } +#else + B_Q12[ 0 ] = SKP_RSHIFT_ROUND( psEncCtrl->GainsPre_Q14[ k ], 2 ); + tmp_32 = SKP_SMLABB( SKP_FIX_CONST( INPUT_TILT, 26 ), psEncCtrl->HarmBoost_Q14[ k ], HarmShapeGain_Q12 ); /* Q26 */ + tmp_32 = SKP_SMLABB( tmp_32, psEncCtrl->coding_quality_Q14, SKP_FIX_CONST( HIGH_RATE_INPUT_TILT, 12 ) ); /* Q26 */ + tmp_32 = SKP_SMULWB( tmp_32, -psEncCtrl->GainsPre_Q14[ k ] ); /* Q24 */ + tmp_32 = SKP_RSHIFT_ROUND( tmp_32, 12 ); /* Q12 */ + B_Q12[ 1 ]= SKP_SAT16( tmp_32 ); + + x_filt_Q12[ 0 ] = SKP_SMLABB( SKP_SMULBB( st_res[ 0 ], B_Q12[ 0 ] ), P->sHarmHP, B_Q12[ 1 ] ); + for( j = 1; j < psEnc->sCmn.subfr_length; j++ ) { + x_filt_Q12[ j ] = SKP_SMLABB( SKP_SMULBB( st_res[ j ], B_Q12[ 0 ] ), st_res[ j - 1 ], B_Q12[ 1 ] ); + } +#endif + P->sHarmHP = st_res[ psEnc->sCmn.subfr_length - 1 ]; + + SKP_Silk_prefilt_FIX( P, x_filt_Q12, pxw, HarmShapeFIRPacked_Q12, Tilt_Q14, + LF_shp_Q14, lag, psEnc->sCmn.subfr_length ); + + px += psEnc->sCmn.subfr_length; + pxw += psEnc->sCmn.subfr_length; + } + + P->lagPrev = psEncCtrl->sCmn.pitchL[ NB_SUBFR - 1 ]; +} + +/* SKP_Silk_prefilter. Prefilter for finding Quantizer input signal */ +SKP_INLINE void SKP_Silk_prefilt_FIX( + SKP_Silk_prefilter_state_FIX *P, /* I/O state */ + SKP_int32 st_res_Q12[], /* I short term residual signal */ + SKP_int16 xw[], /* O prefiltered signal */ + SKP_int32 HarmShapeFIRPacked_Q12, /* I Harmonic shaping coeficients */ + SKP_int Tilt_Q14, /* I Tilt shaping coeficient */ + SKP_int32 LF_shp_Q14, /* I Low-frequancy shaping coeficients*/ + SKP_int lag, /* I Lag for harmonic shaping */ + SKP_int length /* I Length of signals */ +) +{ + SKP_int i, idx, LTP_shp_buf_idx; + SKP_int32 n_LTP_Q12, n_Tilt_Q10, n_LF_Q10; + SKP_int32 sLF_MA_shp_Q12, sLF_AR_shp_Q12; + SKP_int16 *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_Q12 = P->sLF_AR_shp_Q12; + sLF_MA_shp_Q12 = P->sLF_MA_shp_Q12; + + for( i = 0; i < length; i++ ) { + if( lag > 0 ) { + /* unrolled loop */ + SKP_assert( HARM_SHAPE_FIR_TAPS == 3 ); + idx = lag + LTP_shp_buf_idx; + n_LTP_Q12 = SKP_SMULBB( LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 - 1) & LTP_MASK ], HarmShapeFIRPacked_Q12 ); + n_LTP_Q12 = SKP_SMLABT( n_LTP_Q12, LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 ) & LTP_MASK ], HarmShapeFIRPacked_Q12 ); + n_LTP_Q12 = SKP_SMLABB( n_LTP_Q12, LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 + 1) & LTP_MASK ], HarmShapeFIRPacked_Q12 ); + } else { + n_LTP_Q12 = 0; + } + + n_Tilt_Q10 = SKP_SMULWB( sLF_AR_shp_Q12, Tilt_Q14 ); + n_LF_Q10 = SKP_SMLAWB( SKP_SMULWT( sLF_AR_shp_Q12, LF_shp_Q14 ), sLF_MA_shp_Q12, LF_shp_Q14 ); + + sLF_AR_shp_Q12 = SKP_SUB32( st_res_Q12[ i ], SKP_LSHIFT( n_Tilt_Q10, 2 ) ); + sLF_MA_shp_Q12 = SKP_SUB32( sLF_AR_shp_Q12, SKP_LSHIFT( n_LF_Q10, 2 ) ); + + LTP_shp_buf_idx = ( LTP_shp_buf_idx - 1 ) & LTP_MASK; + LTP_shp_buf[ LTP_shp_buf_idx ] = ( SKP_int16 )SKP_SAT16( SKP_RSHIFT_ROUND( sLF_MA_shp_Q12, 12 ) ); + + xw[i] = ( SKP_int16 )SKP_SAT16( SKP_RSHIFT_ROUND( SKP_SUB32( sLF_MA_shp_Q12, n_LTP_Q12 ), 12 ) ); + } + + /* Copy temp variable back to state */ + P->sLF_AR_shp_Q12 = sLF_AR_shp_Q12; + P->sLF_MA_shp_Q12 = sLF_MA_shp_Q12; + P->sLTP_shp_buf_idx = LTP_shp_buf_idx; +} diff --git a/pkg/silk/csilk/SKP_Silk_process_NLSFs_FIX.c b/pkg/silk/csilk/SKP_Silk_process_NLSFs_FIX.c new file mode 100644 index 0000000..28b8e77 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_process_NLSFs_FIX.c @@ -0,0 +1,127 @@ +/*********************************************************************** +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_FIX.h" + +/* Limit, stabilize, convert and quantize NLSFs. */ +void SKP_Silk_process_NLSFs_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Encoder state FIX */ + SKP_Silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control FIX */ + SKP_int *pNLSF_Q15 /* I/O Normalized LSFs (quant out) (0 - (2^15-1)) */ +) +{ + SKP_int doInterpolate; + SKP_int pNLSFW_Q6[ MAX_LPC_ORDER ]; + SKP_int NLSF_mu_Q15, NLSF_mu_fluc_red_Q16; + SKP_int32 i_sqr_Q15; + const SKP_Silk_NLSF_CB_struct *psNLSF_CB; + + /* Used only for NLSF interpolation */ + SKP_int pNLSF0_temp_Q15[ MAX_LPC_ORDER ]; + SKP_int pNLSFW0_temp_Q6[ MAX_LPC_ORDER ]; + SKP_int i; + + SKP_assert( psEnc->speech_activity_Q8 >= 0 ); + SKP_assert( psEnc->speech_activity_Q8 <= 256 ); + SKP_assert( psEncCtrl->sparseness_Q8 >= 0 ); + SKP_assert( psEncCtrl->sparseness_Q8 <= 256 ); + 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; */ + NLSF_mu_Q15 = SKP_SMLAWB( 66, -8388, psEnc->speech_activity_Q8 ); + NLSF_mu_fluc_red_Q16 = SKP_SMLAWB( 6554, -838848, psEnc->speech_activity_Q8 ); + } else { + /* NLSF_mu = 0.005f - 0.004f * psEnc->speech_activity; */ + /* NLSF_mu_fluc_red = 0.2f - 0.1f * psEnc->speech_activity - 0.1f * psEncCtrl->sparseness; */ + NLSF_mu_Q15 = SKP_SMLAWB( 164, -33554, psEnc->speech_activity_Q8 ); + NLSF_mu_fluc_red_Q16 = SKP_SMLAWB( 13107, -1677696, psEnc->speech_activity_Q8 + psEncCtrl->sparseness_Q8 ); + } + SKP_assert( NLSF_mu_Q15 >= 0 ); + SKP_assert( NLSF_mu_Q15 <= 164 ); + SKP_assert( NLSF_mu_fluc_red_Q16 >= 0 ); + SKP_assert( NLSF_mu_fluc_red_Q16 <= 13107 ); + + NLSF_mu_Q15 = SKP_max( NLSF_mu_Q15, 1 ); + + /* Calculate NLSF weights */ + TIC(NLSF_weights_FIX) + SKP_Silk_NLSF_VQ_weights_laroia( pNLSFW_Q6, pNLSF_Q15, psEnc->sCmn.predictLPCOrder ); + TOC(NLSF_weights_FIX) + + /* 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 */ + SKP_Silk_interpolate( pNLSF0_temp_Q15, psEnc->sPred.prev_NLSFq_Q15, pNLSF_Q15, + psEncCtrl->sCmn.NLSFInterpCoef_Q2, psEnc->sCmn.predictLPCOrder ); + + /* Calculate first half NLSF weights for the interpolated NLSFs */ + TIC(NLSF_weights_FIX) + SKP_Silk_NLSF_VQ_weights_laroia( pNLSFW0_temp_Q6, pNLSF0_temp_Q15, psEnc->sCmn.predictLPCOrder ); + TOC(NLSF_weights_FIX) + + /* Update NLSF weights with contribution from first half */ + i_sqr_Q15 = SKP_LSHIFT( SKP_SMULBB( psEncCtrl->sCmn.NLSFInterpCoef_Q2, psEncCtrl->sCmn.NLSFInterpCoef_Q2 ), 11 ); + for( i = 0; i < psEnc->sCmn.predictLPCOrder; i++ ) { + pNLSFW_Q6[ i ] = SKP_SMLAWB( SKP_RSHIFT( pNLSFW_Q6[ i ], 1 ), pNLSFW0_temp_Q6[ i ], i_sqr_Q15 ); + SKP_assert( pNLSFW_Q6[ i ] <= SKP_int16_MAX ); + SKP_assert( pNLSFW_Q6[ i ] >= 1 ); + } + } + + /* Set pointer to the NLSF codebook for the current signal type and LPC order */ + psNLSF_CB = psEnc->sCmn.psNLSF_CB[ psEncCtrl->sCmn.sigtype ]; + + /* Quantize NLSF parameters given the trained NLSF codebooks */ + TIC(MSVQ_encode_FIX) + SKP_Silk_NLSF_MSVQ_encode_FIX( psEncCtrl->sCmn.NLSFIndices, pNLSF_Q15, psNLSF_CB, + psEnc->sPred.prev_NLSFq_Q15, pNLSFW_Q6, NLSF_mu_Q15, NLSF_mu_fluc_red_Q16, + psEnc->sCmn.NLSF_MSVQ_Survivors, psEnc->sCmn.predictLPCOrder, psEnc->sCmn.first_frame_after_reset ); + TOC(MSVQ_encode_FIX) + + /* Convert quantized NLSFs back to LPC coefficients */ + SKP_Silk_NLSF2A_stable( psEncCtrl->PredCoef_Q12[ 1 ], pNLSF_Q15, psEnc->sCmn.predictLPCOrder ); + + if( doInterpolate ) { + /* Calculate the interpolated, quantized LSF vector for the first half */ + SKP_Silk_interpolate( pNLSF0_temp_Q15, psEnc->sPred.prev_NLSFq_Q15, pNLSF_Q15, + psEncCtrl->sCmn.NLSFInterpCoef_Q2, psEnc->sCmn.predictLPCOrder ); + + /* Convert back to LPC coefficients */ + SKP_Silk_NLSF2A_stable( psEncCtrl->PredCoef_Q12[ 0 ], pNLSF0_temp_Q15, psEnc->sCmn.predictLPCOrder ); + + } else { + /* Copy LPC coefficients for first half from second half */ + SKP_memcpy( psEncCtrl->PredCoef_Q12[ 0 ], psEncCtrl->PredCoef_Q12[ 1 ], psEnc->sCmn.predictLPCOrder * sizeof( SKP_int16 ) ); + } +} diff --git a/pkg/silk/csilk/SKP_Silk_process_gains_FIX.c b/pkg/silk/csilk/SKP_Silk_process_gains_FIX.c new file mode 100644 index 0000000..518152a --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_process_gains_FIX.c @@ -0,0 +1,108 @@ +/*********************************************************************** +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_FIX.h" +#include "SKP_Silk_tuning_parameters.h" + +/* Processing of gains */ +void SKP_Silk_process_gains_FIX( + SKP_Silk_encoder_state_FIX *psEnc, /* I/O Encoder state_FIX */ + SKP_Silk_encoder_control_FIX *psEncCtrl /* I/O Encoder control_FIX */ +) +{ + SKP_Silk_shape_state_FIX *psShapeSt = &psEnc->sShape; + SKP_int k; + SKP_int32 s_Q16, InvMaxSqrVal_Q16, gain, gain_squared, ResNrg, ResNrgPart, quant_offset_Q10; + + /* Gain reduction when LTP coding gain is high */ + if( psEncCtrl->sCmn.sigtype == SIG_TYPE_VOICED ) { + /*s = -0.5f * SKP_sigmoid( 0.25f * ( psEncCtrl->LTPredCodGain - 12.0f ) ); */ + s_Q16 = -SKP_Silk_sigm_Q15( SKP_RSHIFT_ROUND( psEncCtrl->LTPredCodGain_Q7 - SKP_FIX_CONST( 12.0, 7 ), 4 ) ); + for( k = 0; k < NB_SUBFR; k++ ) { + psEncCtrl->Gains_Q16[ k ] = SKP_SMLAWB( psEncCtrl->Gains_Q16[ k ], psEncCtrl->Gains_Q16[ k ], s_Q16 ); + } + } + + /* Limit the quantized signal */ + InvMaxSqrVal_Q16 = SKP_DIV32_16( SKP_Silk_log2lin( + SKP_SMULWB( SKP_FIX_CONST( 70.0, 7 ) - psEncCtrl->current_SNR_dB_Q7, SKP_FIX_CONST( 0.33, 16 ) ) ), psEnc->sCmn.subfr_length ); + + for( k = 0; k < NB_SUBFR; k++ ) { + /* Soft limit on ratio residual energy and squared gains */ + ResNrg = psEncCtrl->ResNrg[ k ]; + ResNrgPart = SKP_SMULWW( ResNrg, InvMaxSqrVal_Q16 ); + if( psEncCtrl->ResNrgQ[ k ] > 0 ) { + if( psEncCtrl->ResNrgQ[ k ] < 32 ) { + ResNrgPart = SKP_RSHIFT_ROUND( ResNrgPart, psEncCtrl->ResNrgQ[ k ] ); + } else { + ResNrgPart = 0; + } + } else if( psEncCtrl->ResNrgQ[k] != 0 ) { + if( ResNrgPart > SKP_RSHIFT( SKP_int32_MAX, -psEncCtrl->ResNrgQ[ k ] ) ) { + ResNrgPart = SKP_int32_MAX; + } else { + ResNrgPart = SKP_LSHIFT( ResNrgPart, -psEncCtrl->ResNrgQ[ k ] ); + } + } + gain = psEncCtrl->Gains_Q16[ k ]; + gain_squared = SKP_ADD_SAT32( ResNrgPart, SKP_SMMUL( gain, gain ) ); + if( gain_squared < SKP_int16_MAX ) { + /* recalculate with higher precision */ + gain_squared = SKP_SMLAWW( SKP_LSHIFT( ResNrgPart, 16 ), gain, gain ); + SKP_assert( gain_squared > 0 ); + gain = SKP_Silk_SQRT_APPROX( gain_squared ); /* Q8 */ + psEncCtrl->Gains_Q16[ k ] = SKP_LSHIFT_SAT32( gain, 8 ); /* Q16 */ + } else { + gain = SKP_Silk_SQRT_APPROX( gain_squared ); /* Q0 */ + psEncCtrl->Gains_Q16[ k ] = SKP_LSHIFT_SAT32( gain, 16 ); /* Q16 */ + } + } + + /* Noise shaping quantization */ + SKP_Silk_gains_quant( psEncCtrl->sCmn.GainsIndices, psEncCtrl->Gains_Q16, + &psShapeSt->LastGainIndex, psEnc->sCmn.nFramesInPayloadBuf ); + /* 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_Q7 + SKP_RSHIFT( psEncCtrl->input_tilt_Q15, 8 ) > SKP_FIX_CONST( 1.0, 7 ) ) { + psEncCtrl->sCmn.QuantOffsetType = 0; + } else { + psEncCtrl->sCmn.QuantOffsetType = 1; + } + } + + /* Quantizer boundary adjustment */ + quant_offset_Q10 = SKP_Silk_Quantization_Offsets_Q10[ psEncCtrl->sCmn.sigtype ][ psEncCtrl->sCmn.QuantOffsetType ]; + psEncCtrl->Lambda_Q10 = SKP_FIX_CONST( LAMBDA_OFFSET, 10 ) + + SKP_SMULBB( SKP_FIX_CONST( LAMBDA_DELAYED_DECISIONS, 10 ), psEnc->sCmn.nStatesDelayedDecision ) + + SKP_SMULWB( SKP_FIX_CONST( LAMBDA_SPEECH_ACT, 18 ), psEnc->speech_activity_Q8 ) + + SKP_SMULWB( SKP_FIX_CONST( LAMBDA_INPUT_QUALITY, 12 ), psEncCtrl->input_quality_Q14 ) + + SKP_SMULWB( SKP_FIX_CONST( LAMBDA_CODING_QUALITY, 12 ), psEncCtrl->coding_quality_Q14 ) + + SKP_SMULWB( SKP_FIX_CONST( LAMBDA_QUANT_OFFSET, 16 ), quant_offset_Q10 ); + + SKP_assert( psEncCtrl->Lambda_Q10 > 0 ); + SKP_assert( psEncCtrl->Lambda_Q10 < SKP_FIX_CONST( 2, 10 ) ); +} diff --git a/pkg/silk/csilk/SKP_Silk_quant_LTP_gains_FIX.c b/pkg/silk/csilk/SKP_Silk_quant_LTP_gains_FIX.c new file mode 100644 index 0000000..6caf0ff --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_quant_LTP_gains_FIX.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_FIX.h" + +void SKP_Silk_quant_LTP_gains_FIX( + SKP_int16 B_Q14[], /* I/O (un)quantized LTP gains */ + SKP_int cbk_index[], /* O Codebook Index */ + SKP_int *periodicity_index, /* O Periodicity Index */ + const SKP_int32 W_Q18[], /* I Error Weights in Q18 */ + SKP_int mu_Q8, /* I Mu value (R/D tradeoff) */ + 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_int16 *b_Q14_ptr; + const SKP_int32 *W_Q18_ptr; + SKP_int32 rate_dist_subfr, rate_dist, min_rate_dist; + + + + /***************************************************/ + /* iterate over different codebooks with different */ + /* rates/distortions, and choose best */ + /***************************************************/ + min_rate_dist = SKP_int32_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_Q18_ptr = W_Q18; + b_Q14_ptr = B_Q14; + + rate_dist = 0; + for( j = 0; j < NB_SUBFR; j++ ) { + + SKP_Silk_VQ_WMat_EC_FIX( + &temp_idx[ j ], /* O index of best codebook vector */ + &rate_dist_subfr, /* O best weighted quantization error + mu * rate */ + b_Q14_ptr, /* I input vector to be quantized */ + W_Q18_ptr, /* I weighting matrix */ + cbk_ptr_Q14, /* I codebook */ + cl_ptr, /* I code length for each codebook vector */ + mu_Q8, /* I tradeoff between weighted error and rate */ + cbk_size /* I number of vectors in codebook */ + ); + + rate_dist = SKP_ADD_POS_SAT32( rate_dist, rate_dist_subfr ); + + b_Q14_ptr += LTP_ORDER; + W_Q18_ptr += LTP_ORDER * LTP_ORDER; + } + + /* Avoid never finding a codebook */ + rate_dist = SKP_min( SKP_int32_MAX - 1, rate_dist ); + + 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 < 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++ ) { + for( k = 0; k < LTP_ORDER; k++ ) { + B_Q14[ j * LTP_ORDER + k ] = cbk_ptr_Q14[ SKP_MLA( k, cbk_index[ j ], LTP_ORDER ) ]; + } + } +} + diff --git a/pkg/silk/csilk/SKP_Silk_range_coder.c b/pkg/silk/csilk/SKP_Silk_range_coder.c new file mode 100644 index 0000000..45f9ce4 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_regularize_correlations_FIX.c b/pkg/silk/csilk/SKP_Silk_regularize_correlations_FIX.c new file mode 100644 index 0000000..e2700ac --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_regularize_correlations_FIX.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_FIX.h" + +/* Add noise to matrix diagonal */ +void SKP_Silk_regularize_correlations_FIX( + SKP_int32 *XX, /* I/O Correlation matrices */ + SKP_int32 *xx, /* I/O Correlation values */ + SKP_int32 noise, /* I Noise to add */ + SKP_int D /* I Dimension of XX */ +) +{ + SKP_int i; + for( i = 0; i < D; i++ ) { + matrix_ptr( &XX[ 0 ], i, i, D ) = SKP_ADD32( matrix_ptr( &XX[ 0 ], i, i, D ), noise ); + } + xx[ 0 ] += noise; +} diff --git a/pkg/silk/csilk/SKP_Silk_resampler.c b/pkg/silk/csilk/SKP_Silk_resampler.c new file mode 100644 index 0000000..c3d25e5 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_resampler_down2.c b/pkg/silk/csilk/SKP_Silk_resampler_down2.c new file mode 100644 index 0000000..fedba1f --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_resampler_down2.c @@ -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. +***********************************************************************/ + +/* * + * 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" + +#if (EMBEDDED_ARM<5) +/* 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 ) ); + } +} +#endif diff --git a/pkg/silk/csilk/SKP_Silk_resampler_down2_3.c b/pkg/silk/csilk/SKP_Silk_resampler_down2_3.c new file mode 100644 index 0000000..59ecc7c --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_resampler_down2_3.c @@ -0,0 +1,103 @@ +/*********************************************************************** +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" + +#undef ORDER_FIR +#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/pkg/silk/csilk/SKP_Silk_resampler_down3.c b/pkg/silk/csilk/SKP_Silk_resampler_down3.c new file mode 100644 index 0000000..2cc601e --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_resampler_down3.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. +***********************************************************************/ + +/* * + * 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" + +#undef ORDER_FIR +#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/pkg/silk/csilk/SKP_Silk_resampler_private.h b/pkg/silk/csilk/SKP_Silk_resampler_private.h new file mode 100644 index 0000000..04563fa --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_resampler_private_AR2.c b/pkg/silk/csilk/SKP_Silk_resampler_private_AR2.c new file mode 100644 index 0000000..5d581a4 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_resampler_private_AR2.c @@ -0,0 +1,60 @@ +/*********************************************************************** +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" + +#if (EMBEDDED_ARM<5) +/* 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 ] ); + } +} +#endif diff --git a/pkg/silk/csilk/SKP_Silk_resampler_private_ARMA4.c b/pkg/silk/csilk/SKP_Silk_resampler_private_ARMA4.c new file mode 100644 index 0000000..4351592 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_resampler_private_ARMA4.c @@ -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. +***********************************************************************/ + +/* * + * 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 */ +#if (EMBEDDED_ARM<5) +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 ) ); + } +} +#endif + diff --git a/pkg/silk/csilk/SKP_Silk_resampler_private_IIR_FIR.c b/pkg/silk/csilk/SKP_Silk_resampler_private_IIR_FIR.c new file mode 100644 index 0000000..0976451 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_resampler_private_IIR_FIR.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. +***********************************************************************/ + +/* * + * 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" +#if EMBEDDED_ARM<5 +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; +} +#else +extern 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 ); +#endif +/* 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/pkg/silk/csilk/SKP_Silk_resampler_private_copy.c b/pkg/silk/csilk/SKP_Silk_resampler_private_copy.c new file mode 100644 index 0000000..71df033 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_resampler_private_down4.c b/pkg/silk/csilk/SKP_Silk_resampler_private_down4.c new file mode 100644 index 0000000..3d65ad7 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_resampler_private_down_FIR.c b/pkg/silk/csilk/SKP_Silk_resampler_private_down_FIR.c new file mode 100644 index 0000000..4a441b1 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_resampler_private_down_FIR.c @@ -0,0 +1,167 @@ +/*********************************************************************** +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" +#if EMBEDDED_ARM<5 +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; +} + +#else +extern 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); +extern 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); +#endif + +/* 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/pkg/silk/csilk/SKP_Silk_resampler_private_up2_HQ.c b/pkg/silk/csilk/SKP_Silk_resampler_private_up2_HQ.c new file mode 100644 index 0000000..a95082e --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_resampler_private_up2_HQ.c @@ -0,0 +1,120 @@ +/*********************************************************************** +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. */ +#if (EMBEDDED_ARM<5) +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 ) ); + } +} +#endif + + +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/pkg/silk/csilk/SKP_Silk_resampler_private_up4.c b/pkg/silk/csilk/SKP_Silk_resampler_private_up4.c new file mode 100644 index 0000000..f1cff61 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_resampler_rom.c b/pkg/silk/csilk/SKP_Silk_resampler_rom.c new file mode 100644 index 0000000..b8e8ef8 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_resampler_rom.h b/pkg/silk/csilk/SKP_Silk_resampler_rom.h new file mode 100644 index 0000000..8c12f67 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_resampler_structs.h b/pkg/silk/csilk/SKP_Silk_resampler_structs.h new file mode 100644 index 0000000..743c992 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_resampler_up2.c b/pkg/silk/csilk/SKP_Silk_resampler_up2.c new file mode 100644 index 0000000..9ede6a9 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_resampler_up2.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_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 */ +#if EMBEDDED_ARM<5 +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 ) ); + } +} +#endif diff --git a/pkg/silk/csilk/SKP_Silk_residual_energy16_FIX.c b/pkg/silk/csilk/SKP_Silk_residual_energy16_FIX.c new file mode 100644 index 0000000..60ee2a5 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_residual_energy16_FIX.c @@ -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_FIX.h" + +/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */ +SKP_int32 SKP_Silk_residual_energy16_covar_FIX( + const SKP_int16 *c, /* I Prediction vector */ + const SKP_int32 *wXX, /* I Correlation matrix */ + const SKP_int32 *wXx, /* I Correlation vector */ + SKP_int32 wxx, /* I Signal energy */ + SKP_int D, /* I Dimension */ + SKP_int cQ /* I Q value for c vector 0 - 15 */ +) +{ + SKP_int i, j, lshifts, Qxtra; + SKP_int32 c_max, w_max, tmp, tmp2, nrg; + SKP_int cn[ MAX_MATRIX_SIZE ]; + const SKP_int32 *pRow; + + /* Safety checks */ + SKP_assert( D >= 0 ); + SKP_assert( D <= 16 ); + SKP_assert( cQ > 0 ); + SKP_assert( cQ < 16 ); + + lshifts = 16 - cQ; + Qxtra = lshifts; + + c_max = 0; + for( i = 0; i < D; i++ ) { + c_max = SKP_max_32( c_max, SKP_abs( ( SKP_int32 )c[ i ] ) ); + } + Qxtra = SKP_min_int( Qxtra, SKP_Silk_CLZ32( c_max ) - 17 ); + + w_max = SKP_max_32( wXX[ 0 ], wXX[ D * D - 1 ] ); + Qxtra = SKP_min_int( Qxtra, SKP_Silk_CLZ32( SKP_MUL( D, SKP_RSHIFT( SKP_SMULWB( w_max, c_max ), 4 ) ) ) - 5 ); + Qxtra = SKP_max_int( Qxtra, 0 ); + for( i = 0; i < D; i++ ) { + cn[ i ] = SKP_LSHIFT( ( SKP_int )c[ i ], Qxtra ); + SKP_assert( SKP_abs(cn[i]) <= ( SKP_int16_MAX + 1 ) ); /* Check that SKP_SMLAWB can be used */ + } + lshifts -= Qxtra; + + /* Compute wxx - 2 * wXx * c */ + tmp = 0; + for( i = 0; i < D; i++ ) { + tmp = SKP_SMLAWB( tmp, wXx[ i ], cn[ i ] ); + } + nrg = SKP_RSHIFT( wxx, 1 + lshifts ) - tmp; /* Q: -lshifts - 1 */ + + /* Add c' * wXX * c, assuming wXX is symmetric */ + tmp2 = 0; + for( i = 0; i < D; i++ ) { + tmp = 0; + pRow = &wXX[ i * D ]; + for( j = i + 1; j < D; j++ ) { + tmp = SKP_SMLAWB( tmp, pRow[ j ], cn[ j ] ); + } + tmp = SKP_SMLAWB( tmp, SKP_RSHIFT( pRow[ i ], 1 ), cn[ i ] ); + tmp2 = SKP_SMLAWB( tmp2, tmp, cn[ i ] ); + } + nrg = SKP_ADD_LSHIFT32( nrg, tmp2, lshifts ); /* Q: -lshifts - 1 */ + + /* Keep one bit free always, because we add them for LSF interpolation */ + if( nrg < 1 ) { + nrg = 1; + } else if( nrg > SKP_RSHIFT( SKP_int32_MAX, lshifts + 2 ) ) { + nrg = SKP_int32_MAX >> 1; + } else { + nrg = SKP_LSHIFT( nrg, lshifts + 1 ); /* Q0 */ + } + return nrg; + +} diff --git a/pkg/silk/csilk/SKP_Silk_residual_energy_FIX.c b/pkg/silk/csilk/SKP_Silk_residual_energy_FIX.c new file mode 100644 index 0000000..f422e55 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_residual_energy_FIX.c @@ -0,0 +1,88 @@ +/*********************************************************************** +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_FIX.h" + +/* Calculates residual energies of input subframes where all subframes have LPC_order */ +/* of preceeding samples */ +void SKP_Silk_residual_energy_FIX( + SKP_int32 nrgs[ NB_SUBFR ], /* O Residual energy per subframe */ + SKP_int nrgsQ[ NB_SUBFR ], /* O Q value per subframe */ + const SKP_int16 x[], /* I Input signal */ + SKP_int16 a_Q12[ 2 ][ MAX_LPC_ORDER ],/* I AR coefs for each frame half */ + const SKP_int32 gains[ NB_SUBFR ], /* I Quantization gains */ + const SKP_int subfr_length, /* I Subframe length */ + const SKP_int LPC_order /* I LPC order */ +) +{ + SKP_int offset, i, j, rshift, lz1, lz2; + SKP_int16 *LPC_res_ptr, LPC_res[ ( MAX_FRAME_LENGTH + NB_SUBFR * MAX_LPC_ORDER ) / 2 ]; + const SKP_int16 *x_ptr; + SKP_int16 S[ MAX_LPC_ORDER ]; + SKP_int32 tmp32; + + x_ptr = x; + offset = LPC_order + subfr_length; + + /* Filter input to create the LPC residual for each frame half, and measure subframe energies */ + for( i = 0; i < 2; i++ ) { + /* Calculate half frame LPC residual signal including preceeding samples */ + SKP_memset( S, 0, LPC_order * sizeof( SKP_int16 ) ); + SKP_Silk_LPC_analysis_filter( x_ptr, a_Q12[ i ], S, LPC_res, ( NB_SUBFR >> 1 ) * offset, LPC_order ); + + /* Point to first subframe of the just calculated LPC residual signal */ + LPC_res_ptr = LPC_res + LPC_order; + for( j = 0; j < ( NB_SUBFR >> 1 ); j++ ) { + /* Measure subframe energy */ + SKP_Silk_sum_sqr_shift( &nrgs[ i * ( NB_SUBFR >> 1 ) + j ], &rshift, LPC_res_ptr, subfr_length ); + + /* Set Q values for the measured energy */ + nrgsQ[ i * ( NB_SUBFR >> 1 ) + j ] = -rshift; + + /* Move to next subframe */ + LPC_res_ptr += offset; + } + /* Move to next frame half */ + x_ptr += ( NB_SUBFR >> 1 ) * offset; + } + + /* Apply the squared subframe gains */ + for( i = 0; i < NB_SUBFR; i++ ) { + /* Fully upscale gains and energies */ + lz1 = SKP_Silk_CLZ32( nrgs[ i ] ) - 1; + lz2 = SKP_Silk_CLZ32( gains[ i ] ) - 1; + + tmp32 = SKP_LSHIFT32( gains[ i ], lz2 ); + + /* Find squared gains */ + tmp32 = SKP_SMMUL( tmp32, tmp32 ); // Q( 2 * lz2 - 32 ) + + /* Scale energies */ + nrgs[ i ] = SKP_SMMUL( tmp32, SKP_LSHIFT32( nrgs[ i ], lz1 ) ); // Q( nrgsQ[ i ] + lz1 + 2 * lz2 - 32 - 32 ) + nrgsQ[ i ] += lz1 + 2 * lz2 - 32 - 32; + } +} diff --git a/pkg/silk/csilk/SKP_Silk_scale_copy_vector16.c b/pkg/silk/csilk/SKP_Silk_scale_copy_vector16.c new file mode 100644 index 0000000..9d6f8c3 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_scale_copy_vector16.c @@ -0,0 +1,45 @@ +/*********************************************************************** +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" + +/* 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 */ +) +{ + SKP_int i; + SKP_int32 tmp32; + + for( i = 0; i < dataSize; i++ ) { + tmp32 = SKP_SMULWB( gain_Q16, data_in[ i ] ); + data_out[ i ] = (SKP_int16)SKP_CHECK_FIT16( tmp32 ); + } +} diff --git a/pkg/silk/csilk/SKP_Silk_scale_vector.c b/pkg/silk/csilk/SKP_Silk_scale_vector.c new file mode 100644 index 0000000..320e94a --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_scale_vector.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_SigProc_FIX.h" + +/* Multiply a vector by a constant */ +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 */ +) +{ + SKP_int i; + + for( i = 0; i < dataSize; i++ ) { + data1[ i ] = (SKP_int32)SKP_CHECK_FIT32( SKP_RSHIFT64( SKP_SMULL( data1[ i ], gain_Q26 ), 8 ) );// OUTPUT: Q18 + } +} + diff --git a/pkg/silk/csilk/SKP_Silk_schur.c b/pkg/silk/csilk/SKP_Silk_schur.c new file mode 100644 index 0000000..b631851 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_schur.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. +***********************************************************************/ + +/* * + * SKP_Silk_schur.c * + * * + * Calculates the reflection coefficients from the correlation sequence * + * * + * Copyright 2008 (c), Skype Limited * + * Date: 080103 * + * */ +#include "SKP_Silk_SigProc_FIX.h" + +/* 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 */ +) +{ + SKP_int k, n, lz; + SKP_int32 C[ SKP_Silk_MAX_ORDER_LPC + 1 ][ 2 ]; + SKP_int32 Ctmp1, Ctmp2, rc_tmp_Q15; + + /* Get number of leading zeros */ + lz = SKP_Silk_CLZ32( c[ 0 ] ); + + /* Copy correlations and adjust level to Q30 */ + if( lz < 2 ) { + /* lz must be 1, so shift one to the right */ + for( k = 0; k < order + 1; k++ ) { + C[ k ][ 0 ] = C[ k ][ 1 ] = SKP_RSHIFT( c[ k ], 1 ); + } + } else if( lz > 2 ) { + /* Shift to the left */ + lz -= 2; + for( k = 0; k < order + 1; k++ ) { + C[ k ][ 0 ] = C[ k ][ 1 ] = SKP_LSHIFT( c[k], lz ); + } + } else { + /* No need to shift */ + for( k = 0; k < order + 1; k++ ) { + C[ k ][ 0 ] = C[ k ][ 1 ] = c[ k ]; + } + } + + for( k = 0; k < order; k++ ) { + + /* Get reflection coefficient */ + rc_tmp_Q15 = -SKP_DIV32_16( C[ k + 1 ][ 0 ], SKP_max_32( SKP_RSHIFT( C[ 0 ][ 1 ], 15 ), 1 ) ); + + /* Clip (shouldn't happen for properly conditioned inputs) */ + rc_tmp_Q15 = SKP_SAT16( rc_tmp_Q15 ); + + /* Store */ + rc_Q15[ k ] = (SKP_int16)rc_tmp_Q15; + + /* Update correlations */ + for( n = 0; n < order - k; n++ ) { + Ctmp1 = C[ n + k + 1 ][ 0 ]; + Ctmp2 = C[ n ][ 1 ]; + C[ n + k + 1 ][ 0 ] = SKP_SMLAWB( Ctmp1, SKP_LSHIFT( Ctmp2, 1 ), rc_tmp_Q15 ); + C[ n ][ 1 ] = SKP_SMLAWB( Ctmp2, SKP_LSHIFT( Ctmp1, 1 ), rc_tmp_Q15 ); + } + } + + /* return residual energy */ + return C[0][1]; +} diff --git a/pkg/silk/csilk/SKP_Silk_schur64.c b/pkg/silk/csilk/SKP_Silk_schur64.c new file mode 100644 index 0000000..c4e824c --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_schur64.c @@ -0,0 +1,82 @@ +/*********************************************************************** +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_schur64.c * + * * + * Calculates the reflection coefficients from the correlation sequence * + * using extra precision * + * * + * Copyright 2008 (c), Skype Limited * + * Date: 080103 * + * */ +#include "SKP_Silk_SigProc_FIX.h" + +/* Slower than schur(), but more accurate. */ +/* Uses SMULL(), available on armv4 */ +#if EMBEDDED_ARM<6 +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 */ +) +{ + SKP_int k, n; + SKP_int32 C[ SKP_Silk_MAX_ORDER_LPC + 1 ][ 2 ]; + SKP_int32 Ctmp1_Q30, Ctmp2_Q30, rc_tmp_Q31; + + /* Check for invalid input */ + if( c[ 0 ] <= 0 ) { + SKP_memset( rc_Q16, 0, order * sizeof( SKP_int32 ) ); + return 0; + } + + for( k = 0; k < order + 1; k++ ) { + C[ k ][ 0 ] = C[ k ][ 1 ] = c[ k ]; + } + + for( k = 0; k < order; k++ ) { + /* Get reflection coefficient: divide two Q30 values and get result in Q31 */ + rc_tmp_Q31 = SKP_DIV32_varQ( -C[ k + 1 ][ 0 ], C[ 0 ][ 1 ], 31 ); + + /* Save the output */ + rc_Q16[ k ] = SKP_RSHIFT_ROUND( rc_tmp_Q31, 15 ); + + /* Update correlations */ + for( n = 0; n < order - k; n++ ) { + Ctmp1_Q30 = C[ n + k + 1 ][ 0 ]; + Ctmp2_Q30 = C[ n ][ 1 ]; + + /* Multiply and add the highest int32 */ + C[ n + k + 1 ][ 0 ] = Ctmp1_Q30 + SKP_SMMUL( SKP_LSHIFT( Ctmp2_Q30, 1 ), rc_tmp_Q31 ); + C[ n ][ 1 ] = Ctmp2_Q30 + SKP_SMMUL( SKP_LSHIFT( Ctmp1_Q30, 1 ), rc_tmp_Q31 ); + } + } + + return C[ 0 ][ 1 ]; +} +#endif diff --git a/pkg/silk/csilk/SKP_Silk_setup_complexity.h b/pkg/silk/csilk/SKP_Silk_setup_complexity.h new file mode 100644 index 0000000..f00ab55 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_shell_coder.c b/pkg/silk/csilk/SKP_Silk_shell_coder.c new file mode 100644 index 0000000..0163ab4 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_sigm_Q15.c b/pkg/silk/csilk/SKP_Silk_sigm_Q15.c new file mode 100644 index 0000000..6a104ab --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_sigm_Q15.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_sigm_Q15.c * + * * + * Approximate sigmoid function * + * * + * Copyright 2006 (c), Skype Limited * + * Date: 060221 * + * */ +#include "SKP_Silk_SigProc_FIX.h" +#if EMBEDDED_ARM<4 +/********************************/ +/* 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 ) ); + } + } +} +#endif + diff --git a/pkg/silk/csilk/SKP_Silk_solve_LS_FIX.c b/pkg/silk/csilk/SKP_Silk_solve_LS_FIX.c new file mode 100644 index 0000000..7f026ec --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_solve_LS_FIX.c @@ -0,0 +1,241 @@ +/*********************************************************************** +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_FIX.h" +#include "SKP_Silk_tuning_parameters.h" + +/*****************************/ +/* Internal function headers */ +/*****************************/ + +typedef struct { + SKP_int32 Q36_part; + SKP_int32 Q48_part; +} inv_D_t; + +/* Factorize square matrix A into LDL form */ +SKP_INLINE void SKP_Silk_LDL_factorize_FIX( + SKP_int32 *A, /* I/O Pointer to Symetric Square Matrix */ + SKP_int M, /* I Size of Matrix */ + SKP_int32 *L_Q16, /* I/O Pointer to Square Upper triangular Matrix */ + inv_D_t *inv_D /* I/O Pointer to vector holding inverted diagonal elements of D */ +); + +/* Solve Lx = b, when L is lower triangular and has ones on the diagonal */ +SKP_INLINE void SKP_Silk_LS_SolveFirst_FIX( + const SKP_int32 *L_Q16, /* I Pointer to Lower Triangular Matrix */ + SKP_int M, /* I Dim of Matrix equation */ + const SKP_int32 *b, /* I b Vector */ + SKP_int32 *x_Q16 /* O x Vector */ +); + +/* Solve L^t*x = b, where L is lower triangular with ones on the diagonal */ +SKP_INLINE void SKP_Silk_LS_SolveLast_FIX( + const SKP_int32 *L_Q16, /* I Pointer to Lower Triangular Matrix */ + const SKP_int M, /* I Dim of Matrix equation */ + const SKP_int32 *b, /* I b Vector */ + SKP_int32 *x_Q16 /* O x Vector */ +); + +SKP_INLINE void SKP_Silk_LS_divide_Q16_FIX( + SKP_int32 T[], /* I/O Numenator vector */ + inv_D_t *inv_D, /* I 1 / D vector */ + SKP_int M /* I dimension */ +); + +/* Solves Ax = b, assuming A is symmetric */ +void SKP_Silk_solve_LDL_FIX( + SKP_int32 *A, /* I Pointer to symetric square matrix A */ + SKP_int M, /* I Size of matrix */ + const SKP_int32 *b, /* I Pointer to b vector */ + SKP_int32 *x_Q16 /* O Pointer to x solution vector */ +) +{ + SKP_int32 L_Q16[ MAX_MATRIX_SIZE * MAX_MATRIX_SIZE ]; + SKP_int32 Y[ MAX_MATRIX_SIZE ]; + inv_D_t inv_D[ MAX_MATRIX_SIZE ]; + + SKP_assert( M <= MAX_MATRIX_SIZE ); + + /*************************************************** + Factorize A by LDL such that A = L*D*L', + where L is lower triangular with ones on diagonal + ****************************************************/ + SKP_Silk_LDL_factorize_FIX( A, M, L_Q16, inv_D ); + + /**************************************************** + * substitute D*L'*x = Y. ie: + L*D*L'*x = b => L*Y = b <=> Y = inv(L)*b + ******************************************************/ + SKP_Silk_LS_SolveFirst_FIX( L_Q16, M, b, Y ); + + /**************************************************** + D*L'*x = Y <=> L'*x = inv(D)*Y, because D is + diagonal just multiply with 1/d_i + ****************************************************/ + SKP_Silk_LS_divide_Q16_FIX( Y, inv_D, M ); + + /**************************************************** + x = inv(L') * inv(D) * Y + *****************************************************/ + SKP_Silk_LS_SolveLast_FIX( L_Q16, M, Y, x_Q16 ); +} + +SKP_INLINE void SKP_Silk_LDL_factorize_FIX( + SKP_int32 *A, /* I Pointer to Symetric Square Matrix */ + SKP_int M, /* I Size of Matrix */ + SKP_int32 *L_Q16, /* I/O Pointer to Square Upper triangular Matrix */ + inv_D_t *inv_D /* I/O Pointer to vector holding inverted diagonal elements of D */ +) +{ + SKP_int i, j, k, status, loop_count; + const SKP_int32 *ptr1, *ptr2; + SKP_int32 diag_min_value, tmp_32, err; + SKP_int32 v_Q0[ MAX_MATRIX_SIZE ], D_Q0[ MAX_MATRIX_SIZE ]; + SKP_int32 one_div_diag_Q36, one_div_diag_Q40, one_div_diag_Q48; + + SKP_assert( M <= MAX_MATRIX_SIZE ); + + status = 1; + diag_min_value = SKP_max_32( SKP_SMMUL( SKP_ADD_SAT32( A[ 0 ], A[ SKP_SMULBB( M, M ) - 1 ] ), SKP_FIX_CONST( FIND_LTP_COND_FAC, 31 ) ), 1 << 9 ); + for( loop_count = 0; loop_count < M && status == 1; loop_count++ ) { + status = 0; + for( j = 0; j < M; j++ ) { + ptr1 = matrix_adr( L_Q16, j, 0, M ); + tmp_32 = 0; + for( i = 0; i < j; i++ ) { + v_Q0[ i ] = SKP_SMULWW( D_Q0[ i ], ptr1[ i ] ); /* Q0 */ + tmp_32 = SKP_SMLAWW( tmp_32, v_Q0[ i ], ptr1[ i ] ); /* Q0 */ + } + tmp_32 = SKP_SUB32( matrix_ptr( A, j, j, M ), tmp_32 ); + + if( tmp_32 < diag_min_value ) { + tmp_32 = SKP_SUB32( SKP_SMULBB( loop_count + 1, diag_min_value ), tmp_32 ); + /* Matrix not positive semi-definite, or ill conditioned */ + for( i = 0; i < M; i++ ) { + matrix_ptr( A, i, i, M ) = SKP_ADD32( matrix_ptr( A, i, i, M ), tmp_32 ); + } + status = 1; + break; + } + D_Q0[ j ] = tmp_32; /* always < max(Correlation) */ + + /* two-step division */ + one_div_diag_Q36 = SKP_INVERSE32_varQ( tmp_32, 36 ); /* Q36 */ + one_div_diag_Q40 = SKP_LSHIFT( one_div_diag_Q36, 4 ); /* Q40 */ + err = SKP_SUB32( 1 << 24, SKP_SMULWW( tmp_32, one_div_diag_Q40 ) ); /* Q24 */ + one_div_diag_Q48 = SKP_SMULWW( err, one_div_diag_Q40 ); /* Q48 */ + + /* Save 1/Ds */ + inv_D[ j ].Q36_part = one_div_diag_Q36; + inv_D[ j ].Q48_part = one_div_diag_Q48; + + matrix_ptr( L_Q16, j, j, M ) = 65536; /* 1.0 in Q16 */ + ptr1 = matrix_adr( A, j, 0, M ); + ptr2 = matrix_adr( L_Q16, j + 1, 0, M ); + for( i = j + 1; i < M; i++ ) { + tmp_32 = 0; + for( k = 0; k < j; k++ ) { + tmp_32 = SKP_SMLAWW( tmp_32, v_Q0[ k ], ptr2[ k ] ); /* Q0 */ + } + tmp_32 = SKP_SUB32( ptr1[ i ], tmp_32 ); /* always < max(Correlation) */ + + /* tmp_32 / D_Q0[j] : Divide to Q16 */ + matrix_ptr( L_Q16, i, j, M ) = SKP_ADD32( SKP_SMMUL( tmp_32, one_div_diag_Q48 ), + SKP_RSHIFT( SKP_SMULWW( tmp_32, one_div_diag_Q36 ), 4 ) ); + + /* go to next column */ + ptr2 += M; + } + } + } + + SKP_assert( status == 0 ); +} + +SKP_INLINE void SKP_Silk_LS_divide_Q16_FIX( + SKP_int32 T[], /* I/O Numenator vector */ + inv_D_t *inv_D, /* I 1 / D vector */ + SKP_int M /* I Order */ +) +{ + SKP_int i; + SKP_int32 tmp_32; + SKP_int32 one_div_diag_Q36, one_div_diag_Q48; + + for( i = 0; i < M; i++ ) { + one_div_diag_Q36 = inv_D[ i ].Q36_part; + one_div_diag_Q48 = inv_D[ i ].Q48_part; + + tmp_32 = T[ i ]; + T[ i ] = SKP_ADD32( SKP_SMMUL( tmp_32, one_div_diag_Q48 ), SKP_RSHIFT( SKP_SMULWW( tmp_32, one_div_diag_Q36 ), 4 ) ); + } +} + +/* Solve Lx = b, when L is lower triangular and has ones on the diagonal */ +SKP_INLINE void SKP_Silk_LS_SolveFirst_FIX( + const SKP_int32 *L_Q16, /* I Pointer to Lower Triangular Matrix */ + SKP_int M, /* I Dim of Matrix equation */ + const SKP_int32 *b, /* I b Vector */ + SKP_int32 *x_Q16 /* O x Vector */ +) +{ + SKP_int i, j; + const SKP_int32 *ptr32; + SKP_int32 tmp_32; + + for( i = 0; i < M; i++ ) { + ptr32 = matrix_adr( L_Q16, i, 0, M ); + tmp_32 = 0; + for( j = 0; j < i; j++ ) { + tmp_32 = SKP_SMLAWW( tmp_32, ptr32[ j ], x_Q16[ j ] ); + } + x_Q16[ i ] = SKP_SUB32( b[ i ], tmp_32 ); + } +} + +/* Solve L^t*x = b, where L is lower triangular with ones on the diagonal */ +SKP_INLINE void SKP_Silk_LS_SolveLast_FIX( + const SKP_int32 *L_Q16, /* I Pointer to Lower Triangular Matrix */ + const SKP_int M, /* I Dim of Matrix equation */ + const SKP_int32 *b, /* I b Vector */ + SKP_int32 *x_Q16 /* O x Vector */ +) +{ + SKP_int i, j; + const SKP_int32 *ptr32; + SKP_int32 tmp_32; + + for( i = M - 1; i >= 0; i-- ) { + ptr32 = matrix_adr( L_Q16, 0, i, M ); + tmp_32 = 0; + for( j = M - 1; j > i; j-- ) { + tmp_32 = SKP_SMLAWW( tmp_32, ptr32[ SKP_SMULBB( j, M ) ], x_Q16[ j ] ); + } + x_Q16[ i ] = SKP_SUB32( b[ i ], tmp_32 ); + } +} diff --git a/pkg/silk/csilk/SKP_Silk_sort.c b/pkg/silk/csilk/SKP_Silk_sort.c new file mode 100644 index 0000000..3753c7b --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_structs.h b/pkg/silk/csilk/SKP_Silk_structs.h new file mode 100644 index 0000000..4cb1db5 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_structs_FIX.h b/pkg/silk/csilk/SKP_Silk_structs_FIX.h new file mode 100644 index 0000000..967c90c --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_structs_FIX.h @@ -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. +***********************************************************************/ + +#ifndef SKP_SILK_STRUCTS_FIX_H +#define SKP_SILK_STRUCTS_FIX_H + +#include "SKP_Silk_typedef.h" +#include "SKP_Silk_main.h" +#include "SKP_Silk_structs.h" + + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************/ +/* Noise shaping analysis state */ +/********************************/ +typedef struct { + SKP_int LastGainIndex; + SKP_int32 HarmBoost_smth_Q16; + SKP_int32 HarmShapeGain_smth_Q16; + SKP_int32 Tilt_smth_Q16; +} SKP_Silk_shape_state_FIX; + +/********************************/ +/* Prefilter state */ +/********************************/ +typedef struct { + SKP_int16 sLTP_shp[ LTP_BUF_LENGTH ]; + SKP_int32 sAR_shp[ MAX_SHAPE_LPC_ORDER + 1 ]; // Q14 + SKP_int sLTP_shp_buf_idx; + SKP_int32 sLF_AR_shp_Q12; + SKP_int32 sLF_MA_shp_Q12; + SKP_int sHarmHP; + SKP_int32 rand_seed; + SKP_int lagPrev; +} SKP_Silk_prefilter_state_FIX; + +/*****************************/ +/* 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_int prev_NLSFq_Q15[ MAX_LPC_ORDER ]; /* Previously quantized NLSF vector */ +} SKP_Silk_predict_state_FIX; + + +/********************************/ +/* Encoder state FIX */ +/********************************/ +typedef struct { + SKP_Silk_encoder_state sCmn; /* Common struct, shared with floating-point code */ + +#if HIGH_PASS_INPUT + SKP_int32 variable_HP_smth1_Q15; /* State of first smoother */ + SKP_int32 variable_HP_smth2_Q15; /* State of second smoother */ +#endif + SKP_Silk_shape_state_FIX sShape; /* Shape state */ + SKP_Silk_prefilter_state_FIX sPrefilt; /* Prefilter State */ + SKP_Silk_predict_state_FIX sPred; /* Prediction state */ + + /* Buffer for find pitch and noise shape analysis */ + SKP_DWORD_ALIGN SKP_int16 x_buf[ 2 * MAX_FRAME_LENGTH + LA_SHAPE_MAX ]; + SKP_int LTPCorr_Q15; /* Normalized correlation from pitch lag estimator, approx Q15 */ + SKP_int mu_LTP_Q8; /* Rate-distortion tradeoff in LTP quantization */ + SKP_int32 SNR_dB_Q7; /* Quality setting */ + SKP_int32 avgGain_Q16; /* average gain during active speech */ + SKP_int32 avgGain_Q16_one_bit_per_sample; /* average gain during active speech */ + SKP_int BufferedInChannel_ms; /* Simulated number of ms buffer because of exceeded TargetRate_bps */ + SKP_int speech_activity_Q8; /* Speech activity in Q8 */ + + /* Parameters For LTP scaling Control */ + SKP_int prevLTPredCodGain_Q7; + SKP_int HPLTPredCodGain_Q7; + + SKP_int32 inBandFEC_SNR_comp_Q8; /* Compensation to SNR_dB when using inband FEC Voiced */ + +} SKP_Silk_encoder_state_FIX; + +/************************/ +/* Encoder control FIX */ +/************************/ +typedef struct { + SKP_Silk_encoder_control sCmn; /* Common struct, shared with floating-point code */ + + /* 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_DWORD_ALIGN SKP_int16 AR1_Q13[ NB_SUBFR * MAX_SHAPE_LPC_ORDER ]; + SKP_DWORD_ALIGN 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 GainsPre_Q14[ NB_SUBFR ]; + SKP_int HarmBoost_Q14[ NB_SUBFR ]; + SKP_int Tilt_Q14[ NB_SUBFR ]; + SKP_int HarmShapeGain_Q14[ NB_SUBFR ]; + SKP_int Lambda_Q10; + SKP_int input_quality_Q14; + SKP_int coding_quality_Q14; + SKP_int32 pitch_freq_low_Hz; + SKP_int current_SNR_dB_Q7; + + /* measures */ + SKP_int sparseness_Q8; + SKP_int32 predGain_Q16; + SKP_int LTPredCodGain_Q7; + SKP_int input_quality_bands_Q15[ VAD_N_BANDS ]; + SKP_int input_tilt_Q15; + SKP_int32 ResNrg[ NB_SUBFR ]; /* Residual energy per subframe */ + SKP_int ResNrgQ[ NB_SUBFR ]; /* Q domain for the residual energy > 0 */ + +} SKP_Silk_encoder_control_FIX; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/pkg/silk/csilk/SKP_Silk_sum_sqr_shift.c b/pkg/silk/csilk/SKP_Silk_sum_sqr_shift.c new file mode 100644 index 0000000..a67ecbe --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_sum_sqr_shift.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_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" +#if (EMBEDDED_ARM<5) +/* 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; +} + +#endif diff --git a/pkg/silk/csilk/SKP_Silk_tables.h b/pkg/silk/csilk/SKP_Silk_tables.h new file mode 100644 index 0000000..37613bd --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_tables_LTP.c b/pkg/silk/csilk/SKP_Silk_tables_LTP.c new file mode 100644 index 0000000..77533ab --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_tables_NLSF_CB0_10.c b/pkg/silk/csilk/SKP_Silk_tables_NLSF_CB0_10.c new file mode 100644 index 0000000..d91bda3 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_tables_NLSF_CB0_10.h b/pkg/silk/csilk/SKP_Silk_tables_NLSF_CB0_10.h new file mode 100644 index 0000000..37e2906 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_tables_NLSF_CB0_16.c b/pkg/silk/csilk/SKP_Silk_tables_NLSF_CB0_16.c new file mode 100644 index 0000000..cfa87c6 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_tables_NLSF_CB0_16.h b/pkg/silk/csilk/SKP_Silk_tables_NLSF_CB0_16.h new file mode 100644 index 0000000..bf110e5 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_tables_NLSF_CB1_10.c b/pkg/silk/csilk/SKP_Silk_tables_NLSF_CB1_10.c new file mode 100644 index 0000000..46b3543 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_tables_NLSF_CB1_10.h b/pkg/silk/csilk/SKP_Silk_tables_NLSF_CB1_10.h new file mode 100644 index 0000000..22fddf1 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_tables_NLSF_CB1_16.c b/pkg/silk/csilk/SKP_Silk_tables_NLSF_CB1_16.c new file mode 100644 index 0000000..e68aedc --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_tables_NLSF_CB1_16.h b/pkg/silk/csilk/SKP_Silk_tables_NLSF_CB1_16.h new file mode 100644 index 0000000..ca63a44 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_tables_gain.c b/pkg/silk/csilk/SKP_Silk_tables_gain.c new file mode 100644 index 0000000..7556123 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_tables_other.c b/pkg/silk/csilk/SKP_Silk_tables_other.c new file mode 100644 index 0000000..27bba2b --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_tables_pitch_lag.c b/pkg/silk/csilk/SKP_Silk_tables_pitch_lag.c new file mode 100644 index 0000000..555bc67 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_tables_pulses_per_block.c b/pkg/silk/csilk/SKP_Silk_tables_pulses_per_block.c new file mode 100644 index 0000000..b5803d4 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_tables_sign.c b/pkg/silk/csilk/SKP_Silk_tables_sign.c new file mode 100644 index 0000000..96fc34d --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_tables_type_offset.c b/pkg/silk/csilk/SKP_Silk_tables_type_offset.c new file mode 100644 index 0000000..7effe38 --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_tuning_parameters.h b/pkg/silk/csilk/SKP_Silk_tuning_parameters.h new file mode 100644 index 0000000..09b96ed --- /dev/null +++ b/pkg/silk/csilk/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/pkg/silk/csilk/SKP_Silk_typedef.h b/pkg/silk/csilk/SKP_Silk_typedef.h new file mode 100644 index 0000000..5e1d2e7 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_typedef.h @@ -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. +***********************************************************************/ + +#ifndef _SKP_SILK_API_TYPDEF_H_ +#define _SKP_SILK_API_TYPDEF_H_ + +#ifndef SKP_USE_DOUBLE_PRECISION_FLOATS +#define SKP_USE_DOUBLE_PRECISION_FLOATS 0 +#endif + +#include +#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/pkg/silk/csilk/SKP_Silk_warped_autocorrelation_FIX.c b/pkg/silk/csilk/SKP_Silk_warped_autocorrelation_FIX.c new file mode 100644 index 0000000..6adb627 --- /dev/null +++ b/pkg/silk/csilk/SKP_Silk_warped_autocorrelation_FIX.c @@ -0,0 +1,88 @@ +/*********************************************************************** +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_FIX.h" + +#define QC 10 +#define QS 14 + + +#if EMBEDDED_ARM<6 +/* Autocorrelations for a warped frequency axis */ +void SKP_Silk_warped_autocorrelation_FIX( + SKP_int32 *corr, /* O Result [order + 1] */ + SKP_int *scale, /* O Scaling of the correlation vector */ + const SKP_int16 *input, /* I Input data to correlate */ + const SKP_int16 warping_Q16, /* I Warping coefficient */ + const SKP_int length, /* I Length of input */ + const SKP_int order /* I Correlation order (even) */ +) +{ + SKP_int n, i, lsh; + SKP_int32 tmp1_QS, tmp2_QS; + SKP_int32 state_QS[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; + SKP_int64 corr_QC[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; + + /* Order must be even */ + SKP_assert( ( order & 1 ) == 0 ); + SKP_assert( 2 * QS - QC >= 0 ); + + /* Loop over samples */ + for( n = 0; n < length; n++ ) { + tmp1_QS = SKP_LSHIFT32( ( SKP_int32 )input[ n ], QS ); + /* Loop over allpass sections */ + for( i = 0; i < order; i += 2 ) { + /* Output of allpass section */ + tmp2_QS = SKP_SMLAWB( state_QS[ i ], state_QS[ i + 1 ] - tmp1_QS, warping_Q16 ); + state_QS[ i ] = tmp1_QS; + corr_QC[ i ] += SKP_RSHIFT64( SKP_SMULL( tmp1_QS, state_QS[ 0 ] ), 2 * QS - QC ); + /* Output of allpass section */ + tmp1_QS = SKP_SMLAWB( state_QS[ i + 1 ], state_QS[ i + 2 ] - tmp2_QS, warping_Q16 ); + state_QS[ i + 1 ] = tmp2_QS; + corr_QC[ i + 1 ] += SKP_RSHIFT64( SKP_SMULL( tmp2_QS, state_QS[ 0 ] ), 2 * QS - QC ); + } + state_QS[ order ] = tmp1_QS; + corr_QC[ order ] += SKP_RSHIFT64( SKP_SMULL( tmp1_QS, state_QS[ 0 ] ), 2 * QS - QC ); + } + + lsh = SKP_Silk_CLZ64( corr_QC[ 0 ] ) - 35; + lsh = SKP_LIMIT( lsh, -12 - QC, 30 - QC ); + *scale = -( QC + lsh ); + SKP_assert( *scale >= -30 && *scale <= 12 ); + if( lsh >= 0 ) { + for( i = 0; i < order + 1; i++ ) { + corr[ i ] = ( SKP_int32 )SKP_CHECK_FIT32( SKP_LSHIFT64( corr_QC[ i ], lsh ) ); + } + } else { + for( i = 0; i < order + 1; i++ ) { + corr[ i ] = ( SKP_int32 )SKP_CHECK_FIT32( SKP_RSHIFT64( corr_QC[ i ], -lsh ) ); + } + } + SKP_assert( corr_QC[ 0 ] >= 0 ); // If breaking, decrease QC +} +#endif + diff --git a/pkg/silk/csilk/skp_silk_sdk.h b/pkg/silk/csilk/skp_silk_sdk.h new file mode 100644 index 0000000..811ed71 --- /dev/null +++ b/pkg/silk/csilk/skp_silk_sdk.h @@ -0,0 +1,11 @@ +#ifndef __SKP_SILK_SDK_H +#define __SKP_SILK_SDK_H + +struct silk_handle; + +struct silk_handle *silk_decoder_init(void); +void silk_decoder_deinit(struct silk_handle *h); +int silk_decoder_process(struct silk_handle *h, unsigned char *frame, int frame_size, unsigned char *output_payload, int output_len); +int silk_decoder_set_sample_rate(struct silk_handle *h, int rate); + +#endif /* __SKP_SILK_SDK_H */ diff --git a/pkg/silk/silk.go b/pkg/silk/silk.go new file mode 100644 index 0000000..9c34607 --- /dev/null +++ b/pkg/silk/silk.go @@ -0,0 +1,122 @@ +package silk + +import ( + "bytes" + "encoding/binary" + "fmt" + "unsafe" +) + +/* +#cgo CFLAGS: -I./csilk/ +#include +#include "skp_silk_sdk.h" +*/ +import "C" + +const ( + MAX_BYTES_PER_FRAME = 1024 + MAX_INPUT_FRAMES = 5 + MAX_FRAME_LENGTH = 480 + FRAME_LENGTH_MS = 20 + MAX_API_FS_KHZ = 48 +) + +type Handle *C.struct_silk_handle + +type Decoder struct { + handle Handle + remainder []byte + closed bool + foundHead bool +} + +func SilkInit() *Decoder { + h := C.silk_decoder_init() + decoder := &Decoder{h, make([]byte, 0), false, false} + + return decoder +} + +func (d *Decoder) SetSampleRate(rate int) { + C.silk_decoder_set_sample_rate(d.handle, C.int(rate)) +} + +func (d *Decoder) Decode(buf []byte) []byte { + d.remainder = append(d.remainder, buf...) + + if len(buf) == 0 || d.closed { + return make([]byte, 0) + } + + if !d.foundHead { + var head []byte + if d.remainder[0] == 0x02 { + head = d.remainder[1:10] + d.remainder = d.remainder[10:] + } else { + head = d.remainder[0:9] + d.remainder = d.remainder[9:] + } + + if string(head) == "#!SILK_V3" { + d.foundHead = true + } else { + fmt.Println("not found head") + return make([]byte, 0) + } + } + + // fmt.Println("remainder:", d.remainder[0:10]) + out := make([]byte, 0) + for { + if len(d.remainder) < 2 { + break + } + buffer := bytes.NewBuffer(d.remainder[0:2]) + // fmt.Println("remainder:", d.remainder[0:2]) + + var nlen int16 + if err := binary.Read(buffer, binary.LittleEndian, &nlen); err != nil { + fmt.Println("Error reading int16:", err) + d.remainder = d.remainder[2:] + return make([]byte, 0) + } + + if nlen <= 0 { + fmt.Println("d.remainder:", d.remainder) + d.remainder = d.remainder[2:] + continue + } + // fmt.Println("nlen:", nlen) + + if len(d.remainder) < (int(nlen) + 2) { + break + } + + frame := d.remainder[2 : 2+nlen] + // fmt.Println("frame:", frame) + payload_len := ((FRAME_LENGTH_MS * MAX_API_FS_KHZ) << 1) * MAX_INPUT_FRAMES + payload := make([]byte, payload_len) + cframe := (*C.uchar)(unsafe.Pointer(&frame[0])) + cpayload := (*C.uchar)(unsafe.Pointer(&payload[0])) + outlen := C.int(C.silk_decoder_process(d.handle, cframe, C.int(nlen), cpayload, C.int(payload_len))) + append_payload := payload[0:outlen] + out = append(out, append_payload...) + d.remainder = d.remainder[2+nlen:] + } + + return out +} + +func (d *Decoder) Close() { + if !d.closed { + d.closed = true + C.silk_decoder_deinit(d.handle) + } +} + +func (d *Decoder) Flush() []byte { + var tmp []byte + return d.Decode(tmp) +} diff --git a/pkg/silk/writer.go b/pkg/silk/writer.go new file mode 100644 index 0000000..fdbf1bc --- /dev/null +++ b/pkg/silk/writer.go @@ -0,0 +1,41 @@ +package silk + +import ( + "io" +) + +type SilkWriter struct { + output io.Writer + Decoder *Decoder + DecodedChunkSize int +} + +func NewWriter(out io.Writer) *SilkWriter { + writer := &SilkWriter{out, SilkInit(), 0} + return writer +} + +func (sw *SilkWriter) Write(p []byte) (int, error) { + // fmt.Println("silk Write len:", len(p)) + out := sw.Decoder.Decode(p) + sw.DecodedChunkSize = len(out) + + if sw.DecodedChunkSize > 0 { + _, err := sw.output.Write(out) + if err != nil { + return 0, err + } + } + + return len(p), nil +} + +func (sw *SilkWriter) Close() error { + out := sw.Decoder.Flush() + if len(out) == 0 { + return nil + } + sw.Decoder.Close() + _, err := sw.output.Write(out) + return err +} diff --git a/pkg/silk/z_link_silk_c.c b/pkg/silk/z_link_silk_c.c new file mode 100644 index 0000000..7d90e89 --- /dev/null +++ b/pkg/silk/z_link_silk_c.c @@ -0,0 +1,111 @@ +#include "./csilk/SKP_Silk_NLSF_MSVQ_decode.c" +#include "./csilk/SKP_Silk_scale_copy_vector16.c" +#include "./csilk/SKP_Silk_NLSF2A.c" +#include "./csilk/SKP_Silk_LTP_scale_ctrl_FIX.c" +#include "./csilk/SKP_Silk_NLSF_VQ_weights_laroia.c" +#include "./csilk/SKP_Silk_encode_parameters.c" +#include "./csilk/SKP_Silk_tables_NLSF_CB0_10.c" +#include "./csilk/SKP_Silk_autocorr.c" +#include "./csilk/SKP_Silk_decode_parameters.c" +#include "./csilk/SKP_Silk_k2a_Q16.c" +#include "./csilk/SKP_Silk_NLSF_stabilize.c" +#include "./csilk/SKP_Silk_decode_pitch.c" +#include "./csilk/SKP_Silk_tables_NLSF_CB1_16.c" +#include "./csilk/SKP_Silk_HP_variable_cutoff_FIX.c" +#include "./csilk/SKP_Silk_apply_sine_window.c" +#include "./csilk/SKP_Silk_decode_core.c" +#include "./csilk/SKP_Silk_resampler_down2_3.c" +#include "./csilk/SKP_Silk_log2lin.c" +#include "./csilk/SKP_Silk_NLSF_VQ_rate_distortion_FIX.c" +#include "./csilk/SKP_Silk_PLC.c" +#include "./csilk/SKP_Silk_VQ_nearest_neighbor_FIX.c" +#include "./csilk/SKP_Silk_quant_LTP_gains_FIX.c" +#include "./csilk/SKP_Silk_array_maxabs.c" +#include "./csilk/SKP_Silk_resampler_private_down_FIR.c" +#include "./csilk/SKP_Silk_tables_other.c" +#include "./csilk/Decoder_Api.c" +#include "./csilk/SKP_Silk_NLSF2A_stable.c" +#include "./csilk/SKP_Silk_find_pitch_lags_FIX.c" +#include "./csilk/SKP_Silk_CNG.c" +#include "./csilk/SKP_Silk_LPC_synthesis_order16.c" +#include "./csilk/SKP_Silk_corrMatrix_FIX.c" +#include "./csilk/SKP_Silk_init_encoder_FIX.c" +#include "./csilk/SKP_Silk_sort.c" +#include "./csilk/SKP_Silk_MA.c" +#include "./csilk/SKP_Silk_process_gains_FIX.c" +#include "./csilk/SKP_Silk_decode_pulses.c" +#include "./csilk/SKP_Silk_find_LTP_FIX.c" +#include "./csilk/SKP_Silk_resampler_private_AR2.c" +#include "./csilk/SKP_Silk_shell_coder.c" +#include "./csilk/SKP_Silk_LP_variable_cutoff.c" +#include "./csilk/SKP_Silk_inner_prod_aligned.c" +#include "./csilk/SKP_Silk_tables_pitch_lag.c" +#include "./csilk/SKP_Silk_warped_autocorrelation_FIX.c" +#include "./csilk/SKP_Silk_tables_LTP.c" +#include "./csilk/SKP_Silk_process_NLSFs_FIX.c" +#include "./csilk/SKP_Silk_ana_filt_bank_1.c" +#include "./csilk/SKP_Silk_NSQ.c" +#include "./csilk/SKP_Silk_biquad.c" +#include "./csilk/SKP_Silk_biquad_alt.c" +#include "./csilk/SKP_Silk_tables_NLSF_CB1_10.c" +#include "./csilk/SKP_Silk_scale_vector.c" +#include "./csilk/SKP_Silk_resampler.c" +#include "./csilk/SKP_Silk_range_coder.c" +#include "./csilk/SKP_Silk_decoder_set_fs.c" +#include "./csilk/SKP_Silk_lin2log.c" +#include "./csilk/SKP_Silk_tables_gain.c" +#include "./csilk/SKP_Silk_k2a.c" +#include "./csilk/SKP_Silk_sum_sqr_shift.c" +#include "./csilk/SKP_Silk_resampler_private_ARMA4.c" +#include "./csilk/SKP_Silk_resampler_private_copy.c" +#include "./csilk/SKP_Silk_resampler_rom.c" +#include "./csilk/SKP_Silk_noise_shape_analysis_FIX.c" +#include "./csilk/SKP_Silk_solve_LS_FIX.c" +#include "./csilk/SKP_Silk_div_oabi.c" +#include "./csilk/SKP_Silk_bwexpander.c" +#include "./csilk/SKP_Silk_find_pred_coefs_FIX.c" +#include "./csilk/SKP_Silk_resampler_down2.c" +#include "./csilk/SKP_Silk_enc_API.c" +#include "./csilk/SKP_Silk_resampler_private_up2_HQ.c" +#include "./csilk/SKP_Silk_resampler_private_up4.c" +#include "./csilk/SKP_Silk_LBRR_reset.c" +#include "./csilk/SKP_Silk_detect_SWB_input.c" +#include "./csilk/SKP_Silk_control_audio_bandwidth.c" +#include "./csilk/SKP_Silk_prefilter_FIX.c" +#include "./csilk/SKP_Silk_find_LPC_FIX.c" +#include "./csilk/SKP_Silk_resampler_up2.c" +#include "./csilk/SKP_Silk_bwexpander_32.c" +#include "./csilk/SKP_Silk_encode_pulses.c" +#include "./csilk/SKP_Silk_NLSF_MSVQ_encode_FIX.c" +#include "./csilk/SKP_Silk_tables_pulses_per_block.c" +#include "./csilk/SKP_Silk_control_codec_FIX.c" +#include "./csilk/SKP_Silk_VAD.c" +#include "./csilk/SKP_Silk_NSQ_del_dec.c" +#include "./csilk/SKP_Silk_code_signs.c" +#include "./csilk/SKP_Silk_decode_frame.c" +#include "./csilk/SKP_Silk_burg_modified.c" +#include "./csilk/SKP_Silk_sigm_Q15.c" +#include "./csilk/SKP_Silk_pitch_analysis_core.c" +#include "./csilk/SKP_Silk_NLSF_VQ_sum_error_FIX.c" +#include "./csilk/SKP_Silk_interpolate.c" +#include "./csilk/SKP_Silk_LSF_cos_table.c" +#include "./csilk/SKP_Silk_encode_frame_FIX.c" +#include "./csilk/SKP_Silk_resampler_private_IIR_FIR.c" +#include "./csilk/SKP_Silk_schur.c" +#include "./csilk/SKP_Silk_LPC_synthesis_filter.c" +#include "./csilk/SKP_Silk_pitch_est_tables.c" +#include "./csilk/SKP_Silk_A2NLSF.c" +#include "./csilk/SKP_Silk_residual_energy16_FIX.c" +#include "./csilk/SKP_Silk_LPC_inv_pred_gain.c" +#include "./csilk/SKP_Silk_resampler_down3.c" +#include "./csilk/SKP_Silk_schur64.c" +#include "./csilk/SKP_Silk_gain_quant.c" +#include "./csilk/SKP_Silk_residual_energy_FIX.c" +#include "./csilk/SKP_Silk_resampler_private_down4.c" +#include "./csilk/SKP_Silk_create_init_destroy.c" +#include "./csilk/SKP_Silk_regularize_correlations_FIX.c" +#include "./csilk/SKP_Silk_LTP_analysis_filter_FIX.c" +#include "./csilk/SKP_Silk_dec_API.c" +#include "./csilk/SKP_Silk_tables_sign.c" +#include "./csilk/SKP_Silk_tables_NLSF_CB0_16.c" +#include "./csilk/SKP_Silk_tables_type_offset.c" diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go new file mode 100644 index 0000000..c7af718 --- /dev/null +++ b/pkg/utils/utils.go @@ -0,0 +1,77 @@ +package utils + +import ( + "fmt" + "log" + "os" + "os/exec" + "strings" + + "github.com/pkg/browser" + "golang.org/x/sys/windows/registry" +) + +func getDefaultProgram(fileExtension string) (string, error) { + key, err := registry.OpenKey(registry.CLASSES_ROOT, fmt.Sprintf(`.%s`, fileExtension), registry.QUERY_VALUE) + if err != nil { + return "", err + } + defer key.Close() + + // 读取默认程序关联值 + defaultProgram, _, err := key.GetStringValue("") + if err != nil { + return "", err + } + + return defaultProgram, nil +} + +func hasDefaultProgram(fileExtension string) bool { + prog, err := getDefaultProgram(fileExtension) + if err != nil { + log.Println("getDefaultProgram Error:", err) + return false + } + + if prog == "" { + return false + } + + return true +} + +func OpenFileOrExplorer(filePath string, explorer bool) error { + if _, err := os.Stat(filePath); err != nil { + log.Printf("%s %v\n", filePath, err) + return err + } + + canOpen := false + fileExtension := "" + index := strings.LastIndex(filePath, ".") + if index > 0 { + fileExtension = filePath[index+1:] + canOpen = hasDefaultProgram(fileExtension) + } + + if canOpen && !explorer { + return browser.OpenFile(filePath) + } + + commandArgs := []string{"/select,", filePath} + fmt.Println("cmd:", "explorer", commandArgs) + + // 创建一个Cmd结构体表示要执行的命令 + cmd := exec.Command("explorer", commandArgs...) + + // 执行命令并等待它完成 + err := cmd.Run() + if err != nil { + log.Printf("Error executing command: %s\n", err) + // return err + } + + fmt.Println("Command executed successfully") + return nil +} diff --git a/pkg/wechat/msg.pb.go b/pkg/wechat/msg.pb.go new file mode 100644 index 0000000..ab16df5 --- /dev/null +++ b/pkg/wechat/msg.pb.go @@ -0,0 +1,301 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.33.0 +// protoc v3.6.1 +// source: msg.proto + +package wechat + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type SubMessage1 struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Field1 int32 `protobuf:"varint,1,opt,name=field1,proto3" json:"field1,omitempty"` + Field2 int32 `protobuf:"varint,2,opt,name=field2,proto3" json:"field2,omitempty"` +} + +func (x *SubMessage1) Reset() { + *x = SubMessage1{} + if protoimpl.UnsafeEnabled { + mi := &file_msg_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SubMessage1) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SubMessage1) ProtoMessage() {} + +func (x *SubMessage1) ProtoReflect() protoreflect.Message { + mi := &file_msg_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SubMessage1.ProtoReflect.Descriptor instead. +func (*SubMessage1) Descriptor() ([]byte, []int) { + return file_msg_proto_rawDescGZIP(), []int{0} +} + +func (x *SubMessage1) GetField1() int32 { + if x != nil { + return x.Field1 + } + return 0 +} + +func (x *SubMessage1) GetField2() int32 { + if x != nil { + return x.Field2 + } + return 0 +} + +type SubMessage2 struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Field1 int32 `protobuf:"varint,1,opt,name=field1,proto3" json:"field1,omitempty"` + Field2 string `protobuf:"bytes,2,opt,name=field2,proto3" json:"field2,omitempty"` +} + +func (x *SubMessage2) Reset() { + *x = SubMessage2{} + if protoimpl.UnsafeEnabled { + mi := &file_msg_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SubMessage2) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SubMessage2) ProtoMessage() {} + +func (x *SubMessage2) ProtoReflect() protoreflect.Message { + mi := &file_msg_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SubMessage2.ProtoReflect.Descriptor instead. +func (*SubMessage2) Descriptor() ([]byte, []int) { + return file_msg_proto_rawDescGZIP(), []int{1} +} + +func (x *SubMessage2) GetField1() int32 { + if x != nil { + return x.Field1 + } + return 0 +} + +func (x *SubMessage2) GetField2() string { + if x != nil { + return x.Field2 + } + return "" +} + +type MessageBytesExtra struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Message1 *SubMessage1 `protobuf:"bytes,1,opt,name=message1,proto3" json:"message1,omitempty"` + Message2 []*SubMessage2 `protobuf:"bytes,3,rep,name=message2,proto3" json:"message2,omitempty"` +} + +func (x *MessageBytesExtra) Reset() { + *x = MessageBytesExtra{} + if protoimpl.UnsafeEnabled { + mi := &file_msg_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MessageBytesExtra) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MessageBytesExtra) ProtoMessage() {} + +func (x *MessageBytesExtra) ProtoReflect() protoreflect.Message { + mi := &file_msg_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MessageBytesExtra.ProtoReflect.Descriptor instead. +func (*MessageBytesExtra) Descriptor() ([]byte, []int) { + return file_msg_proto_rawDescGZIP(), []int{2} +} + +func (x *MessageBytesExtra) GetMessage1() *SubMessage1 { + if x != nil { + return x.Message1 + } + return nil +} + +func (x *MessageBytesExtra) GetMessage2() []*SubMessage2 { + if x != nil { + return x.Message2 + } + return nil +} + +var File_msg_proto protoreflect.FileDescriptor + +var file_msg_proto_rawDesc = []byte{ + 0x0a, 0x09, 0x6d, 0x73, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0c, 0x61, 0x70, 0x70, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x22, 0x3d, 0x0a, 0x0b, 0x53, 0x75, 0x62, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x31, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, + 0x64, 0x31, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, + 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x22, 0x3d, 0x0a, 0x0b, 0x53, 0x75, 0x62, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, + 0x31, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x12, + 0x16, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x22, 0x81, 0x01, 0x0a, 0x11, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x45, 0x78, 0x74, 0x72, 0x61, 0x12, 0x35, 0x0a, + 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x31, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x19, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, + 0x75, 0x62, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x31, 0x52, 0x08, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x31, 0x12, 0x35, 0x0a, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, + 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x75, 0x62, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x32, 0x52, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0x42, 0x09, 0x5a, 0x07, 0x2e, + 0x3b, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_msg_proto_rawDescOnce sync.Once + file_msg_proto_rawDescData = file_msg_proto_rawDesc +) + +func file_msg_proto_rawDescGZIP() []byte { + file_msg_proto_rawDescOnce.Do(func() { + file_msg_proto_rawDescData = protoimpl.X.CompressGZIP(file_msg_proto_rawDescData) + }) + return file_msg_proto_rawDescData +} + +var file_msg_proto_msgTypes = make([]protoimpl.MessageInfo, 3) +var file_msg_proto_goTypes = []interface{}{ + (*SubMessage1)(nil), // 0: app.protobuf.SubMessage1 + (*SubMessage2)(nil), // 1: app.protobuf.SubMessage2 + (*MessageBytesExtra)(nil), // 2: app.protobuf.MessageBytesExtra +} +var file_msg_proto_depIdxs = []int32{ + 0, // 0: app.protobuf.MessageBytesExtra.message1:type_name -> app.protobuf.SubMessage1 + 1, // 1: app.protobuf.MessageBytesExtra.message2:type_name -> app.protobuf.SubMessage2 + 2, // [2:2] is the sub-list for method output_type + 2, // [2:2] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_msg_proto_init() } +func file_msg_proto_init() { + if File_msg_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_msg_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SubMessage1); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_msg_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SubMessage2); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_msg_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MessageBytesExtra); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_msg_proto_rawDesc, + NumEnums: 0, + NumMessages: 3, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_msg_proto_goTypes, + DependencyIndexes: file_msg_proto_depIdxs, + MessageInfos: file_msg_proto_msgTypes, + }.Build() + File_msg_proto = out.File + file_msg_proto_rawDesc = nil + file_msg_proto_goTypes = nil + file_msg_proto_depIdxs = nil +} diff --git a/pkg/wechat/wechat.go b/pkg/wechat/wechat.go new file mode 100644 index 0000000..2815392 --- /dev/null +++ b/pkg/wechat/wechat.go @@ -0,0 +1,653 @@ +package wechat + +import ( + "bufio" + "bytes" + "crypto/hmac" + "crypto/sha1" + "database/sql" + "encoding/binary" + "encoding/hex" + "errors" + "fmt" + "io" + "log" + "os" + "path/filepath" + "strings" + "sync" + "unsafe" + "wechatDataBackup/pkg/lame" + "wechatDataBackup/pkg/silk" + + _ "github.com/mattn/go-sqlite3" + "github.com/shirou/gopsutil/v3/process" + "golang.org/x/sys/windows" +) + +type WeChatInfo struct { + ProcessID uint32 + FilePath string + AcountName string + Version string + Is64Bits bool + DllBaseAddr uintptr + DllBaseSize uint32 + DBKey string +} + +type wechatMediaMSG struct { + Key string + MsgSvrID int + Buf []byte +} + +func GetWeChatAllInfo() (WeChatInfo, error) { + info, err := GetWeChatInfo() + if err != nil { + log.Println("GetWeChatInfo:", err) + return info, err + } + + info.DBKey = GetWeChatKey(&info) + + return info, nil +} + +func ExportWeChatAllData(info WeChatInfo, expPath string, progress chan<- string) { + defer close(progress) + fileInfo, err := os.Stat(info.FilePath) + if err != nil || !fileInfo.IsDir() { + progress <- fmt.Sprintf("{\"status\":\"error\", \"result\":\"%s error\"}", info.FilePath) + return + } + if !exportWeChatDateBase(info, expPath, progress) { + return + } + + exportWeChatBat(info, expPath, progress) + exportWeChatVideoAndFile(info, expPath, progress) + exportWeChatVoice(info, expPath, progress) +} + +func exportWeChatVoice(info WeChatInfo, expPath string, progress chan<- string) { + progress <- "{\"status\":\"processing\", \"result\":\"export WeChat voice start\", \"progress\": 61}" + + voicePath := fmt.Sprintf("%s\\FileStorage\\Voice", expPath) + if _, err := os.Stat(voicePath); err != nil { + if err := os.MkdirAll(voicePath, 0644); err != nil { + log.Printf("MkdirAll %s failed: %v\n", voicePath, err) + progress <- fmt.Sprintf("{\"status\":\"error\", \"result\":\"%v error\"}", err) + return + } + } + + var wg sync.WaitGroup + index := -1 + MSGChan := make(chan wechatMediaMSG, 100) + go func() { + for { + index += 1 + mediaMSGDB := fmt.Sprintf("%s\\Msg\\Multi\\MediaMSG%d.db", expPath, index) + _, err := os.Stat(mediaMSGDB) + if err != nil { + break + } + + db, err := sql.Open("sqlite3", mediaMSGDB) + if err != nil { + log.Printf("open %s failed: %v\n", mediaMSGDB, err) + continue + } + defer db.Close() + + rows, err := db.Query("select Key, Reserved0, Buf from Media;") + if err != nil { + log.Printf("Query failed: %v\n", err) + continue + } + + msg := wechatMediaMSG{} + for rows.Next() { + err := rows.Scan(&msg.Key, &msg.MsgSvrID, &msg.Buf) + if err != nil { + log.Println("Scan failed: ", err) + break + } + + MSGChan <- msg + } + } + close(MSGChan) + }() + + for i := 0; i < 20; i++ { + wg.Add(1) + go func() { + defer wg.Done() + for msg := range MSGChan { + mp3Path := fmt.Sprintf("%s\\%d.mp3", voicePath, msg.MsgSvrID) + _, err := os.Stat(mp3Path) + if err == nil { + continue + } + + err = silkToMp3(msg.Buf[:], mp3Path) + if err != nil { + log.Printf("silkToMp3 %s failed: %v\n", mp3Path, err) + } + } + }() + } + wg.Wait() + progress <- "{\"status\":\"processing\", \"result\":\"export WeChat voice end\", \"progress\": 100}" +} + +func exportWeChatVideoAndFile(info WeChatInfo, expPath string, progress chan<- string) { + progress <- "{\"status\":\"processing\", \"result\":\"export WeChat Video and File start\", , \"progress\": 41}" + videoRootPath := info.FilePath + "\\FileStorage\\Video" + fileRootPath := info.FilePath + "\\FileStorage\\File" + cacheRootPath := info.FilePath + "\\FileStorage\\Cache" + rootPaths := []string{videoRootPath, fileRootPath, cacheRootPath} + var wg sync.WaitGroup + taskChan := make(chan [2]string, 100) + go func() { + for _, rootPath := range rootPaths { + log.Println(rootPath) + err := filepath.Walk(rootPath, func(path string, finfo os.FileInfo, err error) error { + if err != nil { + log.Printf("filepath.Walk:%v\n", err) + return err + } + + if !finfo.IsDir() { + expFile := expPath + path[len(info.FilePath):] + _, err := os.Stat(filepath.Dir(expFile)) + if err != nil { + os.MkdirAll(filepath.Dir(expFile), 0644) + } + + _, err = os.Stat(expFile) + if err == nil { + return nil + } + task := [2]string{path, expFile} + taskChan <- task + return nil + } + + return nil + }) + if err != nil { + log.Println("filepath.Walk:", err) + progress <- fmt.Sprintf("{\"status\":\"error\", \"result\":\"%v\"}", err) + } + } + close(taskChan) + }() + + for i := 1; i < 30; i++ { + wg.Add(1) + go func() { + defer wg.Done() + for task := range taskChan { + _, err := copyFile(task[0], task[1]) + if err != nil { + log.Println("DecryptDat:", err) + progress <- fmt.Sprintf("{\"status\":\"error\", \"result\":\"copyFile %v\"}", err) + } + } + }() + } + wg.Wait() + progress <- "{\"status\":\"processing\", \"result\":\"export WeChat Video and File end\", \"progress\": 60}" +} + +func exportWeChatBat(info WeChatInfo, expPath string, progress chan<- string) { + progress <- "{\"status\":\"processing\", \"result\":\"export WeChat Dat start\", \"progress\": 21}" + datRootPath := info.FilePath + "\\FileStorage\\MsgAttach" + fileInfo, err := os.Stat(datRootPath) + if err != nil || !fileInfo.IsDir() { + progress <- fmt.Sprintf("{\"status\":\"error\", \"result\":\"%s error\"}", datRootPath) + return + } + + var wg sync.WaitGroup + taskChan := make(chan [2]string, 100) + go func() { + err = filepath.Walk(datRootPath, func(path string, finfo os.FileInfo, err error) error { + if err != nil { + log.Printf("filepath.Walk:%v\n", err) + return err + } + + if !finfo.IsDir() && strings.HasSuffix(path, ".dat") { + expFile := expPath + path[len(info.FilePath):] + _, err := os.Stat(filepath.Dir(expFile)) + if err != nil { + os.MkdirAll(filepath.Dir(expFile), 0644) + } + + _, err = os.Stat(expFile) + if err == nil { + return nil + } + + task := [2]string{path, expFile} + taskChan <- task + return nil + } + + return nil + }) + + if err != nil { + log.Println("filepath.Walk:", err) + progress <- fmt.Sprintf("{\"status\":\"error\", \"result\":\"%v\"}", err) + } + close(taskChan) + }() + + for i := 1; i < 30; i++ { + wg.Add(1) + go func() { + defer wg.Done() + for task := range taskChan { + err = DecryptDat(task[0], task[1]) + if err != nil { + log.Println("DecryptDat:", err) + progress <- fmt.Sprintf("{\"status\":\"error\", \"result\":\"DecryptDat %v\"}", err) + } + } + }() + } + wg.Wait() + progress <- "{\"status\":\"processing\", \"result\":\"export WeChat Dat end\", \"progress\": 40}" +} + +func exportWeChatDateBase(info WeChatInfo, expPath string, progress chan<- string) bool { + + progress <- "{\"status\":\"processing\", \"result\":\"export WeChat DateBase start\", \"progress\": 1}" + + dbKey, err := hex.DecodeString(info.DBKey) + if err != nil { + log.Println("DecodeString:", err) + progress <- fmt.Sprintf("{\"status\":\"error\", \"result\":\"%v\"}", err) + return false + } + + var wg sync.WaitGroup + taskChan := make(chan [2]string, 20) + go func() { + err = filepath.Walk(info.FilePath+"\\Msg", func(path string, finfo os.FileInfo, err error) error { + if err != nil { + log.Printf("filepath.Walk:%v\n", err) + return err + } + if !finfo.IsDir() && strings.HasSuffix(path, ".db") { + expFile := expPath + path[len(info.FilePath):] + _, err := os.Stat(filepath.Dir(expFile)) + if err != nil { + os.MkdirAll(filepath.Dir(expFile), 0644) + } + + task := [2]string{path, expFile} + taskChan <- task + } + + return nil + }) + if err != nil { + log.Println("filepath.Walk:", err) + progress <- fmt.Sprintf("{\"status\":\"error\", \"result\":\"%v\"}", err) + } + close(taskChan) + }() + + for i := 1; i < 20; i++ { + wg.Add(1) + go func() { + defer wg.Done() + for task := range taskChan { + if filepath.Base(task[0]) == "xInfo.db" { + copyFile(task[0], task[1]) + } else { + err = DecryptDataBase(task[0], dbKey, task[1]) + if err != nil { + log.Println("DecryptDataBase:", err) + progress <- fmt.Sprintf("{\"status\":\"error\", \"result\":\"%s %v\"}", task[0], err) + } + } + } + }() + } + wg.Wait() + progress <- "{\"status\":\"processing\", \"result\":\"export WeChat DateBase end\", \"progress\": 20}" + return true +} + +func GetWeChatInfo() (info WeChatInfo, rerr error) { + info = WeChatInfo{} + processes, err := process.Processes() + if err != nil { + log.Println("Error getting processes:", err) + rerr = err + return + } + + found := false + for _, p := range processes { + name, err := p.Name() + if err != nil { + continue + } + if name == "WeChat.exe" { + found = true + info.ProcessID = uint32(p.Pid) + info.Is64Bits, _ = Is64BitProcess(info.ProcessID) + log.Println("ProcessID", info.ProcessID) + files, err := p.OpenFiles() + if err != nil { + log.Println("OpenFiles failed") + return + } + + for _, f := range files { + if strings.HasSuffix(f.Path, "\\Media.db") { + // fmt.Printf("opened %s\n", f.Path[4:]) + filePath := f.Path[4:] + parts := strings.Split(filePath, string(filepath.Separator)) + if len(parts) < 4 { + return info, errors.New("Error filePath " + filePath) + } + info.FilePath = strings.Join(parts[:len(parts)-2], string(filepath.Separator)) + info.AcountName = strings.Join(parts[len(parts)-3:len(parts)-2], string(filepath.Separator)) + } + + } + + if len(info.FilePath) == 0 { + rerr = errors.New("wechat not log in") + return + } + + hModuleSnap, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPMODULE|windows.TH32CS_SNAPMODULE32, uint32(p.Pid)) + if err != nil { + log.Println("CreateToolhelp32Snapshot failed", err) + return + } + defer windows.CloseHandle(hModuleSnap) + + var me32 windows.ModuleEntry32 + me32.Size = uint32(windows.SizeofModuleEntry32) + + err = windows.Module32First(hModuleSnap, &me32) + if err != nil { + log.Println("Module32First failed", err) + return + } + + for ; err == nil; err = windows.Module32Next(hModuleSnap, &me32) { + if windows.UTF16ToString(me32.Module[:]) == "WeChatWin.dll" { + // fmt.Printf("MODULE NAME: %s\n", windows.UTF16ToString(me32.Module[:])) + // fmt.Printf("executable NAME: %s\n", windows.UTF16ToString(me32.ExePath[:])) + // fmt.Printf("base address: 0x%08X\n", me32.ModBaseAddr) + // fmt.Printf("base ModBaseSize: %d\n", me32.ModBaseSize) + info.DllBaseAddr = me32.ModBaseAddr + info.DllBaseSize = me32.ModBaseSize + + var zero windows.Handle + driverPath := windows.UTF16ToString(me32.ExePath[:]) + infoSize, err := windows.GetFileVersionInfoSize(driverPath, &zero) + if err != nil { + log.Println("GetFileVersionInfoSize failed", err) + return + } + versionInfo := make([]byte, infoSize) + if err = windows.GetFileVersionInfo(driverPath, 0, infoSize, unsafe.Pointer(&versionInfo[0])); err != nil { + log.Println("GetFileVersionInfo failed", err) + return + } + var fixedInfo *windows.VS_FIXEDFILEINFO + fixedInfoLen := uint32(unsafe.Sizeof(*fixedInfo)) + err = windows.VerQueryValue(unsafe.Pointer(&versionInfo[0]), `\`, (unsafe.Pointer)(&fixedInfo), &fixedInfoLen) + if err != nil { + log.Println("VerQueryValue failed", err) + return + } + // fmt.Printf("%s: v%d.%d.%d.%d\n", windows.UTF16ToString(me32.Module[:]), + // (fixedInfo.FileVersionMS>>16)&0xff, + // (fixedInfo.FileVersionMS>>0)&0xff, + // (fixedInfo.FileVersionLS>>16)&0xff, + // (fixedInfo.FileVersionLS>>0)&0xff) + + info.Version = fmt.Sprintf("%d.%d.%d.%d", + (fixedInfo.FileVersionMS>>16)&0xff, + (fixedInfo.FileVersionMS>>0)&0xff, + (fixedInfo.FileVersionLS>>16)&0xff, + (fixedInfo.FileVersionLS>>0)&0xff) + break + } + } + } + } + + if !found { + rerr = errors.New("not found process") + } + + return +} + +func Is64BitProcess(pid uint32) (bool, error) { + is64Bit := false + handle, err := windows.OpenProcess(windows.PROCESS_QUERY_INFORMATION, false, pid) + if err != nil { + log.Println("Error opening process:", err) + return is64Bit, errors.New("OpenProcess failed") + } + defer windows.CloseHandle(handle) + + err = windows.IsWow64Process(handle, &is64Bit) + if err != nil { + log.Println("Error IsWow64Process:", err) + } + return !is64Bit, err +} + +func GetWeChatKey(info *WeChatInfo) string { + handle, err := windows.OpenProcess(windows.PROCESS_QUERY_INFORMATION|windows.PROCESS_VM_READ, false, uint32(info.ProcessID)) + if err != nil { + log.Println("Error opening process:", err) + return "" + } + defer windows.CloseHandle(handle) + + buffer := make([]byte, info.DllBaseSize) + err = windows.ReadProcessMemory(handle, uintptr(info.DllBaseAddr), &buffer[0], uintptr(len(buffer)), nil) + if err != nil { + log.Println("Error ReadProcessMemory:", err) + return "" + } + + offset := 0 + // searchStr := []byte(info.AcountName) + for { + index := hasDeviceSybmol(buffer[offset:]) + if index == -1 { + fmt.Println("hasDeviceSybmolxxxx") + break + } + fmt.Printf("hasDeviceSybmol: 0x%X\n", index) + keys := findDBKeyPtr(buffer[offset:index], info.Is64Bits) + // fmt.Println("keys:", keys) + + key, err := findDBkey(handle, info.FilePath+"\\Msg\\Media.db", keys) + if err == nil { + // fmt.Println("key:", key) + return key + } + + offset += (index + 20) + } + + return "" +} + +func hasDeviceSybmol(buffer []byte) int { + sybmols := [...][]byte{ + {'a', 'n', 'd', 'r', 'o', 'i', 'd', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00}, + {'i', 'p', 'h', 'o', 'n', 'e', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00}, + {'i', 'p', 'a', 'd', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00}, + } + for _, syb := range sybmols { + if index := bytes.Index(buffer, syb); index != -1 { + return index + } + } + + return -1 +} + +func findDBKeyPtr(buffer []byte, is64Bits bool) [][]byte { + keys := make([][]byte, 0) + step := 8 + keyLen := []byte{0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} + if !is64Bits { + keyLen = keyLen[:4] + step = 4 + } + + offset := len(buffer) - step + for { + if bytes.Contains(buffer[offset:offset+step], keyLen) { + keys = append(keys, buffer[offset-step:offset]) + } + + offset -= step + if offset <= 0 { + break + } + } + + return keys +} + +func findDBkey(handle windows.Handle, path string, keys [][]byte) (string, error) { + var keyAddrPtr uint64 + addrBuffer := make([]byte, 0x08) + for _, key := range keys { + copy(addrBuffer, key) + err := binary.Read(bytes.NewReader(addrBuffer), binary.LittleEndian, &keyAddrPtr) + if err != nil { + log.Println("binary.Read:", err) + continue + } + if keyAddrPtr == 0x00 { + continue + } + log.Println("keyAddrPtr: 0x%X\n", keyAddrPtr) + keyBuffer := make([]byte, 0x20) + err = windows.ReadProcessMemory(handle, uintptr(keyAddrPtr), &keyBuffer[0], uintptr(len(keyBuffer)), nil) + if err != nil { + // fmt.Println("Error ReadProcessMemory:", err) + continue + } + if checkDataBaseKey(path, keyBuffer) { + return hex.EncodeToString(keyBuffer), nil + } + } + + return "", errors.New("not found key") +} + +func checkDataBaseKey(path string, password []byte) bool { + fp, err := os.Open(path) + if err != nil { + return false + } + defer fp.Close() + + fpReader := bufio.NewReaderSize(fp, defaultPageSize*100) + + buffer := make([]byte, defaultPageSize) + + n, err := fpReader.Read(buffer) + if err != nil && n != defaultPageSize { + log.Println("read failed:", err, n) + return false + } + + salt := buffer[:16] + key := pbkdf2HMAC(password, salt, defaultIter, keySize) + + page1 := buffer[16:defaultPageSize] + + macSalt := xorBytes(salt, 0x3a) + macKey := pbkdf2HMAC(key, macSalt, 2, keySize) + + hashMac := hmac.New(sha1.New, macKey) + hashMac.Write(page1[:len(page1)-32]) + hashMac.Write([]byte{1, 0, 0, 0}) + + return hmac.Equal(hashMac.Sum(nil), page1[len(page1)-32:len(page1)-12]) +} + +func (info WeChatInfo) String() string { + return fmt.Sprintf("PID: %d\nVersion: v%s\nBaseAddr: 0x%08X\nDllSize: %d\nIs 64Bits: %v\nFilePath %s\nAcountName: %s", + info.ProcessID, info.Version, info.DllBaseAddr, info.DllBaseSize, info.Is64Bits, info.FilePath, info.AcountName) +} + +func copyFile(src, dst string) (int64, error) { + sourceFile, err := os.Open(src) + if err != nil { + return 0, err + } + defer sourceFile.Close() + + destFile, err := os.Create(dst) + if err != nil { + return 0, err + } + defer destFile.Close() + + bytesWritten, err := io.Copy(destFile, sourceFile) + if err != nil { + return bytesWritten, err + } + + return bytesWritten, nil +} + +func silkToMp3(amrBuf []byte, mp3Path string) error { + amrReader := bytes.NewReader(amrBuf) + + var pcmBuffer bytes.Buffer + sr := silk.NewWriter(&pcmBuffer) + sr.Decoder.SetSampleRate(24000) + amrReader.WriteTo(sr) + sr.Close() + + if pcmBuffer.Len() == 0 { + return errors.New("silk to mp3 failed " + mp3Path) + } + + of, err := os.Create(mp3Path) + if err != nil { + return nil + } + defer of.Close() + + wr := lame.NewWriter(of) + wr.Encoder.SetInSamplerate(24000) + wr.Encoder.SetNumChannels(1) + wr.Encoder.SetBitrate(16) + wr.Encoder.SetQuality(7) + // IMPORTANT! + wr.Encoder.InitParams() + + pcmBuffer.WriteTo(wr) + wr.Close() + + return nil +} diff --git a/pkg/wechat/wechatDBDec.go b/pkg/wechat/wechatDBDec.go new file mode 100644 index 0000000..5c1a708 --- /dev/null +++ b/pkg/wechat/wechatDBDec.go @@ -0,0 +1,170 @@ +package wechat + +import ( + "bufio" + "crypto/aes" + "crypto/cipher" + "crypto/hmac" + "crypto/sha1" + "fmt" + "io" + "os" +) + +const ( + keySize = 32 + defaultIter = 64000 + defaultPageSize = 4096 +) + +func DecryptDataBase(path string, password []byte, expPath string) error { + sqliteFileHeader := []byte("SQLite format 3") + sqliteFileHeader = append(sqliteFileHeader, byte(0)) + + fp, err := os.Open(path) + if err != nil { + return err + } + defer fp.Close() + + fpReader := bufio.NewReaderSize(fp, defaultPageSize*100) + // fpReader := bufio.NewReader(fp) + + buffer := make([]byte, defaultPageSize) + + n, err := fpReader.Read(buffer) + if err != nil && n != defaultPageSize { + return fmt.Errorf("read failed") + } + + salt := buffer[:16] + key := pbkdf2HMAC(password, salt, defaultIter, keySize) + + page1 := buffer[16:defaultPageSize] + + macSalt := xorBytes(salt, 0x3a) + macKey := pbkdf2HMAC(key, macSalt, 2, keySize) + + hashMac := hmac.New(sha1.New, macKey) + hashMac.Write(page1[:len(page1)-32]) + hashMac.Write([]byte{1, 0, 0, 0}) + + if !hmac.Equal(hashMac.Sum(nil), page1[len(page1)-32:len(page1)-12]) { + return fmt.Errorf("incorrect password") + } + + outFilePath := expPath + outFile, err := os.Create(outFilePath) + if err != nil { + return err + } + defer outFile.Close() + + // Write SQLite file header + _, err = outFile.Write(sqliteFileHeader) + if err != nil { + return err + } + + block, err := aes.NewCipher(key) + if err != nil { + return err + } + + page1 = buffer[16:defaultPageSize] + iv := page1[len(page1)-48 : len(page1)-32] + stream := cipher.NewCBCDecrypter(block, iv) + decrypted := make([]byte, len(page1)-48) + stream.CryptBlocks(decrypted, page1[:len(page1)-48]) + _, err = outFile.Write(decrypted) + if err != nil { + return err + } + _, err = outFile.Write(page1[len(page1)-48:]) + if err != nil { + return err + } + + for { + n, err = fpReader.Read(buffer) + if err != nil { + if err == io.EOF { + break + } + return err + } else if n < defaultPageSize { + return fmt.Errorf("read data to short %d", n) + } + + iv := buffer[len(buffer)-48 : len(buffer)-32] + stream := cipher.NewCBCDecrypter(block, iv) + decrypted := make([]byte, len(buffer)-48) + stream.CryptBlocks(decrypted, buffer[:len(buffer)-48]) + _, err = outFile.Write(decrypted) + if err != nil { + return err + } + _, err = outFile.Write(buffer[len(buffer)-48:]) + if err != nil { + return err + } + } + + return nil +} + +func pbkdf2HMAC(password, salt []byte, iter, keyLen int) []byte { + dk := make([]byte, keyLen) + loop := (keyLen + sha1.Size - 1) / sha1.Size + key := make([]byte, 0, len(salt)+4) + u := make([]byte, sha1.Size) + for i := 1; i <= loop; i++ { + key = key[:0] + key = append(key, salt...) + key = append(key, byte(i>>24), byte(i>>16), byte(i>>8), byte(i)) + hmac := hmac.New(sha1.New, password) + hmac.Write(key) + digest := hmac.Sum(nil) + copy(u, digest) + for j := 2; j <= iter; j++ { + hmac.Reset() + hmac.Write(digest) + digest = hmac.Sum(digest[:0]) + for k, di := range digest { + u[k] ^= di + } + } + copy(dk[(i-1)*sha1.Size:], u) + } + return dk +} + +func xorBytes(a []byte, b byte) []byte { + result := make([]byte, len(a)) + for i := range a { + result[i] = a[i] ^ b + } + return result +} + +/* +func main() { + + str := "82b1a210335140a1bc8a57397391186494abe666595b4f408095538b5518f7d5" + // 将十六进制字符串解码为字节 + password, err := hex.DecodeString(str) + if err != nil { + fmt.Println("解码出错:", err) + return + } + + fmt.Println(hex.EncodeToString(password)) + + err = decryptMsg("Media.db", password) + if err != nil { + fmt.Println("Error:", err) + } else { + fmt.Println("Decryption successful!") + } +} +*/ diff --git a/pkg/wechat/wechatDataProvider.go b/pkg/wechat/wechatDataProvider.go new file mode 100644 index 0000000..086daf7 --- /dev/null +++ b/pkg/wechat/wechatDataProvider.go @@ -0,0 +1,878 @@ +package wechat + +import ( + "database/sql" + "encoding/xml" + "errors" + "fmt" + "log" + "os" + "path/filepath" + "sort" + "strconv" + "strings" + sync "sync" + "time" + + "github.com/beevik/etree" + _ "github.com/mattn/go-sqlite3" + "github.com/pierrec/lz4" + "google.golang.org/protobuf/proto" +) + +const ( + Wechat_Message_Type_Text = 1 + Wechat_Message_Type_Picture = 3 + Wechat_Message_Type_Voice = 34 + Wechat_Message_Type_Video = 43 + Wechat_Message_Type_Emoji = 47 + Wechat_Message_Type_Misc = 49 + Wechat_Message_Type_System = 10000 +) + +const ( + Wechat_Misc_Message_TEXT = 1 + Wechat_Misc_Message_CardLink = 5 + Wechat_Misc_Message_File = 6 + Wechat_Misc_Message_CustomEmoji = 8 + Wechat_Misc_Message_ForwardMessage = 19 + Wechat_Misc_Message_Applet = 33 + Wechat_Misc_Message_Applet2 = 36 + Wechat_Misc_Message_Refer = 57 + Wechat_Misc_Message_Live = 63 + Wechat_Misc_Message_Notice = 87 + Wechat_Misc_Message_Live2 = 88 + Wechat_Misc_Message_Transfer = 2000 + Wechat_Misc_Message_RedPacket = 2003 +) + +const ( + Wechat_System_Message_Notice = 1 + Wechat_System_Message_Tickle = 4 + Wechat_System_Message_Notice2 = 8000 +) + +type Message_Search_Direction int + +const ( + Message_Search_Forward Message_Search_Direction = iota + Message_Search_Backward + Message_Search_Both +) + +type WeChatUserInfo struct { + UserName string `json:"UserName"` + Alias string `json:"Alias"` + ReMark string `json:"ReMark"` + NickName string `json:"NickName"` + SmallHeadImgUrl string `json:"SmallHeadImgUrl"` + BigHeadImgUrl string `json:"BigHeadImgUrl"` +} + +type WeChatSession struct { + UserName string `json:"UserName"` + NickName string `json:"NickName"` + Content string `json:"Content"` + UserInfo WeChatUserInfo `json:"UserInfo"` + Time uint64 `json:"Time"` + IsGroup bool `json:IsGroup` +} + +type WeChatSessionList struct { + Total int `json:"Total"` + Rows []WeChatSession `json:"Rows"` +} + +type FileInfo struct { + FileName string `json:"fileName"` + FileSize string `json:"fileSize"` + FilePath string `json:"filePath"` + FileExt string `json:"fileExt"` +} + +type LinkInfo struct { + Url string `json:"Url"` + Title string `json:"Title"` + Description string `json:"Description"` + DisPlayName string `json:"DisPlayName"` +} + +type ReferInfo struct { + Type int `json:"Type"` + SubType int `json:"SubType"` + Svrid int64 `json:"Svrid"` + Displayname string `json:"Displayname"` + Content string `json:"Content"` +} + +type WeChatMessage struct { + LocalId int `json:"LocalId"` + MsgSvrId int64 `json:"MsgSvrId"` + Type int `json:"type"` + SubType int `json:"SubType"` + IsSender int `json:"IsSender"` + CreateTime int64 `json:"createTime"` + Talker string `json:"talker"` + Content string `json:"content"` + ThumbPath string `json:"ThumbPath"` + ImagePath string `json:"ImagePath"` + VideoPath string `json:"VideoPath"` + FileInfo FileInfo `json:"fileInfo"` + EmojiPath string `json:"EmojiPath"` + VoicePath string `json:"VoicePath"` + IsChatRoom bool `json:"isChatRoom"` + UserInfo WeChatUserInfo `json:"userInfo"` + LinkInfo LinkInfo `json:"LinkInfo"` + ReferInfo ReferInfo `json:"ReferInfo"` + compressContent []byte + bytesExtra []byte +} + +type WeChatMessageList struct { + KeyWord string `json:"KeyWord"` + Total int `json:"Total"` + Rows []WeChatMessage `json:"Rows"` +} + +type WeChatMessageDate struct { + Date []string `json:"Date"` + Total int `json:"Total"` +} + +type WeChatUserList struct { + Users []WeChatUserInfo `json:"Users"` + Total int `json:"Total"` +} + +type wechatMsgDB struct { + path string + db *sql.DB + startTime int64 + endTime int64 +} + +type WechatDataProvider struct { + resPath string + microMsg *sql.DB + + msgDBs []*wechatMsgDB + userInfoMap map[string]WeChatUserInfo + userInfoMtx sync.Mutex + + SelfInfo *WeChatUserInfo +} + +const ( + MicroMsgDB = "MicroMsg.db" +) + +type byTime []*wechatMsgDB + +func (a byTime) Len() int { return len(a) } +func (a byTime) Less(i, j int) bool { return a[i].startTime > a[j].startTime } +func (a byTime) Swap(i, j int) { a[i], a[j] = a[j], a[i] } + +func CreateWechatDataProvider(resPath string) (*WechatDataProvider, error) { + provider := &WechatDataProvider{} + provider.resPath = resPath + provider.msgDBs = make([]*wechatMsgDB, 0) + log.Println(resPath) + userName := filepath.Base(resPath) + MicroMsgDBPath := resPath + "\\Msg\\" + MicroMsgDB + microMsg, err := sql.Open("sqlite3", MicroMsgDBPath) + if err != nil { + log.Printf("open db %s error: %v", MicroMsgDBPath, err) + return provider, err + } + + index := 0 + for { + msgDBPath := fmt.Sprintf("%s\\Msg\\Multi\\MSG%d.db", provider.resPath, index) + if _, err := os.Stat(msgDBPath); err != nil { + log.Println("msgDBPath end", msgDBPath) + break + } + + msgDB, err := wechatOpenMsgDB(msgDBPath) + if err != nil { + log.Printf("open db %s error: %v", msgDBPath, err) + break + } + provider.msgDBs = append(provider.msgDBs, msgDB) + log.Printf("MSG%d.db start %d - %d end\n", index, msgDB.startTime, msgDB.endTime) + index += 1 + } + sort.Sort(byTime(provider.msgDBs)) + for _, db := range provider.msgDBs { + log.Printf("%s start %d - %d end\n", db.path, db.startTime, db.endTime) + } + provider.userInfoMap = make(map[string]WeChatUserInfo) + provider.microMsg = microMsg + provider.SelfInfo, err = provider.WechatGetUserInfoByName(userName) + if err != nil { + log.Printf("WechatGetUserInfoByName %s failed: %v", userName, err) + return provider, err + } + provider.userInfoMap[userName] = *provider.SelfInfo + log.Println("resPath:", provider.resPath) + return provider, nil +} + +func (P *WechatDataProvider) WechatWechatDataProviderClose() { + if P.microMsg != nil { + P.microMsg.Close() + } + + for _, db := range P.msgDBs { + db.db.Close() + } + log.Println("WechatWechatDataProviderClose") +} + +func (P *WechatDataProvider) WechatGetUserInfoByName(name string) (*WeChatUserInfo, error) { + info := &WeChatUserInfo{} + + var UserName, Alias, ReMark, NickName string + querySql := fmt.Sprintf("select ifnull(UserName,'') as UserName, ifnull(Alias,'') as Alias, ifnull(ReMark,'') as ReMark, ifnull(NickName,'') as NickName from Contact where UserName='%s';", name) + // log.Println(querySql) + err := P.microMsg.QueryRow(querySql).Scan(&UserName, &Alias, &ReMark, &NickName) + if err != nil { + log.Println("not found User:", err) + return info, err + } + + log.Printf("UserName %s, Alias %s, ReMark %s, NickName %s\n", UserName, Alias, ReMark, NickName) + + var smallHeadImgUrl, bigHeadImgUrl string + querySql = fmt.Sprintf("select ifnull(smallHeadImgUrl,'') as smallHeadImgUrl, ifnull(bigHeadImgUrl,'') as bigHeadImgUrl from ContactHeadImgUrl where usrName='%s';", UserName) + // log.Println(querySql) + err = P.microMsg.QueryRow(querySql).Scan(&smallHeadImgUrl, &bigHeadImgUrl) + if err != nil { + log.Println("not find headimg", err) + } + + info.UserName = UserName + info.Alias = Alias + info.ReMark = ReMark + info.NickName = NickName + info.SmallHeadImgUrl = smallHeadImgUrl + info.BigHeadImgUrl = bigHeadImgUrl + + // log.Println(info) + return info, nil +} + +func (P *WechatDataProvider) WeChatGetSessionList(pageIndex int, pageSize int) (*WeChatSessionList, error) { + List := &WeChatSessionList{} + List.Rows = make([]WeChatSession, 0) + + querySql := fmt.Sprintf("select ifnull(strUsrName,'') as strUsrName,ifnull(strNickName,'') as strNickName,ifnull(strContent,'') as strContent, nTime from Session order by rowid desc limit %d, %d;", pageIndex*pageSize, pageSize) + dbRows, err := P.microMsg.Query(querySql) + if err != nil { + log.Println(err) + return List, err + } + defer dbRows.Close() + + var strUsrName, strNickName, strContent string + var nTime uint64 + for dbRows.Next() { + var session WeChatSession + err = dbRows.Scan(&strUsrName, &strNickName, &strContent, &nTime) + if err != nil { + log.Println(err) + continue + } + if len(strContent) == 0 { + log.Printf("%s cotent nil\n", strUsrName) + continue + } + + session.UserName = strUsrName + session.NickName = strNickName + session.Content = strContent + session.Time = nTime + session.IsGroup = strings.HasSuffix(strUsrName, "@chatroom") + info, err := P.WechatGetUserInfoByName(strUsrName) + if err != nil { + log.Printf("WechatGetUserInfoByName %s failed\n", strUsrName) + continue + } + session.UserInfo = *info + List.Rows = append(List.Rows, session) + List.Total += 1 + } + + return List, nil +} + +func (P *WechatDataProvider) WeChatGetMessageListByTime(userName string, time int64, pageSize int, direction Message_Search_Direction) (*WeChatMessageList, error) { + + List := &WeChatMessageList{} + List.Rows = make([]WeChatMessage, 0) + selectTime := time + selectpageSize := pageSize + + if direction == Message_Search_Both { + selectpageSize = pageSize / 2 + } + for direction == Message_Search_Forward || direction == Message_Search_Both { + selectList, err := P.weChatGetMessageListByTime(userName, selectTime, selectpageSize, Message_Search_Forward) + if err != nil { + return List, err + } + + if selectList.Total == 0 { + break + } + + selectTime = selectList.Rows[selectList.Total-1].CreateTime - 1 + selectpageSize -= selectList.Total + List.Total += selectList.Total + List.Rows = append(List.Rows, selectList.Rows...) + if selectpageSize <= 0 { + break + } + log.Printf("Forward selectTime %d, selectpageSize %d\n", selectTime, selectpageSize) + } + + selectTime = time + if direction == Message_Search_Both { + selectpageSize = pageSize / 2 + } + for direction == Message_Search_Backward || direction == Message_Search_Both { + selectList, err := P.weChatGetMessageListByTime(userName, selectTime, selectpageSize, Message_Search_Backward) + if err != nil { + return List, err + } + + if selectList.Total == 0 { + break + } + + selectTime = selectList.Rows[0].CreateTime + 1 + selectpageSize -= selectList.Total + List.Total += selectList.Total + List.Rows = append(selectList.Rows, List.Rows...) + if selectpageSize <= 0 { + break + } + log.Printf("Backward selectTime %d, selectpageSize %d\n", selectTime, selectpageSize) + } + + return List, nil +} + +func (P *WechatDataProvider) weChatGetMessageListByTime(userName string, time int64, pageSize int, direction Message_Search_Direction) (*WeChatMessageList, error) { + List := &WeChatMessageList{} + List.Rows = make([]WeChatMessage, 0) + index := P.wechatFindDBIndex(userName, time, direction) + if index == -1 { + log.Printf("Not found %s %d data\n", userName, time) + return List, nil + } + + sqlFormat := "select localId,MsgSvrID,Type,SubType,IsSender,CreateTime,ifnull(StrTalker,'') as StrTalker, ifnull(StrContent,'') as StrContent,ifnull(CompressContent,'') as CompressContent,ifnull(BytesExtra,'') as BytesExtra from MSG Where StrTalker='%s' And CreateTime<=%d order by CreateTime desc limit %d;" + if direction == Message_Search_Backward { + sqlFormat = "select localId,MsgSvrID,Type,SubType,IsSender,CreateTime,ifnull(StrTalker,'') as StrTalker, ifnull(StrContent,'') as StrContent,ifnull(CompressContent,'') as CompressContent,ifnull(BytesExtra,'') as BytesExtra from ( select localId, MsgSvrID, Type, SubType, IsSender, CreateTime, StrTalker, StrContent, CompressContent, BytesExtra FROM MSG Where StrTalker='%s' And CreateTime>%d order by CreateTime asc limit %d) AS SubQuery order by CreateTime desc;" + } + querySql := fmt.Sprintf(sqlFormat, userName, time, pageSize) + log.Println(querySql) + + rows, err := P.msgDBs[index].db.Query(querySql) + if err != nil { + log.Printf("%s failed %v\n", querySql, err) + return List, nil + } + defer rows.Close() + var localId, Type, SubType, IsSender int + var MsgSvrID, CreateTime int64 + var StrTalker, StrContent string + var CompressContent, BytesExtra []byte + + for rows.Next() { + message := WeChatMessage{} + err = rows.Scan(&localId, &MsgSvrID, &Type, &SubType, &IsSender, &CreateTime, + &StrTalker, &StrContent, &CompressContent, &BytesExtra) + if err != nil { + log.Println("rows.Scan failed", err) + return List, err + } + message.LocalId = localId + message.MsgSvrId = MsgSvrID + message.Type = Type + message.SubType = SubType + message.IsSender = IsSender + message.CreateTime = CreateTime + message.Talker = StrTalker + message.Content = StrContent + message.IsChatRoom = strings.HasSuffix(StrTalker, "@chatroom") + message.compressContent = make([]byte, len(CompressContent)) + message.bytesExtra = make([]byte, len(BytesExtra)) + copy(message.compressContent, CompressContent) + copy(message.bytesExtra, BytesExtra) + P.wechatMessageExtraHandle(&message) + P.wechatMessageGetUserInfo(&message) + P.wechatMessageEmojiHandle(&message) + P.wechatMessageCompressContentHandle(&message) + List.Rows = append(List.Rows, message) + List.Total += 1 + } + + if err := rows.Err(); err != nil { + log.Println("rows.Scan failed", err) + return List, err + } + + return List, nil +} + +func (P *WechatDataProvider) WeChatGetMessageListByKeyWord(userName string, time int64, keyWord string, msgType string, pageSize int) (*WeChatMessageList, error) { + List := &WeChatMessageList{} + List.Rows = make([]WeChatMessage, 0) + List.KeyWord = keyWord + _time := time + selectPagesize := pageSize + if keyWord != "" || msgType != "" { + selectPagesize = 600 + } + for { + log.Println("time:", _time, keyWord) + rawList, err := P.weChatGetMessageListByTime(userName, _time, selectPagesize, Message_Search_Forward) + if err != nil { + log.Println("weChatGetMessageListByTime failed: ", err) + return nil, err + } + log.Println("rawList.Total:", rawList.Total) + if rawList.Total == 0 { + if List.Total == 0 { + log.Printf("user %s not find [%s]\n", userName, keyWord) + } + break + } + + for i, _ := range rawList.Rows { + if weChatMessageTypeFilter(&rawList.Rows[i], msgType) && (len(keyWord) == 0 || weChatMessageContains(&rawList.Rows[i], keyWord)) { + List.Rows = append(List.Rows, rawList.Rows[i]) + List.Total += 1 + if List.Total >= pageSize { + return List, nil + } + } + } + + _time = rawList.Rows[rawList.Total-1].CreateTime - 1 + } + + return List, nil +} + +func (P *WechatDataProvider) WeChatGetMessageDate(userName string) (*WeChatMessageDate, error) { + messageData := &WeChatMessageDate{} + messageData.Date = make([]string, 0) + messageData.Total = 0 + + _time := time.Now().Unix() + + for { + index := P.wechatFindDBIndex(userName, _time, Message_Search_Forward) + if index == -1 { + log.Println("wechat find db end") + return messageData, nil + } + + sqlFormat := " SELECT DISTINCT strftime('%%Y-%%m-%%d', datetime(CreateTime+28800, 'unixepoch')) FROM MSG WHERE StrTalker='%s' order by CreateTime desc;" + querySql := fmt.Sprintf(sqlFormat, userName) + + rows, err := P.msgDBs[index].db.Query(querySql) + if err != nil { + log.Printf("%s failed %v\n", querySql, err) + return messageData, nil + } + defer rows.Close() + + var date string + for rows.Next() { + err = rows.Scan(&date) + if err != nil { + log.Println("rows.Scan failed", err) + return messageData, err + } + + messageData.Date = append(messageData.Date, date) + messageData.Total += 1 + } + + if err := rows.Err(); err != nil { + log.Println("rows.Scan failed", err) + return messageData, err + } + + _time = P.wechatGetLastMessageCreateTime(userName, index) + if -1 == _time { + log.Println("wechatGetLastMessageCreateTime failed") + return messageData, errors.New("wechatGetLastMessageCreateTime failed") + } + + _time -= 1 + } +} + +func (P *WechatDataProvider) WeChatGetChatRoomUserList(chatroom string) (*WeChatUserList, error) { + userList := &WeChatUserList{} + userList.Users = make([]WeChatUserInfo, 0) + userList.Total = 0 + + sqlFormat := "select UserNameList from ChatRoom where ChatRoomName='%s';" + querySql := fmt.Sprintf(sqlFormat, chatroom) + + var userNameListStr string + err := P.microMsg.QueryRow(querySql).Scan(&userNameListStr) + if err != nil { + log.Println("Scan: ", err) + return nil, err + } + + userNameArray := strings.Split(userNameListStr, "^G") + log.Println("userNameArray:", userNameArray) + + for _, userName := range userNameArray { + pinfo, err := P.WechatGetUserInfoByNameOnCache(userName) + if err == nil { + userList.Users = append(userList.Users, *pinfo) + userList.Total += 1 + } + } + + return userList, nil +} + +func (info WeChatUserInfo) String() string { + return fmt.Sprintf("NickName:[%s] Alias:[%s], NickName:[%s], ReMark:[%s], SmallHeadImgUrl:[%s], BigHeadImgUrl[%s]", + info.NickName, info.Alias, info.NickName, info.ReMark, info.SmallHeadImgUrl, info.BigHeadImgUrl) +} + +func (P *WechatDataProvider) wechatMessageExtraHandle(msg *WeChatMessage) { + var extra MessageBytesExtra + err := proto.Unmarshal(msg.bytesExtra, &extra) + if err != nil { + log.Println("proto.Unmarshal failed", err) + return + } + + for _, ext := range extra.Message2 { + switch ext.Field1 { + case 1: + if msg.IsChatRoom { + msg.Talker = ext.Field2 + } + case 3: + if len(ext.Field2) > 0 && (msg.Type == Wechat_Message_Type_Picture || msg.Type == Wechat_Message_Type_Video || msg.Type == Wechat_Message_Type_Misc) { + msg.ThumbPath = P.resPath + ext.Field2[len(P.SelfInfo.UserName):] + } + case 4: + if len(ext.Field2) > 0 { + if msg.Type == Wechat_Message_Type_Misc && msg.SubType == Wechat_Misc_Message_File { + msg.FileInfo.FilePath = P.resPath + ext.Field2[len(P.SelfInfo.UserName):] + msg.FileInfo.FileName = filepath.Base(ext.Field2) + } else if msg.Type == Wechat_Message_Type_Picture || msg.Type == Wechat_Message_Type_Video || msg.Type == Wechat_Message_Type_Misc { + msg.ImagePath = P.resPath + ext.Field2[len(P.SelfInfo.UserName):] + msg.VideoPath = P.resPath + ext.Field2[len(P.SelfInfo.UserName):] + } + } + } + } + + if msg.Type == Wechat_Message_Type_Voice { + msg.VoicePath = fmt.Sprintf("%s\\FileStorage\\Voice\\%d.mp3", P.resPath, msg.MsgSvrId) + } +} + +type EmojiMsg struct { + XMLName xml.Name `xml:"msg"` + Emoji Emoji `xml:"emoji"` +} + +type Emoji struct { + XMLName xml.Name `xml:"emoji"` + CdnURL string `xml:"cdnurl,attr"` + Thumburl string `xml:"thumburl,attr"` + Width string `xml:"width,attr"` + Height string `xml:"height,attr"` +} + +func (P *WechatDataProvider) wechatMessageEmojiHandle(msg *WeChatMessage) { + if msg.Type != Wechat_Message_Type_Emoji { + return + } + + emojiMsg := EmojiMsg{} + err := xml.Unmarshal([]byte(msg.Content), &emojiMsg) + if err != nil { + log.Println("xml.Unmarshal failed: ", err, msg.Content) + return + } + + msg.EmojiPath = emojiMsg.Emoji.CdnURL +} + +type xmlDocument struct { + *etree.Document +} + +func NewxmlDocument(e *etree.Document) *xmlDocument { + return &xmlDocument{e} +} + +func (e *xmlDocument) FindElementValue(path string) string { + item := e.FindElement(path) + if item != nil { + return item.Text() + } + + return "" +} + +func (P *WechatDataProvider) wechatMessageCompressContentHandle(msg *WeChatMessage) { + if len(msg.compressContent) == 0 { + return + } + + unCompressContent := make([]byte, len(msg.compressContent)*10) + ulen, err := lz4.UncompressBlock(msg.compressContent, unCompressContent) + if err != nil { + log.Println("UncompressBlock failed:", err, msg.MsgSvrId) + return + } + + compMsg := etree.NewDocument() + if err := compMsg.ReadFromBytes(unCompressContent[:ulen-1]); err != nil { + // os.WriteFile("D:\\tmp\\"+string(msg.LocalId)+".xml", unCompressContent[:ulen], 0600) + log.Println("ReadFromBytes failed:", err) + return + } + + root := NewxmlDocument(compMsg) + if msg.Type == Wechat_Message_Type_Misc && msg.SubType == Wechat_Misc_Message_CardLink { + msg.LinkInfo.Title = root.FindElementValue("/msg/appmsg/title") + msg.LinkInfo.Description = root.FindElementValue("/msg/appmsg/des") + msg.LinkInfo.Url = root.FindElementValue("/msg/appmsg/url") + msg.LinkInfo.DisPlayName = root.FindElementValue("/msg/appmsg/sourcedisplayname") + appName := root.FindElementValue("/msg/appinfo/appname") + if len(msg.LinkInfo.DisPlayName) == 0 && len(appName) > 0 { + msg.LinkInfo.DisPlayName = appName + } + } else if msg.Type == Wechat_Message_Type_Misc && msg.SubType == Wechat_Misc_Message_Refer { + msg.Content = root.FindElementValue("/msg/appmsg/title") + msg.ReferInfo.Type, _ = strconv.Atoi(root.FindElementValue("/msg/appmsg/refermsg/type")) + msg.ReferInfo.Svrid, _ = strconv.ParseInt(root.FindElementValue("/msg/appmsg/refermsg/svrid"), 10, 64) + msg.ReferInfo.Displayname = root.FindElementValue("/msg/appmsg/refermsg/displayname") + msg.ReferInfo.Content = root.FindElementValue("/msg/appmsg/refermsg/content") + + if msg.ReferInfo.Type == Wechat_Message_Type_Misc { + contentXML := etree.NewDocument() + if err := contentXML.ReadFromString(msg.ReferInfo.Content); err != nil { + log.Println("ReadFromString failed:", err) + return + } + + root := NewxmlDocument(contentXML) + msg.ReferInfo.Content = root.FindElementValue("/msg/appmsg/title") + msg.ReferInfo.SubType, _ = strconv.Atoi(root.FindElementValue("/msg/appmsg/type")) + } + } +} + +func (P *WechatDataProvider) wechatMessageGetUserInfo(msg *WeChatMessage) { + who := msg.Talker + if msg.IsSender == 1 { + who = P.SelfInfo.UserName + } + + pinfo, err := P.WechatGetUserInfoByNameOnCache(who) + if err != nil { + log.Println("WechatGetUserInfoByNameOnCache:", err) + return + } + + msg.UserInfo = *pinfo +} + +func (P *WechatDataProvider) wechatFindDBIndex(userName string, time int64, direction Message_Search_Direction) int { + if direction == Message_Search_Forward { + index := 0 + for { + if index >= len(P.msgDBs) { + return -1 + } + msgDB := P.msgDBs[index] + + if msgDB.startTime > time { + index += 1 + continue + } + + rowId := 0 + querySql := fmt.Sprintf("select rowid from Name2ID where UsrName='%s';", userName) + err := msgDB.db.QueryRow(querySql).Scan(&rowId) + if err != nil { + log.Printf("Scan: %v\n", err) + index += 1 + continue + } + + querySql = fmt.Sprintf(" select rowid from MSG where StrTalker='%s' AND CreateTime<=%d limit 1;", userName, time) + log.Printf("in %s, %s\n", msgDB.path, querySql) + err = msgDB.db.QueryRow(querySql).Scan(&rowId) + if err != nil { + log.Printf("Scan: %v\n", err) + index += 1 + continue + } + + log.Printf("Select in %d %s\n", index, msgDB.path) + return index + } + } else { + index := len(P.msgDBs) - 1 + for { + if index < 0 { + return -1 + } + msgDB := P.msgDBs[index] + + if msgDB.endTime < time { + index -= 1 + continue + } + + rowId := 0 + querySql := fmt.Sprintf("select rowid from Name2ID where UsrName='%s';", userName) + err := msgDB.db.QueryRow(querySql).Scan(&rowId) + if err != nil { + log.Printf("Scan: %v\n", err) + index -= 1 + continue + } + + querySql = fmt.Sprintf(" select rowid from MSG where StrTalker='%s' AND CreateTime>%d limit 1;", userName, time) + log.Printf("in %s, %s\n", msgDB.path, querySql) + err = msgDB.db.QueryRow(querySql).Scan(&rowId) + if err != nil { + log.Printf("Scan: %v\n", err) + index -= 1 + continue + } + + log.Printf("Select in %d %s\n", index, msgDB.path) + return index + } + } +} + +func (P *WechatDataProvider) wechatGetLastMessageCreateTime(userName string, index int) int64 { + if index >= len(P.msgDBs) { + return -1 + } + sqlFormat := "SELECT CreateTime FROM MSG WHERE StrTalker='%s' order by CreateTime asc limit 1;" + querySql := fmt.Sprintf(sqlFormat, userName) + var lastTime int64 + err := P.msgDBs[index].db.QueryRow(querySql).Scan(&lastTime) + if err != nil { + log.Println("select DB lastTime failed:", index, ":", err) + return -1 + } + + return lastTime +} + +func weChatMessageContains(msg *WeChatMessage, chars string) bool { + + switch msg.Type { + case Wechat_Message_Type_Text: + return strings.Contains(msg.Content, chars) + case Wechat_Message_Type_Misc: + switch msg.SubType { + case Wechat_Misc_Message_CardLink: + return strings.Contains(msg.LinkInfo.Title, chars) || strings.Contains(msg.LinkInfo.Description, chars) + case Wechat_Misc_Message_Refer: + return strings.Contains(msg.Content, chars) + case Wechat_Misc_Message_File: + return strings.Contains(msg.FileInfo.FileName, chars) + default: + return false + } + default: + return false + } +} + +func weChatMessageTypeFilter(msg *WeChatMessage, msgType string) bool { + switch msgType { + case "": + return true + case "文件": + return msg.Type == Wechat_Message_Type_Misc && msg.SubType == Wechat_Misc_Message_File + case "图片与视频": + return msg.Type == Wechat_Message_Type_Picture || msg.Type == Wechat_Message_Type_Video + case "链接": + return msg.Type == Wechat_Misc_Message_CardLink || msg.SubType == Wechat_Misc_Message_CardLink + default: + if strings.HasPrefix(msgType, "群成员") { + userName := msgType[len("群成员"):] + return msg.UserInfo.UserName == userName + } + + return false + } +} + +func wechatOpenMsgDB(path string) (*wechatMsgDB, error) { + msgDB := wechatMsgDB{} + + db, err := sql.Open("sqlite3", path) + if err != nil { + log.Printf("open db %s error: %v", path, err) + return nil, err + } + msgDB.db = db + msgDB.path = path + querySql := "select CreateTime from MSG order by CreateTime asc limit 1;" + err = msgDB.db.QueryRow(querySql).Scan(&msgDB.startTime) + if err != nil { + log.Println("select DB startTime failed:", path, ":", err) + return nil, err + } + + querySql = "select CreateTime from MSG order by CreateTime desc limit 1;" + err = msgDB.db.QueryRow(querySql).Scan(&msgDB.endTime) + if err != nil { + log.Println("select DB endTime failed:", path, ":", err) + return nil, err + } + + return &msgDB, nil +} + +func (P *WechatDataProvider) WechatGetUserInfoByNameOnCache(name string) (*WeChatUserInfo, error) { + + // log.Printf("who: %s", who) + + P.userInfoMtx.Lock() + defer P.userInfoMtx.Unlock() + + info, ok := P.userInfoMap[name] + if ok { + return &info, nil + } + + pinfo, err := P.WechatGetUserInfoByName(name) + if err != nil { + log.Printf("WechatGetUserInfoByName %s failed: %v\n", name, err) + return nil, err + } + + P.userInfoMap[name] = *pinfo + + return pinfo, nil +} diff --git a/pkg/wechat/wechatIMGDec.go b/pkg/wechat/wechatIMGDec.go new file mode 100644 index 0000000..5f246e5 --- /dev/null +++ b/pkg/wechat/wechatIMGDec.go @@ -0,0 +1,209 @@ +package wechat + +import ( + "bufio" + "encoding/hex" + "errors" + "fmt" + "io" + "log" + "os" + "path/filepath" + "sync" + "time" +) + +/* + from: https://github.com/liuggchen/wechatDatDecode.git +*/ + +var imagePrefixBtsMap = make(map[string][]byte) + +func DecryptDatByDir(inDir, outDir string) error { + + startTime := time.Now() + f, er := os.Open(inDir) + if er != nil { + fmt.Println(er.Error()) + return er + } + readdir, er := f.Readdir(0) + if er != nil { + fmt.Println(er.Error()) + } + + if stat, er := os.Stat(outDir); os.IsNotExist(er) { + er := os.MkdirAll(outDir, 0755) + if er != nil { + return er + } + } else if !stat.IsDir() { + return errors.New(outDir + "is file") + } + + var taskChan = make(chan os.FileInfo, 100) + + go func() { + for _, info := range readdir { + taskChan <- info + } + close(taskChan) + }() + + var wg sync.WaitGroup + for i := 0; i < 10; i++ { + wg.Add(1) + go func() { + defer wg.Done() + for info := range taskChan { + handlerOne(info, inDir, outDir) + } + }() + } + + wg.Wait() + t := time.Since(startTime).Seconds() + log.Printf("\nfinished time= %v s\n", t) + + return nil +} + +func DecryptDat(inFile string, outFile string) error { + + sourceFile, err := os.Open(inFile) + if err != nil { + log.Println(err.Error()) + return err + } + + var preTenBts = make([]byte, 10) + _, _ = sourceFile.Read(preTenBts) + decodeByte, _, er := findDecodeByte(preTenBts) + if er != nil { + log.Println(er.Error()) + return err + } + + distFile, er := os.Create(outFile) + if er != nil { + log.Println(er.Error()) + return err + } + writer := bufio.NewWriter(distFile) + _, _ = sourceFile.Seek(0, 0) + var rBts = make([]byte, 1024) + for { + n, er := sourceFile.Read(rBts) + if er != nil { + if er == io.EOF { + break + } + log.Println("error: ", er.Error()) + return err + } + for i := 0; i < n; i++ { + _ = writer.WriteByte(rBts[i] ^ decodeByte) + } + } + _ = writer.Flush() + _ = distFile.Close() + _ = sourceFile.Close() + // fmt.Println("output file:", distFile.Name()) + + return nil +} + +func handlerOne(info os.FileInfo, dir string, outputDir string) { + if info.IsDir() || filepath.Ext(info.Name()) != ".dat" { + return + } + fmt.Println("find file: ", info.Name()) + fPath := dir + "/" + info.Name() + sourceFile, err := os.Open(fPath) + if err != nil { + fmt.Println(err.Error()) + return + } + + var preTenBts = make([]byte, 10) + _, _ = sourceFile.Read(preTenBts) + decodeByte, _, er := findDecodeByte(preTenBts) + if er != nil { + fmt.Println(er.Error()) + return + } + + distFile, er := os.Create(outputDir + "/" + info.Name()) + if er != nil { + fmt.Println(er.Error()) + return + } + writer := bufio.NewWriter(distFile) + _, _ = sourceFile.Seek(0, 0) + var rBts = make([]byte, 1024) + for { + n, er := sourceFile.Read(rBts) + if er != nil { + if er == io.EOF { + break + } + fmt.Println("error: ", er.Error()) + return + } + for i := 0; i < n; i++ { + _ = writer.WriteByte(rBts[i] ^ decodeByte) + } + } + _ = writer.Flush() + _ = distFile.Close() + + fmt.Println("output file:", distFile.Name()) +} + +func init() { + //JPEG (jpg),文件头:FFD8FF + //PNG (png),文件头:89504E47 + //GIF (gif),文件头:47494638 + //TIFF (tif),文件头:49492A00 + //Windows Bitmap (bmp),文件头:424D + const ( + Jpeg = "FFD8FF" + Png = "89504E47" + Gif = "47494638" + Tif = "49492A00" + Bmp = "424D" + ) + JpegPrefixBytes, _ := hex.DecodeString(Jpeg) + PngPrefixBytes, _ := hex.DecodeString(Png) + GifPrefixBytes, _ := hex.DecodeString(Gif) + TifPrefixBytes, _ := hex.DecodeString(Tif) + BmpPrefixBytes, _ := hex.DecodeString(Bmp) + + imagePrefixBtsMap = map[string][]byte{ + ".jpeg": JpegPrefixBytes, + ".png": PngPrefixBytes, + ".gif": GifPrefixBytes, + ".tif": TifPrefixBytes, + ".bmp": BmpPrefixBytes, + } +} + +func findDecodeByte(bts []byte) (byte, string, error) { + for ext, prefixBytes := range imagePrefixBtsMap { + deCodeByte, err := testPrefix(prefixBytes, bts) + if err == nil { + return deCodeByte, ext, err + } + } + return 0, "", errors.New("decode fail") +} + +func testPrefix(prefixBytes []byte, bts []byte) (deCodeByte byte, error error) { + var initDecodeByte = prefixBytes[0] ^ bts[0] + for i, prefixByte := range prefixBytes { + if b := prefixByte ^ bts[i]; b != initDecodeByte { + return 0, errors.New("no") + } + } + return initDecodeByte, nil +} diff --git a/res/result.png b/res/result.png new file mode 100644 index 0000000000000000000000000000000000000000..3044ff3031b718a8ea7f762955a89daed8b4d5fd GIT binary patch literal 253402 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 z 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

$*bGDVca}4*n&kBy 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 z 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 D)W&lC literal 0 HcmV?d00001 diff --git a/wails.json b/wails.json new file mode 100644 index 0000000..52d9021 --- /dev/null +++ b/wails.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://wails.io/schemas/config.v2.json", + "name": "wechatDataBackup", + "outputfilename": "wechatDataBackup", + "frontend:install": "", + "frontend:build": "", + "frontend:dev:watcher": "", + "frontend:dev:serverUrl": "", + "author": { + "name": "hal", + "email": "1174221722@qq.com" + } +}

v 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 afAK4I1hp!iSklh`0000C00093P)t-s0002; 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 literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/088_合十.58cd6a1d.png b/frontend/dist/assets/088_合十.58cd6a1d.png new file mode 100644 index 0000000000000000000000000000000000000000..f92a569413917af53c287be19e922716959bd1f4 GIT binary patch literal 4707 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 literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/090_咖啡.8f40dc95.png b/frontend/dist/assets/090_咖啡.8f40dc95.png new file mode 100644 index 0000000000000000000000000000000000000000..27f3ee895d4b910a19b533185aeb4ea077e74248 GIT binary patch literal 5915 zcmV+$7v$)PP)C00090P)t-s0001) znVFcFn6k36v9YnEqoag`gqD_;ySux!wY9Xgw3nBcgoK2&w6wCavYecpw6wIdv$Kwl zj(>lDmzS59mzU<|=7fZVva+(SuCBGUwV|P*dwYAJprER%sSJkB^|BppcM| zprD|Ig@v`XwSj?wudlDOv$KYVhJb*8q@<*lmX@2Fo2aO$gM)*qsi~fxp0~HRii(PY zf`X2Yj-Q{Ov9Ynk!^4%8mDSbNdwYAfwzjsmwvUgGrKP2`w6w3Uua=gUm6er{kdU37 zotvARrKP2Qetw9Eh<<*4!^6Y>|NpcPRm zva+(z&(HVw_pGd}sHmu}uCC?f<<{2L)YR0lu&}+ny!rY0*x1T$BzNDn2l9G~zM<>OMS>4^;$;ruVY;3f6O5ot&=C+2qe@?P?NPvKV z!iiV6dP~~c+IxF@rfEK(pP#&eP_cAIi%lzuiHU=QgSdQ5t8PNOySu)GQm$}Axw*NW zot>4ImW_>#oL)DAL?(82c5!iWk5MgvLnOMoy03CYd3kxig;a-1Dagpk$B$g3W!p=3LZPc5KgI+|QIkWw#~mzU_diH3%TdU|@nhg6+kH*6~q znVg=4goM0&N2zQ;g@uKmVL5d*7|fMt^7QrNvV+v1aeF!&$B<#7Wju2|D5Q>n*rj#Q znrdk%49&;HvxsDrb7G@kF_lgx;I4kRc0;glK4&EgoQ{N?e{z3LIh|H2Z!#BhFA<-W zjoqtziC|5GRza(1H;qaqe?K9FJ{zc&im8iprGI3#epIGpH<(r}vZ9)qm6NWEZl-rt zooY#lMkBqmuC=P9>%5GWf_G?WXs?4{fJiK$nU#xqaB{4&`~Uy|O>|ODQve4X6gUs6 zQXi*6H23t~eJjkhn_?;l-NCh&NjLHA>FDIKp_Gw;V^aF^-rCZ|!nLBGjDL7@Z)Z|H zH6!@c)P{8T_1wyf_3-fB$a!PPaLWJy6M#uXK~#9!?9#DrgD?;VU}&fUNFcH$EUekH zph}?T5iBp3d>+gi$%BK-kV<}r4h%>n-FSz-U7Ze59{?&F~6U62dsRD0*MljN>#u7()mX+G+qnNSeRQ z9{*Y!DXgVjPQzq~pcqod1v=3L`)RGea{fm?ER~e?X74 zhNd*ZOV@y4n8HVTgW)DEa^9;k8^qU-KY+(5Z z4-jGlC*vy@|BL_BS%koGB;tz@kGLGoa!ky4op79r3kA5X<0KNV4W2PsnvF#fpDz!Q zk@(3Ihrjfzr!mm`f|0P1qfL-I6^EiGpIh^t55L*jnYTXwq$tOM5U@SwBew$?4P$4n z9nydFJVHb|ijER6(=KqWEwRv0T<kbnIcM~(+tnpOP~~R3Ub3g1hn5DwQE1j`wNA5qUKNK9H+>atI6G zEBd(i(a2$be=>~S@=yb=5OKdBWnv$DV_nge4(RP#A?pfiHu(D;3w-K6l1uuJ94Hi& z&97faX4D_@hl#Tu{y|6}xV|1V`TM<>`s2s0Khw_^6eU}*+_mTkkY(Qs=6yHdssUYx zKKk3Z|I@ z-hK0#fBh~=Tsq<*Ksb2!?k~#AHZ+Mij^k0i=z*vpf~Xcm1VJ_GO+>wjUiBh&+?@|6 z_dM=854ZEQ?1kb)l&lDuuosOS7`UK@q%gO&7a9z2G}{)AQ7{xGWg0|#vmT(LpSOw@ zmG*fdf4S4|=l&1(|Np#K7nk4l_a{IAcy^=zZj%V+=Z(7gE=9SsZEQxHhZ&L(CiL11#`aYFxZSP&m)rl#)xWD58Z3%*Te zftSnIP(cuA8tsds{Epq1&;7?nc#P&n`0dx_mt$jNxyLU)HV0vPb~FKuPQAVJwtqc| zAF-prm`-LneSJg}4LIRqSq$-Z6CGQ3wJmUwz>z?}aQ)G$BbUjH&raW*gg%%ajpcG6 zl*!~qfABLfr;}+Ci^VcIccV&);XoHfJg}P>S;P!xwBzXBb_G!Ufg}cqYGZjEa5!$y zz^eyF!7(2DiJtWf~KM{!it4eX2%?4~>0GT4YyPy~q~nfsJ)B;7g_6S*7H z&n92ocE=~&EpWJ3^PfM2B-ubg#lo8nVa5b~z(__HxwWmsc!vV!u8^#<#e9Bs0@8u> zK-_Wf`ONcsj&%HYCe}W`6CcihUQuP0BY70}kx;f6IoV`aRk4ewceb+^bVO()fk#6s z6P{0L^<-LSU|=BWPmeuLWZckRkA79ZE1ve}wbFY=W;j@aM#_iNJVBsFfl*~yK=DK8 z+YmS&A-O&RM*|GQe5h5ly1yB&^T>Zc3GGMgNqz^eK)kkSFsY1%qzMC}_!L{Se4`&& zWLc8D6m?`nYdRGt#&r=Sk1>o1E2b)y)UY3N{Qp9~p`Nc)N-MIRQH?lH1jF7TpAu1g z5t|Kn8N`6d(!P$3tp!dgN|0rZ1W%b|yUD&#oXb|URDIa*zyDYK_lN6wEt{>q5v+E* zfI@wS2yBlC@XE>>%$x$l%})y4T0Gpky!T9n1y`#N1zsg=5^tzu(rW3z+VF#&|Z*kY9+ z;$R8H0ZT|jkU)x%xN(c%g2bWs{x?1K_q?P@YZBU~w|qfE^2q<%%PhqDfN38ZDRb`IQfvwb{!Ok>}CMx2GFJQJ3xQ;&3YO(7O( zBL#pZy~YnSKnuVQUo4c%um!-VcE*tnR1yDhKL2D>`t4g!=E}uxlQKfk6u?MCG3Yoa zH|TZ#Ox6sb33+4wh7Sg1c=~`Ph+J>AdTn!hmT{)@Lju3708G#|7{nLoA%Ea9`6-+o z=DqQF+>!84Pg#}-@_BW+DgVC%2U`;F6R>G%Ch(>i0I=M!#@h4(t z|8b%>uLCuK*h@WC>ZpT0`_da5)JQ){!-g_>sKZfKiw~eVO@U?tNB|8;go%{Ku5~|V zj6Vuz#Cfq6Bt2=qo>ydfqU2(s22FUr-nx$exmtlv{4vj*>axt49)#NsQ$jp`1ORFv zkL&c%{kA`#^`D|oR&Wz3zXEP~u~2%27@9A>DdG8G>uUZFYeX}CcmaJ?EmtX|KsNzN z01Y7G92vyk0(!7t?|(&5=c?QREEcNZX_y^~)7L3@uEtiPm)96VQp=~f5rZzFl|Uj) z0J}jS0DkmIx}>TrRbA%GyoY2fc7MWbGgS#*c{Y8$>t-(V16V~VdYhCkK?@=RB4RC& zkwDb3SR)b%8}x{u5fr6dsB+aR#?Um4!Cwr1q&Jqt+@4R@-z0cBM;ITx?17@Br<9Qc zNbrY|2$0cepkHmoj_92zew-5(X;`2c1k6OAb{Q$Kx%KCg_tLePqY6=z<{0aH0(4Cj?X3g7 zTqbCZpF=|s5BrWF{7XoA>MuTQc_bh7`i_u=02;YTSJU~0+>z$Im!t8^a8h*N&G#gj z_r)ATV+eFR;fPuV8giTtdCLqwEzP-B)FOfahiMW{YlveZuZBXJ3=*dt*GK071x2QfDzSus~v9z4cZRyU7pD zSi=>gy$jJ&z%6moE#PtMiHH;!HqaQydAlW{4iJPhzUwJ)Fw_2^uVVi7Tj#iwNRPzt zEw@3!_{58~EVbKW42PLu0Q5y%Sn?Q{c}>URTDV%6SD4hFwmuCm@*dXO0x-d^Nnqf| z8t{%rKSdYw^##g!~L!G z^~taDvt^F-Rs#-*;U-~&Qe)Li=2o-(JKI+sNbk&Na+-7(C@A>dB!8+!72IS^oz3q& zb9I&aPJTS%NfMn+qPCl&Px|awkR(f!@%+y2b%*lrdZTd>s;&g>&)kRvTh!;L2{)N5 z&ql?sp1J;x+1;Xi+$oWe0}WFvWc!!dr?LS=@8KuMa&doqlls{GH&>(CvWp6^j1y+q zKi3dSI$}-+(RY`#(Xx1d)7r>>UYd>b0}tsA_NReFJo*nb*h0~GA~5ZRk- z;@=cc|1_6pW92MIl2C`924b1ih7;agBvP4JV9F6*$iAeGXY%|fwES$2t&eXnP z3^tH%_LRZ>vCL6)qf%iM-9Vt|Q|LQ*FOH7K^8EJ4fBRwA?fbV^%ILSTR8HqSZml5S zbhcYQB;zmjI-^VzMR!V2Egf|o`kof0@$pDn-M+v5kDh1Td4F%&86O`nilsCOaKlct z$~2*T3x&I^UMK*>wc13Z9S%5~40lQdwR;HZQn52T9(PuI`~Tt@*WLTK_Y`?_d_0n& z+M9zoz>6TO-6vq^%Cw09S0x5&G1{FI#O=uex%MSV+PnS9zkJGfYxlMHe^ivocm@qB z#d>Lw&XEZ2OCS-z^FgUzRDgRn9x3XN@4vQtBTv`v?i{?eC&``B`1rTu@n|Bey>eYB z@q=y}p*!G9@HlBtl_$n0WEr}Cu(NxU54CUKyZioIlAC0008?P)t-s0002* zyJF?9M7w$u--adqiZA=bE$49<||`11PJ zj{n`7C+@>i0rYZiND*xxR{-r3}rEt)9g#Z8l|J5h{{r&y?`}z6z_xAMv(VR4=cXOvn;WiQ59z8N-DuJgzO`@> z#UUWbi5IjkEzp!5$5T@KphVG}J?FD1^6lcnM@RaPKh%L0=Gep5r*!H}O!<61_-s7+ z@!kEgNcUko>*m@0zEjnvQq7MU{_x8DsYm#AJ-IY9)|@8$qodibVCdk_=-bHR&8+v6 zlk|jy)~nGtsv_>{;@-lb^?7;Jqi@faEbF=| zz-|)m*ud*jQT@A2_f|O1eHE`~5w>Lz;JSRtUtao_L*>Sr_l%6xTU`CNOv#TbyBiwr z%*@`QpVyO)#5gze#Vg2n6x_X+^4HeXgMaX3W9GD2*g84ktS#xkzWnLB_*^xlARqPN z;Oonj*|&?{se0vjc*|;NLpw>l0`p+!mpMv60PtuDR%vost0000_bW%=J01E#8Jp4)={wNew{r&tu zH5dN-{{H=$Y5mKl`F}I~;a*Jq=DU$~x~r;_Q~isEbz@rQ&!L`j@UG?G-qg^=mEgs) z=gGv3=h(``zPE{fRP2%f024_`L_t(|+U%4;YuaEK#}_bhN)jDJC5VSs>Cl$af~U6h z*22b0P)4bTF?QK^5D$f(cFiSJB9VaR)Pn?yvav%+4#PseLIcA~KgFK6alUUD@4=U4 zFzD~rfBC)7)0F@7;+bduL(-cmO8Rd|9~X<;^fY-I#iYbWn#O&0_K%O_U$o9U?pz;Rz*rYI=qc&5vsnzoBKZRMhBpm; z9C)_v1!HlGl2UxO%7+Ew1y1DM`8cq#I?oBv8}H4?&N7 z7E=6Rd0qGuT&9ww!pBCFW>SfoV&7c)3~ce>!*Q8IwNp5LeI!XUKsu^$)HL$ZaY8!s z*N1y64@}hVF;sht{Dn{{l}Z&Miz70{J`d}Ij{Wt>i;e^3vH~x##CP%EWplagpBv|M znV4_FaR41o1NiGBhz@$dwxLLJxk30Q>L$_y@EI0R(Fcgi z?Wr6wzjpgL8a>|D^5pz8;CSRNBjj`^T%aJ(>j+* zlX!J+arIHtv=1*Q`IT?L{>y5zd;#uMbmx{Gb*ql^o&J4W13LGMomKd%R{f+Q?iS^h zufll-J@Oe4BvpqOx~SVZ9Pcjfv}jg;7jO0bTNHkoG_%;Z(7zz^SrAUopUQoHBoJx2 zf78-{)=j@mE^yI`7N})Oe};V)a#6QAB1)h2uhFd5#dUmv_iYHx9`@GLvQ?~g%Wc+x)@AG+{=l6Yj^6i^~ z->WxLlu_@E13*txcQo-Wo1UU{`Y$W-H*fFV@^_&QiGTYhUHTRG8elBF!5bga^tPlK zL;yOS5de<*)AZZh{w~#bEAcP*N_ZIoz*q=iO@(#f7XgARN6X;~{a(>?)8CCq;=eT$ zuXy@~D}}?q{1U*yJl3fUAQfIu)6e_*6biY&8$sett;G8^eZ7P4`ss8e5+MM72c>O_ z(heUHfb~cuO;-lq4Gw~zoETl`nO{o$1C^>)OVZcna=Cv+0&r=uKCZ+>fWxEha`~F( zPHVL_;(yi^fGqKA#d)iRr`>aNa|B?80E|8&02}T(caG1G2foM2iP0TE949_L37eg? zL#03crg^joe<#okD2rprV2`z#>wba&j7n7t0dVC}_}lxfHRV9>-w2+omGdSo(r{=| zj}~4}<_Zc(01h(&aQQF*VFkYd!N~k0MMUt|@$u>63hwV^GJDaWW0U}xUBMPW&_w{o zK4So{9q2{BBWT+^&z$EMU6S8aR4Oq+=kf7eW0xG4PIFu#W|ge~0SFKP=Mn}OHj&QE zCY%0b)=d2K$^lJJ=l)Zx@%WHBK3!T~SXeG`{5g4nHGu&V1Zx}veD#e=0Er}DNu4d6 zg)97}jl7_!9_Z_M{5(;gQux7h8reZ-;WWKR0Gt@WDFd)C{sG`ga=?%L%O(DDM2lrQ zRSzjTZ9r9Nk=mW-N~zQ`D3vO4oJZ<6XV8WKY(b~x27sXnuw>SWwE|rUgCCTFJCbY- zElRbf!vegj+9lE~TtC*=!=Ux`NLt9W2k_+c`(PQ70DKr=ljgyXUI0J0dCnl;grW9b zaKEblfB|egy>Yd@9RY1`U%?GShXIy?HiOY0LHcv2<K!T4ba32t-l zqFFr&1;jItgX;^?E&B2WA&hwa^micpRmh6DV1psYVV8=CVF;e0T*lD5}HVI|C2lb1K3r@I>MApM8 z5cGNEDo1CbS`V4=a~W2cCK9A3q>MI?0|45laK~Y{8pS2Zvh1oPmL)l+tiF0ZOXoJq zSAc*Nfi`al$Mt&MYnEc1=b0JFKg%R1M7K_F`8o*z?et`4(*8j&0(dxvoe{+{Nt>2v zJP^pTjSUbA8jKFVUDLeX92jeP#ThWOqJNel3!t0ud_3q3;QXpL>RLhAqZwwlDTd)U zwKrrs78-7d8CEkVo5)5qamg@0L_eDmho{hC(b+ zWK!NR>C^#x^;CYEaS?ez|G@%q&E7=dJARHfoDu91V2xFJPV50VRr-T@ES2}&*8ta@ z09Wi$=5$|9=%t7O*c|<$u7FDlrlyDwY(rFhLnN;1Teq>ogtv6 zGpvm_8b7DvL-*g<0I*}9x=#$V)36_U&0QZeBY6cu6dJ_Htwhhrn!L~EaL2lCeqf|x z8^DLJr@Q|F%-rSz41fTI#vqcGdPW27oyBk$Dx~N;04{9+KPv!7-)nhMpoF9-GR*-H zt;*9VP3NVxltKkQeNqPiXUuXr`P=CS0XVMbL!Rq2lL&)6M?-)?%4)?%9Nr>VLDY`X zDJMq*oY+Sjz+XzO*yl+gj;e!J7k4)Y~dp2^a0 z8_6?=zx=4G+Rs4UkA`78Gx5#up9PK+peNZT)|XrNMs92AXHG!IsIJkbst4F@43J5l z3CQE?M199L2qBPWW)ttrvzucCwjjWRZ+WikDXNI@|3VV@VLZxemW55t34*((Mo zAS6U8@K!Jo$(Fe&(r-tX;sGcYfWdJ5qH5Nbd1zr!PNM|w(_A4o9H`26F>lLyJ$N7? zx{Bqyp`{taoL_ocVFr$3S!W4kd3RJNyg(pk6E!KwhffY^X_Ggi4kO2=+8 z?>tL=f^Ffz+r@I(r@pGoqN!6sdzQMKk|gS5RzlwoJ%tFjIr!SHplwzrb!ZI=^4U*& z^KDk9lYLaN=c9Lt&&vo0j8(_kTXQ+j%82j~NN5TfI$om#Pk{-8)0*c`>Z;zl;n1nb zo52M*0#oiO_T9SF2>r}BPf zU94`#AXqB1kzy}w+oX!79Z zIDz|Rijd@NcP3!Qm4a$qRkzt)Pp4BZ0gBlU{13Z?@T%T)Ka~aUT?5?b1b<8 z!ArEMu*5Dq8XU^{$E5B#=R%id*yD<;CjFr>iG7{)%tyo4sz@P#A`b zYze6E!1BPt%!GiuU;(6xR<4PXLWAp+rer~tA|Ve)M@VGwPL?WLh7Mj*FE*7rFx6Ml zJLuB){M4sz)4HTTQ{O4F0?%{4?>omrh8Cr^ef<21*amMN9h{tCW8Ex!T@iHrx>EVL zrmsJAvtZoLFdL6?hKyfctsGpE9eeixTlD1M;l@A0CV+sZ6+B4RwTKDuDIBe?Up##J zly9uAO#fmT9 z0tc^ubbwC>YEkI86Z-!0t$?T!tShG?S2XNp{~NAwa6CSE_-eg8Vk2NriB|r(K)FU1 zwk?KWf*#`bH9q5uQW*~WIXvq&MQ1P?l@0Y#8`Xnr9M$9T`Asv`IPnG z0xwm^6z7T3X~W13m?gkDJY!Uf`|vPY>yie2VzbF#)zc^-|I(63{iW@Vu#^fgbVi~9-eSJh@XW4o z3e!bq;2dJl@%*|(PlnTnlgXj;g}(?AY=WW~+IBV<2G5xR?n=X7SLl6@SL>fgxD^$q zWG3l+HWvm@q(WAQT=Lu;o6#j6{g?bWv8o^xm%xo@q6pl8E5JcX+!h5_bl}NBd+oUEMP@J+!+!O}92wXurNC{}%7F^HZjGp1=;Ky!K(-oq~05ymPQUO(f zgQ$bB5Sgfe3o=JDxTJrDAEYkXgO4sWHFp~;1?d0@sUZTS#0s)t11{+t&&%&>_42*F zV$@IssQ?FF2S_jrcyN(ia6zy+T++qrgUC(VEzIA3sWz=dDr64463?I^MN|N0XwK$v zk1bx}v3!(&|LAosVT}+DOhQ^f0|8A1V4xXWz&Ra>8QwJR-7!YTf&wptlHeNBM1^1S z1RHQp57Moh0FUb5IeHVbkU2ntYw&m~oXg09%@c!;(Qg9(d#SeS7I#SFV4yT0q9VW< zI|$N<(JiwfkDlLms9_wG#g7xjob4v0Z8r2j`7<}8VOkpD7TYLFA(BrFa|C5wT n<*Ke5BD!8J<2&yEbEkX;k2>>20{{bq00000NkvXXu0mjfCe?f_ literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/093_凋谢.aa715ee6.png b/frontend/dist/assets/093_凋谢.aa715ee6.png new file mode 100644 index 0000000000000000000000000000000000000000..6b618a3af2d66aa5ac2da0bf677dce2420a7c644 GIT binary patch literal 5137 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 literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/096_便便.b0d5c50c.png b/frontend/dist/assets/096_便便.b0d5c50c.png new file mode 100644 index 0000000000000000000000000000000000000000..07126f8af89535adfaff260fa59b10b0300b6d90 GIT binary patch literal 5693 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 literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/099_庆祝.2d9e8f8a.png b/frontend/dist/assets/099_庆祝.2d9e8f8a.png new file mode 100644 index 0000000000000000000000000000000000000000..cfdf01450515a00cc236e9c6795aac98673680b8 GIT binary patch literal 5048 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 literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/104_烟花.61568e1e.png b/frontend/dist/assets/104_烟花.61568e1e.png new file mode 100644 index 0000000000000000000000000000000000000000..330aca8088d9b591a725f7d24ab7ee579e8817ca GIT binary patch literal 6371 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 literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/105_爆竹.35531687.png b/frontend/dist/assets/105_爆竹.35531687.png new file mode 100644 index 0000000000000000000000000000000000000000..f1a6a0b36dab9c130ac4ec4ade23d3525510862c GIT binary patch literal 4552 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 literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/107_跳跳.24101efa.png b/frontend/dist/assets/107_跳跳.24101efa.png new file mode 100644 index 0000000000000000000000000000000000000000..e211b8c88ef0daaaa7572e18d4c1c6094e231632 GIT binary patch literal 4273 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 NU}j`x*o4N!{tuLS!;Sy| literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/108_发抖.3eabd306.png b/frontend/dist/assets/108_发抖.3eabd306.png new file mode 100644 index 0000000000000000000000000000000000000000..41596e8114e44f3943706af5f70d718d17f18133 GIT binary patch literal 4563 zcmY*cXHXMdunnOlp$F;Gd+$Y%(5sYCm8O75Q<^|Pnjt`F0YaB1RRsj8Qbl_2`hkFS z6zLs-Q1bZR_vgJcvuDq}b7p5}_RgKzSh$f61%w#_001cTbTv(HGxFa65#I92a`FWL z0KA49m}}i0Z$ShAkP`y`)Bo|mzW)yb0D$l|000^wkQDI0>i-xB2>!hxBmK9?ttJEl z2?_tLF`VP{sVqO;mU}lEyASbe#s<4e!*h!IZmtxb?)5G)f z;<&kQJ#aX@o{4EUUAByYA&8o~iHYgXojbodIS;wG@Z8)R$uhS#ZEfv}ii(da?8|X- zbcBS@)tFW>a(I4zGcz+uKJp?bzV9fhw~l<<$qGg=+S^X>c>Etq3S24AItAHwl02S^ z1J|v%0fk;(US71x;dyxu@6eDC5&q3o!gVO%s)cctf}4ztxIWlX+P%FD`P~$GT(i_k zzUa1?*yZ#K3JQuXK|#Es;f|sro{{eIo8ykOH14zbB`fnOBV7tM5tnuUFiUDHRuosx z|CgVCi-+g(XZXIF+CiQIp8f9CS}tx-Ye!D*tXLo_66NXf02ngWmpnFj2p5ET8<+Q7%gt(Zf%h|w-2M@NX zDRy@Ea^9pTVB&D&7Hb&!8xavG6siXX^AZuAot;%zefn5lmY0{~W2 z)`545jje%^2~9(Dv%fwzGKlv_oOPPQV6f9Fc`-3D4i0u^W@bla#?{qT{Os&rp3!N& zlAN4uou}}5sZaquy}1mnKNPAaKz)y!!Wsg>N1^vW*qfW1>FQ|rz7kvG;7FmR6=sGU zH@`lt@-#L!I;qo*G2;j|WbI>NF%*a5mIsbI67f%;o+>MQX)%9fV89OzpN*H|)6(8V zBT8f35@lrY_4WA5N_=6_>2SeNZ4SP*6<=Dq@)3bW*i9rFd_}6g6Bf=7Eu6l68HRqQ zMrHsUn0R;nWPx>9!$9ntg}@g|C5PS**?uo%=&KW=LJL?Zuk;Vv6s~hoGK*+^t=*pT zWVDBacz11eK}4wcGkuBuKfnJOEqzy#|0doX+;7?e08lFEX{wnA&h6#|Jfd~E+fS>F z1k|dj`j{*2EC%oUz{Mn;0M1B`TBvG0oTvw7z@H%silHkKM<@3L}cuIL4FJl%1Dy1KQ5BNUF8MtAl!<#iESD~0SuzUx6_IslQZL?Y> z>j0e=zU(~knvV3%x0JZ~>7wcR)g9Ti0_j;^-k&fhy@MKW+)t_1Ov`#i8bgMcd+7k* z+u#5fEzeMmVrSNk!kSXjFiOn2c$upx6_MuU%XpOt7Q^hmBEw5Xgsgd*1f92N7U?3R zp_vb15C5GPw^6J8u@~u49R_aL7zUA(rd37O$ zD{=QxAx{jSshMWI+HW~b6mJmfvv8k5xPJMdZ>DyYFqO!V5TAy&7w^j=sT{ikRuKuY zi&{QFemZ?@%((!(wN&7N25*>fORHWgtA`I6P=ar_1bLJc^O24N88@Q}L0b28`S;L2 zQhI7&lnQ(~_z~&~)K{h9RUIdI`#na-0i$K+rYxj1o0f|k)2;>oMNHhYpH*`M_N~%x z5ZkLMrKdDoHJ4=gJMju>r4JOjfh@4SI##`xnnkKYV{V3)y>UqsyObbtp$hTq5&J~f zzMYun=@nl|`pMaMt39wp6M%=e|jE+3rwQWfsDaL1mbJ-Vw zL3&slvAL%0nZu_)KApbCU*|7fx71-p42wRu)^d=Z9x^+J><;YjXuffX-mE!m-N!ct zx~n7#JLyT$B|dz(ui}5$C7!>3Cw7SCL5>9B-FY-G^6h!>1fgWY$$;8jV?7hW%ne<$ zu7o?b{#)@++9QPQkqO_c$(O^Ol6(k0+1dnOXMw!03JeNuUzSx>Rf>vw2l)kz{ zvl&x6K_lYpu;nmWrAtOL^pn2Ay7|aMRQTa1+s_a`B)a@7p&P_1fDE0bBI*+{yRV5e z^%9k_$Y7_T;Yy15^MtrU)78I1o%!e&X_{W6?&vm27#nTBQcIwuNOenlBmL8(bP-Vz zk^3SdoSeYifm;j@b2B>;loEhVUa7ATyjum?AV0)b8q3K4ps$_C&+ebMO67(vVJ7SS z22-S$G)HoDwg4LH>goiAaDhxR4Gk`?qi1Hbz+6M2J~278n{SeWEWgXmg`&3jhQ6sb z7q|q1rJ+=(UIEy4J}cRQ*dX)LV`+_9j9v7jPxTKCGx8DP78&xV{PBp9;> zn$!FUiMYMpuWaJArZ`tJB4f{u31!b?qT8CR+*CWn+r`=sQ_hB}9JZ1uEg9REoFKeOY zzW(y}RaoApm&LRHHQmya;D~`Ed5{zjleT1Dz`}kVb$)WUeP=r0q=z(k4_}$GGrKei zth-y?`28c}^cg6Fl#{q_eLRbm9lwa%jimbQr>}35_+-2N@MrpdrUrDamH^{b!QHEzhQkp1@y-%3OX}?8~v<9b#~v`Yjr+p_^#X@!^a3c zf;6(aHHNX!=hv;en(pHX#r)aZi|j%#?RH~X<%3M0yZ1OAM(|kye5>?!=s_gJir`2J zvRgk@tg4XvnB8vM;W(Ab-O9?3Kd)e&>n-c+bF?}EclX-n2w4MZoQ#Z$G(`jFAMNCL zA!^potM$=S-K&27)B+QFs>~he^C%V&&3<3cizP}L`rp6)DRB=c9peOgCB??RI$Jnp zSsx*%%mA@TLl?iJpKsrrjE?rn+ZdXE3A4b8fg#S%RbkZHBgAxGm87f%kreY*?P1q8 zUTyLLo>#e62a=xyT}j`=j~|O&t!-NaoSjG89My`5nmeWeTp<1qNXeQqT%9n}mxhI2 z43m^!#|VQ~$fXb(n|0Fs-J$dGsNzsgMugK77$G580!7sU5-bYIzAVM|Mmcya_afe9 zlpF}{-RmPdm}liz@RnR8ikRv!k$hQ*X$UU^W)Y}U*MVc$SEg5c4~Da-S()G&foB>T z9{@>@x?7r)j%8<{*uQbKw8W?r)bDx<5hk8GKe#-~6_xp+eM8QVQh~9;p|YOjEC7r`X%^eiUDwJbo0rl;X7dlflKjinWHY48T&OEEBAtr_n9@R=Ud4PIEBL=om zJtrrAy7{e~q|xcbA&x!!Q}N=ll@|)sGv|j%{8fKqh--$CC=~Fsb(d---87U8%%xB=S^1*A`)?Nj5Qbe!jgFhP(Kg%5NN|>V5R9u^kV$`DsgslR9XrxP_3fFQ~4igRtVh)thub9sk&RZhrCb!Bk?#W`}=8ANYT}=yXyc&wfXO`>xs@FBq_h_#mrxs8(&xtBc zqU0!kzK!JYRX40IP#f><=ewIotMxuoT!hnf2@@qah{n;oY*ci-p?MaZKC3ebI@3M?#|zl+T9IRpR?>AjOwZ{v5`nw2oKMjt1Ius zsgVZ1Ud-JUv_F!WDy*&sIk3!akeQSx!rQ1YRXn1Ltq2J+xjg4DefG|f0uc;3l`$x} zk(2DNK+8b->k|lQLjS%aVtIMz`M}WPbXbs0gLXS(7rJ%Oqd@Tv8$C@nO(tnhf*ZuW z_+yF!`==|3mbUqlPKmjz1l(re(S10_NNGwmdM`Q8gVVTFb56rL)wOFxMVg3A>W>;X z=vWF%EG0xn!a_o7Fi2vM1Q?TOA~X)86~wwAi7%wexn(HsxUI>5_?wUGvyW@iYFF_- zwO(Eq)J8`P$S;u_gVKi``mL-C8^Y^5C2q#dykQX^cJSK!U)A*do{jtM)xB~Wnn)tbT)1=*93G;;v7tLxjr8lx82rXwot3Omu%SS*D_kiD%Jr9fMk}G%xcf zQ8C=a6Rar~{TpDb=C{Zg&;^RvLj8h(?&hA4SEfSvPU()kk!s zvd4h0?I@3S2RihW+>gYu2edr*4~Cuxbp7#KtKt3SIf)>2JmRQA`3TDxPAAn!+NNpz z3=RrZnrVjhGO-2R+b|saF_jrXr9@Y*ankfoL0A?u?(f9jSKtvRn0l|7llh#;=U6+DLp+# z{au@F4hlYRQQ&^4jl2$gZDWZY*3(rBjHCwZDt2wXHcIn+JqKkAhy(%{lJv+azInot zeV(foI7so$=HqfibisWw(Jo+Bfb}7Nle^ZJ*KiWZM0Gm0s!6L6dJ=w3Z4LM_8MVK% z>)uc7kP*~5)hpStM6djitPC)>f-QQW|Mj8DnBhLhKk-+C3zM}=Vbw2RtuY+>~d7~7D1*4K7BvJvy4$DbP=w~mi;V-U*MFHA0&EZC6AW@Rac zE?$v`u~pVc?$RryXz}1L{`V@EU9{Bsv9w7B!7ef>O}^Sp+XP=%*OUe+zpwUOJgE*i uL4N`UqQ2n4!U61FRfnGcZF8L$3~zPVeYKvxIKEv@0eV_SnxE9|QU3!&DtG$; literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/109_转圈.67669ca4.png b/frontend/dist/assets/109_转圈.67669ca4.png new file mode 100644 index 0000000000000000000000000000000000000000..f81e84ff71f02327620514c16230961c469f5c5f GIT binary patch literal 4137 zcmV+^5Z3RBP)C00090P)t-s0000E z2LlWT0{{R3000000000001gEL5CQ@W2Lb>9000000000E1_IK5HUIzs0000000031 z0000000000000000PmAI0001{78U>i00000@R~9J0000000RI3l|3EokvRYW0P~|V z_irr4c`xXWH}97>=#e&;K_2$4G3$^x{+&JSlQ&j16q=fv`I$T6iZwD7394u)x^pZ` z3JRiRCiIp%-ib7@Y%2dGB&@8gDh39N6cqI%BULpNvTiEtkvPVBFXSK~#2Xu=W+(L{ zBmW~KjS~|900960|K|=4=MD_|s3hhM3;D)A{~{szswW2o0_>4E>W(<}_xJnz{QAQ? z`oK5&xijkz4emZZ?vywG9vb~kP3$u>^p-mCm@?`gALtVk4h{{AiH83rBxwS)pDp(xA&?Uj{}d1_1O%m} zr2U;e|2H?l85x@s6E-0YMFO zLm(FKlukMb%D~W`xL+vPz;XV7dQ>opq$ucUJuv;&hkP9o^zWZAAJxULb7x^y^|OC_ zOzz^~%D=0enTCafVLu=7B|iWF43bGiK~#9!?9n|AgD?z0VY^B5>j(l-hg51MZsV2v zABK$yL>SDJ?*eal&~@E?=xwQSQfi8|B#-bYM{&?A?^Zqh$iYL9l;H#BPYCk-lKE6F zFOY?M{zP6tk{$Wdm_Q0v%?-jAL4=#R(d>K@U}Ajc44Ef{8bx z|F_UWX(=uAeeTA9^aR%IP2j;Ave*z04q5CDS?oDuf-^ZGnLGq9fh>8J`lKdw&=%!4 z7;d`H`o6n!tl;+0zvp@IA1dt%oVxIK4VvM6rBu}%ySJrMWoy@P^X9JqtGo5&R@XhOLx>bh9UumKy7&H@OUah_xh5&0m9 zD}dolZX({5(MHaOV4?Tq=={7J!)J2AP&1JE7^*n%P3Z@5-@XpqnDBitfEsG}B3?B@ z4iFE5ggpkI4kw_eMgaB8$zz+~>^y6^Kk*|UHK|U38u<~+o>JhjCjiOG*1?ci9i^y*Hn1r-aG;1tpBmEV&( z&l3k=r#urvQhw^Xd|(;a0SbW7u!FU=le>X&&;$;EuEr!h zANK7FZ7-X3)DstArl>1|)DxOFYv%p?pT2wz4hdPYVmA=10D+L;;IEG!eg2$+yQf59 zIS2=Pzx`egvT)h4W4B%}g@D($jvb2$-o0Y?@>6GV#Q{GPCAkpZ6Q^FBbT2{E^i7v#*DGW+o1#+sU%Y7nTY zX>2?^d-jw$Ijy&rB_!Oz8VG`%Bp3fYqUa6?I<hV;zYt*to;KH z5?f%Pa8!bFG@%aIldvo+D+}m`@Nj=DAUr%GGApYq<|MW_V3j4!0TRf0SAh+h1OPfY z_f1705L8rTXLof0-2w(6Tf4F=fHEMdX$hyWg#ZgL8BIVgS*Qb8p{BfFA2Y4Q7YYI) z7D6bPU|(WF$Y!kBz?3uxFoQJ-p*bMvPDtV0X?-QWa8LqdBRDG)6ADja%ZEV=SKGNU zg3A8AS=fPixNQzyvb4?k#<$m(w<2INHL$+w4peFw_OXPtlQ}3n2a$f z^xS*LPCE=qkVoiA(R2~=Dk%E#l=q_I6Q@{lTNpH6S?&MV4^vyV_EF+ z%l+Mj2jk=BGh+aF`+DOCLaZiD8oC|KhwVSz`@;_I0Kk0JIqd$vZBn5tH%Hz?a*CDW zgUk>-`nD5UCncU=0esmwMwf)8sj4=18~QaBRNOS1?RKx%Yqy)to6wD?>``N2NRC>p zD79=^W(tC#$IT8$%L3j9=j?w+muZ5NACyW_)g&X?*G(IIu~5HkQ}27OC~4rv@=}?m ztKh#gQ*nG<7Vvp~JCiI=5(HPJvo$4ODHc^n8XIoX>kmhI%QQ{fHqDkk8ulB>foqKM zWrI79<=8G)MULRz>(qJyTRZar1OZSW$~0Zd)@q89&sX4XsE(#-(hN9qd~rUnfIE;g zT!A2j!4m(6qZJlG9^%uupujO=Ri?|OQWj@G$07=dYgi5Lsob}N|1QSAz4PYX{@yC< z(1suIB!VtO281k9^3}e3Dxdl7=mO~=v9-C%W(?@VAS3}|Mgbxi5i(?%h7unddu41E zr*4q@kQuTS*{L0DuCWXovULau63E94fC0oQ42BELfgKQrk%w<@^}l3*7MtTUWZI9w z{vgC}0f;c9Pn!3r@VCF(CMB``IO8NOlsgX^FcH@hJG>=k0DfBQ2NBb17zi5b0(>G= zL;zz5|HKS`p40z%dAhfq3ZV3)#o`EF$b=)}YkQej@Lyd8P5Fv%L|(n8Px zcLFM~CJyY!?(-a+YZ;zS{l`WLo6 zm_^0Nk|h}}Dh#_xQCLx~3uQkf)@r$~DCmzO`dI`Oy~k~zE6&a~&zcZD|NPQ+*4B3k^>V~1|jK_6C#4BYx&8i6wS2uWKSr>8}Xr7DV>q|e-2vnU)>YirSeEi>+H|r}lh%?UWRnoABp$ADh2pJ$*KGuBG zzFt3-Ks$lJByPwEwc?Ab$3gZtc>_J&8EVI!jNXd(N%xZF zIf>OEeSLbnigp|%oyP8-x91hiW`0XKNn{W`2k%MoHT|z!5Gr1k!}^j#v`|kqMLP)* z?}cA(g0J`(8J6UaWGn;G!rXGAjMRVR7ZhK2*ENH++4%+;<}GGpFb5cflW^tFN_g4c zK#q@n#oFeRHb-ZR(6($O8-qwAdry;?hK*GZ&XL1wKHDtKb-Te}`j~g;$R4c|?v5_22LF=~NC&bM5Y0Y^`<*Xznb=ZcN}|t)|Omt~pq))dGda zy4r^pm8!D^Nm*a^WsHjRP3!!b2Iu-}wHe%270yE4Lz_z5DcBctj9AfiCU*GI)3dpS zZG0)sZ&`_I-VhgxeO1zMZM0S_n8l33yB?Jp1(#|_ zLEl1V z0$ib#7o1qz)ap+tkAVOSgV3CD@g>}Fps<8Tu4;I}go+g0us~8!#0wzr(1pW=+!8ro nB$aW)h+LUM!u`j8{2TZMV8XKb>RU-R00000NkvXXu0mjfz&@MA literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/emoji.b5d5ea11.png b/frontend/dist/assets/emoji.b5d5ea11.png new file mode 100644 index 0000000000000000000000000000000000000000..840cda192fd9aae6f75171d370ed1358046935d1 GIT binary patch literal 4977 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 N$_g6tm9nP6{{dkQ`-}hp literal 0 HcmV?d00001 diff --git a/frontend/dist/assets/index.beba636e.js b/frontend/dist/assets/index.beba636e.js new file mode 100644 index 0000000..009d820 --- /dev/null +++ b/frontend/dist/assets/index.beba636e.js @@ -0,0 +1,348 @@ +function E1(e,t){for(var n=0;nr[o]})}}}return Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const o of document.querySelectorAll('link[rel="modulepreload"]'))r(o);new MutationObserver(o=>{for(const i of o)if(i.type==="childList")for(const a of i.addedNodes)a.tagName==="LINK"&&a.rel==="modulepreload"&&r(a)}).observe(document,{childList:!0,subtree:!0});function n(o){const i={};return o.integrity&&(i.integrity=o.integrity),o.referrerpolicy&&(i.referrerPolicy=o.referrerpolicy),o.crossorigin==="use-credentials"?i.credentials="include":o.crossorigin==="anonymous"?i.credentials="omit":i.credentials="same-origin",i}function r(o){if(o.ep)return;o.ep=!0;const i=n(o);fetch(o.href,i)}})();var Hr=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};function ud(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}function aE(e){var t=e.default;if(typeof t=="function"){var n=function(){return t.apply(this,arguments)};n.prototype=t.prototype}else n={};return Object.defineProperty(n,"__esModule",{value:!0}),Object.keys(e).forEach(function(r){var o=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(n,r,o.get?o:{enumerable:!0,get:function(){return e[r]}})}),n}var f={exports:{}},gt={};/** + * @license React + * react.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var _s=Symbol.for("react.element"),lE=Symbol.for("react.portal"),sE=Symbol.for("react.fragment"),cE=Symbol.for("react.strict_mode"),uE=Symbol.for("react.profiler"),dE=Symbol.for("react.provider"),fE=Symbol.for("react.context"),vE=Symbol.for("react.forward_ref"),pE=Symbol.for("react.suspense"),gE=Symbol.for("react.memo"),hE=Symbol.for("react.lazy"),Bm=Symbol.iterator;function mE(e){return e===null||typeof e!="object"?null:(e=Bm&&e[Bm]||e["@@iterator"],typeof e=="function"?e:null)}var M1={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},O1=Object.assign,R1={};function Qa(e,t,n){this.props=e,this.context=t,this.refs=R1,this.updater=n||M1}Qa.prototype.isReactComponent={};Qa.prototype.setState=function(e,t){if(typeof e!="object"&&typeof e!="function"&&e!=null)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")};Qa.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};function I1(){}I1.prototype=Qa.prototype;function Ag(e,t,n){this.props=e,this.context=t,this.refs=R1,this.updater=n||M1}var Dg=Ag.prototype=new I1;Dg.constructor=Ag;O1(Dg,Qa.prototype);Dg.isPureReactComponent=!0;var jm=Array.isArray,P1=Object.prototype.hasOwnProperty,Lg={current:null},T1={key:!0,ref:!0,__self:!0,__source:!0};function N1(e,t,n){var r,o={},i=null,a=null;if(t!=null)for(r in t.ref!==void 0&&(a=t.ref),t.key!==void 0&&(i=""+t.key),t)P1.call(t,r)&&!T1.hasOwnProperty(r)&&(o[r]=t[r]);var l=arguments.length-2;if(l===1)o.children=n;else if(1>>1,k=M[B];if(0>>1;Bo(W,A))Yo(K,W)?(M[B]=K,M[Y]=A,B=Y):(M[B]=W,M[H]=A,B=H);else if(Yo(K,A))M[B]=K,M[Y]=A,B=Y;else break e}}return L}function o(M,L){var A=M.sortIndex-L.sortIndex;return A!==0?A:M.id-L.id}if(typeof performance=="object"&&typeof performance.now=="function"){var i=performance;e.unstable_now=function(){return i.now()}}else{var a=Date,l=a.now();e.unstable_now=function(){return a.now()-l}}var s=[],c=[],u=1,d=null,v=3,h=!1,g=!1,p=!1,b=typeof setTimeout=="function"?setTimeout:null,m=typeof clearTimeout=="function"?clearTimeout:null,y=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function S(M){for(var L=n(c);L!==null;){if(L.callback===null)r(c);else if(L.startTime<=M)r(c),L.sortIndex=L.expirationTime,t(s,L);else break;L=n(c)}}function x(M){if(p=!1,S(M),!g)if(n(s)!==null)g=!0,_($);else{var L=n(c);L!==null&&O(x,L.startTime-M)}}function $(M,L){g=!1,p&&(p=!1,m(R),R=-1),h=!0;var A=v;try{for(S(L),d=n(s);d!==null&&(!(d.expirationTime>L)||M&&!I());){var B=d.callback;if(typeof B=="function"){d.callback=null,v=d.priorityLevel;var k=B(d.expirationTime<=L);L=e.unstable_now(),typeof k=="function"?d.callback=k:d===n(s)&&r(s),S(L)}else r(s);d=n(s)}if(d!==null)var j=!0;else{var H=n(c);H!==null&&O(x,H.startTime-L),j=!1}return j}finally{d=null,v=A,h=!1}}var E=!1,w=null,R=-1,P=5,N=-1;function I(){return!(e.unstable_now()-NM||125B?(M.sortIndex=A,t(c,M),n(s)===null&&M===n(c)&&(p?(m(R),R=-1):p=!0,O(x,A-B))):(M.sortIndex=k,t(s,M),g||h||(g=!0,_($))),M},e.unstable_shouldYield=I,e.unstable_wrapCallback=function(M){var L=v;return function(){var A=v;v=L;try{return M.apply(this,arguments)}finally{v=A}}}})(A1);(function(e){e.exports=A1})(_1);/** + * @license React + * react-dom.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var D1=f.exports,or=_1.exports;function me(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),Nv=Object.prototype.hasOwnProperty,xE=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,Wm={},Vm={};function wE(e){return Nv.call(Vm,e)?!0:Nv.call(Wm,e)?!1:xE.test(e)?Vm[e]=!0:(Wm[e]=!0,!1)}function $E(e,t,n,r){if(n!==null&&n.type===0)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return r?!1:n!==null?!n.acceptsBooleans:(e=e.toLowerCase().slice(0,5),e!=="data-"&&e!=="aria-");default:return!1}}function EE(e,t,n,r){if(t===null||typeof t>"u"||$E(e,t,n,r))return!0;if(r)return!1;if(n!==null)switch(n.type){case 3:return!t;case 4:return t===!1;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}function Ln(e,t,n,r,o,i,a){this.acceptsBooleans=t===2||t===3||t===4,this.attributeName=r,this.attributeNamespace=o,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=i,this.removeEmptyString=a}var Sn={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){Sn[e]=new Ln(e,0,!1,e,null,!1,!1)});[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var t=e[0];Sn[t]=new Ln(t,1,!1,e[1],null,!1,!1)});["contentEditable","draggable","spellCheck","value"].forEach(function(e){Sn[e]=new Ln(e,2,!1,e.toLowerCase(),null,!1,!1)});["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){Sn[e]=new Ln(e,2,!1,e,null,!1,!1)});"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(e){Sn[e]=new Ln(e,3,!1,e.toLowerCase(),null,!1,!1)});["checked","multiple","muted","selected"].forEach(function(e){Sn[e]=new Ln(e,3,!0,e,null,!1,!1)});["capture","download"].forEach(function(e){Sn[e]=new Ln(e,4,!1,e,null,!1,!1)});["cols","rows","size","span"].forEach(function(e){Sn[e]=new Ln(e,6,!1,e,null,!1,!1)});["rowSpan","start"].forEach(function(e){Sn[e]=new Ln(e,5,!1,e.toLowerCase(),null,!1,!1)});var Fg=/[\-:]([a-z])/g;function kg(e){return e[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(e){var t=e.replace(Fg,kg);Sn[t]=new Ln(t,1,!1,e,null,!1,!1)});"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var t=e.replace(Fg,kg);Sn[t]=new Ln(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)});["xml:base","xml:lang","xml:space"].forEach(function(e){var t=e.replace(Fg,kg);Sn[t]=new Ln(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)});["tabIndex","crossOrigin"].forEach(function(e){Sn[e]=new Ln(e,1,!1,e.toLowerCase(),null,!1,!1)});Sn.xlinkHref=new Ln("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1);["src","href","action","formAction"].forEach(function(e){Sn[e]=new Ln(e,1,!1,e.toLowerCase(),null,!0,!0)});function Bg(e,t,n,r){var o=Sn.hasOwnProperty(t)?Sn[t]:null;(o!==null?o.type!==0:r||!(2l||o[a]!==i[l]){var s=` +`+o[a].replace(" at new "," at ");return e.displayName&&s.includes("")&&(s=s.replace("",e.displayName)),s}while(1<=a&&0<=l);break}}}finally{Ef=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?Rl(e):""}function ME(e){switch(e.tag){case 5:return Rl(e.type);case 16:return Rl("Lazy");case 13:return Rl("Suspense");case 19:return Rl("SuspenseList");case 0:case 2:case 15:return e=Mf(e.type,!1),e;case 11:return e=Mf(e.type.render,!1),e;case 1:return e=Mf(e.type,!0),e;default:return""}}function Lv(e){if(e==null)return null;if(typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case ca:return"Fragment";case sa:return"Portal";case _v:return"Profiler";case jg:return"StrictMode";case Av:return"Suspense";case Dv:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case F1:return(e.displayName||"Context")+".Consumer";case z1:return(e._context.displayName||"Context")+".Provider";case Hg:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case Wg:return t=e.displayName||null,t!==null?t:Lv(e.type)||"Memo";case Ro:t=e._payload,e=e._init;try{return Lv(e(t))}catch{}}return null}function OE(e){var t=e.type;switch(e.tag){case 24:return"Cache";case 9:return(t.displayName||"Context")+".Consumer";case 10:return(t._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=t.render,e=e.displayName||e.name||"",t.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return t;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return Lv(t);case 8:return t===jg?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof t=="function")return t.displayName||t.name||null;if(typeof t=="string")return t}return null}function Ko(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function B1(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}function RE(e){var t=B1(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),r=""+e[t];if(!e.hasOwnProperty(t)&&typeof n<"u"&&typeof n.get=="function"&&typeof n.set=="function"){var o=n.get,i=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return o.call(this)},set:function(a){r=""+a,i.call(this,a)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return r},setValue:function(a){r=""+a},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}function ac(e){e._valueTracker||(e._valueTracker=RE(e))}function j1(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r="";return e&&(r=B1(e)?e.checked?"true":"false":e.value),e=r,e!==n?(t.setValue(e),!0):!1}function vu(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}function zv(e,t){var n=t.checked;return Wt({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:n!=null?n:e._wrapperState.initialChecked})}function Ym(e,t){var n=t.defaultValue==null?"":t.defaultValue,r=t.checked!=null?t.checked:t.defaultChecked;n=Ko(t.value!=null?t.value:n),e._wrapperState={initialChecked:r,initialValue:n,controlled:t.type==="checkbox"||t.type==="radio"?t.checked!=null:t.value!=null}}function H1(e,t){t=t.checked,t!=null&&Bg(e,"checked",t,!1)}function Fv(e,t){H1(e,t);var n=Ko(t.value),r=t.type;if(n!=null)r==="number"?(n===0&&e.value===""||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if(r==="submit"||r==="reset"){e.removeAttribute("value");return}t.hasOwnProperty("value")?kv(e,t.type,n):t.hasOwnProperty("defaultValue")&&kv(e,t.type,Ko(t.defaultValue)),t.checked==null&&t.defaultChecked!=null&&(e.defaultChecked=!!t.defaultChecked)}function Gm(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var r=t.type;if(!(r!=="submit"&&r!=="reset"||t.value!==void 0&&t.value!==null))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}n=e.name,n!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,n!==""&&(e.name=n)}function kv(e,t,n){(t!=="number"||vu(e.ownerDocument)!==e)&&(n==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}var Il=Array.isArray;function Ma(e,t,n,r){if(e=e.options,t){t={};for(var o=0;o"+t.valueOf().toString()+"",t=lc.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}});function ns(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&n.nodeType===3){n.nodeValue=t;return}}e.textContent=t}var Ll={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},IE=["Webkit","ms","Moz","O"];Object.keys(Ll).forEach(function(e){IE.forEach(function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),Ll[t]=Ll[e]})});function Y1(e,t,n){return t==null||typeof t=="boolean"||t===""?"":n||typeof t!="number"||t===0||Ll.hasOwnProperty(e)&&Ll[e]?(""+t).trim():t+"px"}function G1(e,t){e=e.style;for(var n in t)if(t.hasOwnProperty(n)){var r=n.indexOf("--")===0,o=Y1(n,t[n],r);n==="float"&&(n="cssFloat"),r?e.setProperty(n,o):e[n]=o}}var PE=Wt({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function Hv(e,t){if(t){if(PE[e]&&(t.children!=null||t.dangerouslySetInnerHTML!=null))throw Error(me(137,e));if(t.dangerouslySetInnerHTML!=null){if(t.children!=null)throw Error(me(60));if(typeof t.dangerouslySetInnerHTML!="object"||!("__html"in t.dangerouslySetInnerHTML))throw Error(me(61))}if(t.style!=null&&typeof t.style!="object")throw Error(me(62))}}function Wv(e,t){if(e.indexOf("-")===-1)return typeof t.is=="string";switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var Vv=null;function Vg(e){return e=e.target||e.srcElement||window,e.correspondingUseElement&&(e=e.correspondingUseElement),e.nodeType===3?e.parentNode:e}var Uv=null,Oa=null,Ra=null;function Xm(e){if(e=zs(e)){if(typeof Uv!="function")throw Error(me(280));var t=e.stateNode;t&&(t=gd(t),Uv(e.stateNode,e.type,t))}}function K1(e){Oa?Ra?Ra.push(e):Ra=[e]:Oa=e}function q1(){if(Oa){var e=Oa,t=Ra;if(Ra=Oa=null,Xm(e),t)for(e=0;e>>=0,e===0?32:31-(jE(e)/HE|0)|0}var sc=64,cc=4194304;function Pl(e){switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return e&4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return e&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return e}}function mu(e,t){var n=e.pendingLanes;if(n===0)return 0;var r=0,o=e.suspendedLanes,i=e.pingedLanes,a=n&268435455;if(a!==0){var l=a&~o;l!==0?r=Pl(l):(i&=a,i!==0&&(r=Pl(i)))}else a=n&~o,a!==0?r=Pl(a):i!==0&&(r=Pl(i));if(r===0)return 0;if(t!==0&&t!==r&&(t&o)===0&&(o=r&-r,i=t&-t,o>=i||o===16&&(i&4194240)!==0))return t;if((r&4)!==0&&(r|=n&16),t=e.entangledLanes,t!==0)for(e=e.entanglements,t&=r;0n;n++)t.push(e);return t}function Ds(e,t,n){e.pendingLanes|=t,t!==536870912&&(e.suspendedLanes=0,e.pingedLanes=0),e=e.eventTimes,t=31-Ar(t),e[t]=n}function YE(e,t){var n=e.pendingLanes&~t;e.pendingLanes=t,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=t,e.mutableReadLanes&=t,e.entangledLanes&=t,t=e.entanglements;var r=e.eventTimes;for(e=e.expirationTimes;0=Fl),i0=String.fromCharCode(32),a0=!1;function gS(e,t){switch(e){case"keyup":return SM.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function hS(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var ua=!1;function xM(e,t){switch(e){case"compositionend":return hS(t);case"keypress":return t.which!==32?null:(a0=!0,i0);case"textInput":return e=t.data,e===i0&&a0?null:e;default:return null}}function wM(e,t){if(ua)return e==="compositionend"||!Zg&&gS(e,t)?(e=vS(),Vc=qg=No=null,ua=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=r}e:{for(;n;){if(n.nextSibling){n=n.nextSibling;break e}n=n.parentNode}n=void 0}n=u0(n)}}function SS(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?SS(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function CS(){for(var e=window,t=vu();t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href=="string"}catch{n=!1}if(n)e=t.contentWindow;else break;t=vu(e.document)}return t}function Jg(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}function NM(e){var t=CS(),n=e.focusedElem,r=e.selectionRange;if(t!==n&&n&&n.ownerDocument&&SS(n.ownerDocument.documentElement,n)){if(r!==null&&Jg(n)){if(t=r.start,e=r.end,e===void 0&&(e=t),"selectionStart"in n)n.selectionStart=t,n.selectionEnd=Math.min(e,n.value.length);else if(e=(t=n.ownerDocument||document)&&t.defaultView||window,e.getSelection){e=e.getSelection();var o=n.textContent.length,i=Math.min(r.start,o);r=r.end===void 0?i:Math.min(r.end,o),!e.extend&&i>r&&(o=r,r=i,i=o),o=d0(n,i);var a=d0(n,r);o&&a&&(e.rangeCount!==1||e.anchorNode!==o.node||e.anchorOffset!==o.offset||e.focusNode!==a.node||e.focusOffset!==a.offset)&&(t=t.createRange(),t.setStart(o.node,o.offset),e.removeAllRanges(),i>r?(e.addRange(t),e.extend(a.node,a.offset)):(t.setEnd(a.node,a.offset),e.addRange(t)))}}for(t=[],e=n;e=e.parentNode;)e.nodeType===1&&t.push({element:e,left:e.scrollLeft,top:e.scrollTop});for(typeof n.focus=="function"&&n.focus(),n=0;n=document.documentMode,da=null,Qv=null,Bl=null,Zv=!1;function f0(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;Zv||da==null||da!==vu(r)||(r=da,"selectionStart"in r&&Jg(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),Bl&&ss(Bl,r)||(Bl=r,r=Su(Qv,"onSelect"),0pa||(e.current=op[pa],op[pa]=null,pa--)}function _t(e,t){pa++,op[pa]=e.current,e.current=t}var qo={},On=oi(qo),Vn=oi(!1),Ri=qo;function Fa(e,t){var n=e.type.contextTypes;if(!n)return qo;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===t)return r.__reactInternalMemoizedMaskedChildContext;var o={},i;for(i in n)o[i]=t[i];return r&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=o),o}function Un(e){return e=e.childContextTypes,e!=null}function xu(){zt(Vn),zt(On)}function b0(e,t,n){if(On.current!==qo)throw Error(me(168));_t(On,t),_t(Vn,n)}function PS(e,t,n){var r=e.stateNode;if(t=t.childContextTypes,typeof r.getChildContext!="function")return n;r=r.getChildContext();for(var o in r)if(!(o in t))throw Error(me(108,OE(e)||"Unknown",o));return Wt({},n,r)}function wu(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||qo,Ri=On.current,_t(On,e),_t(Vn,Vn.current),!0}function S0(e,t,n){var r=e.stateNode;if(!r)throw Error(me(169));n?(e=PS(e,t,Ri),r.__reactInternalMemoizedMergedChildContext=e,zt(Vn),zt(On),_t(On,e)):zt(Vn),_t(Vn,n)}var lo=null,hd=!1,Bf=!1;function TS(e){lo===null?lo=[e]:lo.push(e)}function VM(e){hd=!0,TS(e)}function ii(){if(!Bf&&lo!==null){Bf=!0;var e=0,t=Ot;try{var n=lo;for(Ot=1;e>=a,o-=a,uo=1<<32-Ar(t)+o|n<R?(P=w,w=null):P=w.sibling;var N=v(m,w,S[R],x);if(N===null){w===null&&(w=P);break}e&&w&&N.alternate===null&&t(m,w),y=i(N,y,R),E===null?$=N:E.sibling=N,E=N,w=P}if(R===S.length)return n(m,w),Ft&&ui(m,R),$;if(w===null){for(;RR?(P=w,w=null):P=w.sibling;var I=v(m,w,N.value,x);if(I===null){w===null&&(w=P);break}e&&w&&I.alternate===null&&t(m,w),y=i(I,y,R),E===null?$=I:E.sibling=I,E=I,w=P}if(N.done)return n(m,w),Ft&&ui(m,R),$;if(w===null){for(;!N.done;R++,N=S.next())N=d(m,N.value,x),N!==null&&(y=i(N,y,R),E===null?$=N:E.sibling=N,E=N);return Ft&&ui(m,R),$}for(w=r(m,w);!N.done;R++,N=S.next())N=h(w,m,R,N.value,x),N!==null&&(e&&N.alternate!==null&&w.delete(N.key===null?R:N.key),y=i(N,y,R),E===null?$=N:E.sibling=N,E=N);return e&&w.forEach(function(z){return t(m,z)}),Ft&&ui(m,R),$}function b(m,y,S,x){if(typeof S=="object"&&S!==null&&S.type===ca&&S.key===null&&(S=S.props.children),typeof S=="object"&&S!==null){switch(S.$$typeof){case ic:e:{for(var $=S.key,E=y;E!==null;){if(E.key===$){if($=S.type,$===ca){if(E.tag===7){n(m,E.sibling),y=o(E,S.props.children),y.return=m,m=y;break e}}else if(E.elementType===$||typeof $=="object"&&$!==null&&$.$$typeof===Ro&&O0($)===E.type){n(m,E.sibling),y=o(E,S.props),y.ref=hl(m,E,S),y.return=m,m=y;break e}n(m,E);break}else t(m,E);E=E.sibling}S.type===ca?(y=$i(S.props.children,m.mode,x,S.key),y.return=m,m=y):(x=Zc(S.type,S.key,S.props,null,m.mode,x),x.ref=hl(m,y,S),x.return=m,m=x)}return a(m);case sa:e:{for(E=S.key;y!==null;){if(y.key===E)if(y.tag===4&&y.stateNode.containerInfo===S.containerInfo&&y.stateNode.implementation===S.implementation){n(m,y.sibling),y=o(y,S.children||[]),y.return=m,m=y;break e}else{n(m,y);break}else t(m,y);y=y.sibling}y=Kf(S,m.mode,x),y.return=m,m=y}return a(m);case Ro:return E=S._init,b(m,y,E(S._payload),x)}if(Il(S))return g(m,y,S,x);if(dl(S))return p(m,y,S,x);hc(m,S)}return typeof S=="string"&&S!==""||typeof S=="number"?(S=""+S,y!==null&&y.tag===6?(n(m,y.sibling),y=o(y,S),y.return=m,m=y):(n(m,y),y=Gf(S,m.mode,x),y.return=m,m=y),a(m)):n(m,y)}return b}var Ba=kS(!0),BS=kS(!1),Fs={},Qr=oi(Fs),fs=oi(Fs),vs=oi(Fs);function yi(e){if(e===Fs)throw Error(me(174));return e}function sh(e,t){switch(_t(vs,t),_t(fs,e),_t(Qr,Fs),e=t.nodeType,e){case 9:case 11:t=(t=t.documentElement)?t.namespaceURI:jv(null,"");break;default:e=e===8?t.parentNode:t,t=e.namespaceURI||null,e=e.tagName,t=jv(t,e)}zt(Qr),_t(Qr,t)}function ja(){zt(Qr),zt(fs),zt(vs)}function jS(e){yi(vs.current);var t=yi(Qr.current),n=jv(t,e.type);t!==n&&(_t(fs,e),_t(Qr,n))}function ch(e){fs.current===e&&(zt(Qr),zt(fs))}var jt=oi(0);function Iu(e){for(var t=e;t!==null;){if(t.tag===13){var n=t.memoizedState;if(n!==null&&(n=n.dehydrated,n===null||n.data==="$?"||n.data==="$!"))return t}else if(t.tag===19&&t.memoizedProps.revealOrder!==void 0){if((t.flags&128)!==0)return t}else if(t.child!==null){t.child.return=t,t=t.child;continue}if(t===e)break;for(;t.sibling===null;){if(t.return===null||t.return===e)return null;t=t.return}t.sibling.return=t.return,t=t.sibling}return null}var jf=[];function uh(){for(var e=0;en?n:4,e(!0);var r=Hf.transition;Hf.transition={};try{e(!1),t()}finally{Ot=n,Hf.transition=r}}function rC(){return br().memoizedState}function KM(e,t,n){var r=Vo(e);if(n={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null},oC(e))iC(t,n);else if(n=DS(e,t,n,r),n!==null){var o=_n();Dr(n,e,r,o),aC(n,t,r)}}function qM(e,t,n){var r=Vo(e),o={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null};if(oC(e))iC(t,o);else{var i=e.alternate;if(e.lanes===0&&(i===null||i.lanes===0)&&(i=t.lastRenderedReducer,i!==null))try{var a=t.lastRenderedState,l=i(a,n);if(o.hasEagerState=!0,o.eagerState=l,Br(l,a)){var s=t.interleaved;s===null?(o.next=o,ah(t)):(o.next=s.next,s.next=o),t.interleaved=o;return}}catch{}finally{}n=DS(e,t,o,r),n!==null&&(o=_n(),Dr(n,e,r,o),aC(n,t,r))}}function oC(e){var t=e.alternate;return e===Ht||t!==null&&t===Ht}function iC(e,t){jl=Pu=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function aC(e,t,n){if((n&4194240)!==0){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,Yg(e,n)}}var Tu={readContext:yr,useCallback:Cn,useContext:Cn,useEffect:Cn,useImperativeHandle:Cn,useInsertionEffect:Cn,useLayoutEffect:Cn,useMemo:Cn,useReducer:Cn,useRef:Cn,useState:Cn,useDebugValue:Cn,useDeferredValue:Cn,useTransition:Cn,useMutableSource:Cn,useSyncExternalStore:Cn,useId:Cn,unstable_isNewReconciler:!1},XM={readContext:yr,useCallback:function(e,t){return Gr().memoizedState=[e,t===void 0?null:t],e},useContext:yr,useEffect:I0,useImperativeHandle:function(e,t,n){return n=n!=null?n.concat([e]):null,Kc(4194308,4,ZS.bind(null,t,e),n)},useLayoutEffect:function(e,t){return Kc(4194308,4,e,t)},useInsertionEffect:function(e,t){return Kc(4,2,e,t)},useMemo:function(e,t){var n=Gr();return t=t===void 0?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var r=Gr();return t=n!==void 0?n(t):t,r.memoizedState=r.baseState=t,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:t},r.queue=e,e=e.dispatch=KM.bind(null,Ht,e),[r.memoizedState,e]},useRef:function(e){var t=Gr();return e={current:e},t.memoizedState=e},useState:R0,useDebugValue:gh,useDeferredValue:function(e){return Gr().memoizedState=e},useTransition:function(){var e=R0(!1),t=e[0];return e=GM.bind(null,e[1]),Gr().memoizedState=e,[t,e]},useMutableSource:function(){},useSyncExternalStore:function(e,t,n){var r=Ht,o=Gr();if(Ft){if(n===void 0)throw Error(me(407));n=n()}else{if(n=t(),fn===null)throw Error(me(349));(Pi&30)!==0||VS(r,t,n)}o.memoizedState=n;var i={value:n,getSnapshot:t};return o.queue=i,I0(YS.bind(null,r,i,e),[e]),r.flags|=2048,hs(9,US.bind(null,r,i,n,t),void 0,null),n},useId:function(){var e=Gr(),t=fn.identifierPrefix;if(Ft){var n=fo,r=uo;n=(r&~(1<<32-Ar(r)-1)).toString(32)+n,t=":"+t+"R"+n,n=ps++,0<\/script>",e=e.removeChild(e.firstChild)):typeof r.is=="string"?e=a.createElement(n,{is:r.is}):(e=a.createElement(n),n==="select"&&(a=e,r.multiple?a.multiple=!0:r.size&&(a.size=r.size))):e=a.createElementNS(e,n),e[Kr]=t,e[ds]=r,gC(e,t,!1,!1),t.stateNode=e;e:{switch(a=Wv(n,r),n){case"dialog":Dt("cancel",e),Dt("close",e),o=r;break;case"iframe":case"object":case"embed":Dt("load",e),o=r;break;case"video":case"audio":for(o=0;oWa&&(t.flags|=128,r=!0,ml(i,!1),t.lanes=4194304)}else{if(!r)if(e=Iu(a),e!==null){if(t.flags|=128,r=!0,n=e.updateQueue,n!==null&&(t.updateQueue=n,t.flags|=4),ml(i,!0),i.tail===null&&i.tailMode==="hidden"&&!a.alternate&&!Ft)return xn(t),null}else 2*Xt()-i.renderingStartTime>Wa&&n!==1073741824&&(t.flags|=128,r=!0,ml(i,!1),t.lanes=4194304);i.isBackwards?(a.sibling=t.child,t.child=a):(n=i.last,n!==null?n.sibling=a:t.child=a,i.last=a)}return i.tail!==null?(t=i.tail,i.rendering=t,i.tail=t.sibling,i.renderingStartTime=Xt(),t.sibling=null,n=jt.current,_t(jt,r?n&1|2:n&1),t):(xn(t),null);case 22:case 23:return Ch(),r=t.memoizedState!==null,e!==null&&e.memoizedState!==null!==r&&(t.flags|=8192),r&&(t.mode&1)!==0?(er&1073741824)!==0&&(xn(t),t.subtreeFlags&6&&(t.flags|=8192)):xn(t),null;case 24:return null;case 25:return null}throw Error(me(156,t.tag))}function oO(e,t){switch(th(t),t.tag){case 1:return Un(t.type)&&xu(),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return ja(),zt(Vn),zt(On),uh(),e=t.flags,(e&65536)!==0&&(e&128)===0?(t.flags=e&-65537|128,t):null;case 5:return ch(t),null;case 13:if(zt(jt),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(me(340));ka()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return zt(jt),null;case 4:return ja(),null;case 10:return ih(t.type._context),null;case 22:case 23:return Ch(),null;case 24:return null;default:return null}}var yc=!1,En=!1,iO=typeof WeakSet=="function"?WeakSet:Set,De=null;function ya(e,t){var n=e.ref;if(n!==null)if(typeof n=="function")try{n(null)}catch(r){Yt(e,t,r)}else n.current=null}function hp(e,t,n){try{n()}catch(r){Yt(e,t,r)}}var F0=!1;function aO(e,t){if(Jv=yu,e=CS(),Jg(e)){if("selectionStart"in e)var n={start:e.selectionStart,end:e.selectionEnd};else e:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var o=r.anchorOffset,i=r.focusNode;r=r.focusOffset;try{n.nodeType,i.nodeType}catch{n=null;break e}var a=0,l=-1,s=-1,c=0,u=0,d=e,v=null;t:for(;;){for(var h;d!==n||o!==0&&d.nodeType!==3||(l=a+o),d!==i||r!==0&&d.nodeType!==3||(s=a+r),d.nodeType===3&&(a+=d.nodeValue.length),(h=d.firstChild)!==null;)v=d,d=h;for(;;){if(d===e)break t;if(v===n&&++c===o&&(l=a),v===i&&++u===r&&(s=a),(h=d.nextSibling)!==null)break;d=v,v=d.parentNode}d=h}n=l===-1||s===-1?null:{start:l,end:s}}else n=null}n=n||{start:0,end:0}}else n=null;for(ep={focusedElem:e,selectionRange:n},yu=!1,De=t;De!==null;)if(t=De,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,De=e;else for(;De!==null;){t=De;try{var g=t.alternate;if((t.flags&1024)!==0)switch(t.tag){case 0:case 11:case 15:break;case 1:if(g!==null){var p=g.memoizedProps,b=g.memoizedState,m=t.stateNode,y=m.getSnapshotBeforeUpdate(t.elementType===t.type?p:Rr(t.type,p),b);m.__reactInternalSnapshotBeforeUpdate=y}break;case 3:var S=t.stateNode.containerInfo;S.nodeType===1?S.textContent="":S.nodeType===9&&S.documentElement&&S.removeChild(S.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(me(163))}}catch(x){Yt(t,t.return,x)}if(e=t.sibling,e!==null){e.return=t.return,De=e;break}De=t.return}return g=F0,F0=!1,g}function Hl(e,t,n){var r=t.updateQueue;if(r=r!==null?r.lastEffect:null,r!==null){var o=r=r.next;do{if((o.tag&e)===e){var i=o.destroy;o.destroy=void 0,i!==void 0&&hp(t,n,i)}o=o.next}while(o!==r)}}function bd(e,t){if(t=t.updateQueue,t=t!==null?t.lastEffect:null,t!==null){var n=t=t.next;do{if((n.tag&e)===e){var r=n.create;n.destroy=r()}n=n.next}while(n!==t)}}function mp(e){var t=e.ref;if(t!==null){var n=e.stateNode;switch(e.tag){case 5:e=n;break;default:e=n}typeof t=="function"?t(e):t.current=e}}function yC(e){var t=e.alternate;t!==null&&(e.alternate=null,yC(t)),e.child=null,e.deletions=null,e.sibling=null,e.tag===5&&(t=e.stateNode,t!==null&&(delete t[Kr],delete t[ds],delete t[rp],delete t[HM],delete t[WM])),e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function bC(e){return e.tag===5||e.tag===3||e.tag===4}function k0(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||bC(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function yp(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.nodeType===8?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(n.nodeType===8?(t=n.parentNode,t.insertBefore(e,n)):(t=n,t.appendChild(e)),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=Cu));else if(r!==4&&(e=e.child,e!==null))for(yp(e,t,n),e=e.sibling;e!==null;)yp(e,t,n),e=e.sibling}function bp(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(e=e.child,e!==null))for(bp(e,t,n),e=e.sibling;e!==null;)bp(e,t,n),e=e.sibling}var gn=null,Pr=!1;function Eo(e,t,n){for(n=n.child;n!==null;)SC(e,t,n),n=n.sibling}function SC(e,t,n){if(Xr&&typeof Xr.onCommitFiberUnmount=="function")try{Xr.onCommitFiberUnmount(dd,n)}catch{}switch(n.tag){case 5:En||ya(n,t);case 6:var r=gn,o=Pr;gn=null,Eo(e,t,n),gn=r,Pr=o,gn!==null&&(Pr?(e=gn,n=n.stateNode,e.nodeType===8?e.parentNode.removeChild(n):e.removeChild(n)):gn.removeChild(n.stateNode));break;case 18:gn!==null&&(Pr?(e=gn,n=n.stateNode,e.nodeType===8?kf(e.parentNode,n):e.nodeType===1&&kf(e,n),as(e)):kf(gn,n.stateNode));break;case 4:r=gn,o=Pr,gn=n.stateNode.containerInfo,Pr=!0,Eo(e,t,n),gn=r,Pr=o;break;case 0:case 11:case 14:case 15:if(!En&&(r=n.updateQueue,r!==null&&(r=r.lastEffect,r!==null))){o=r=r.next;do{var i=o,a=i.destroy;i=i.tag,a!==void 0&&((i&2)!==0||(i&4)!==0)&&hp(n,t,a),o=o.next}while(o!==r)}Eo(e,t,n);break;case 1:if(!En&&(ya(n,t),r=n.stateNode,typeof r.componentWillUnmount=="function"))try{r.props=n.memoizedProps,r.state=n.memoizedState,r.componentWillUnmount()}catch(l){Yt(n,t,l)}Eo(e,t,n);break;case 21:Eo(e,t,n);break;case 22:n.mode&1?(En=(r=En)||n.memoizedState!==null,Eo(e,t,n),En=r):Eo(e,t,n);break;default:Eo(e,t,n)}}function B0(e){var t=e.updateQueue;if(t!==null){e.updateQueue=null;var n=e.stateNode;n===null&&(n=e.stateNode=new iO),t.forEach(function(r){var o=gO.bind(null,e,r);n.has(r)||(n.add(r),r.then(o,o))})}}function Mr(e,t){var n=t.deletions;if(n!==null)for(var r=0;ro&&(o=a),r&=~i}if(r=o,r=Xt()-r,r=(120>r?120:480>r?480:1080>r?1080:1920>r?1920:3e3>r?3e3:4320>r?4320:1960*sO(r/1960))-r,10e?16:e,_o===null)var r=!1;else{if(e=_o,_o=null,Au=0,(wt&6)!==0)throw Error(me(331));var o=wt;for(wt|=4,De=e.current;De!==null;){var i=De,a=i.child;if((De.flags&16)!==0){var l=i.deletions;if(l!==null){for(var s=0;sXt()-bh?wi(e,0):yh|=n),Yn(e,t)}function RC(e,t){t===0&&((e.mode&1)===0?t=1:(t=cc,cc<<=1,(cc&130023424)===0&&(cc=4194304)));var n=_n();e=ho(e,t),e!==null&&(Ds(e,t,n),Yn(e,n))}function pO(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),RC(e,n)}function gO(e,t){var n=0;switch(e.tag){case 13:var r=e.stateNode,o=e.memoizedState;o!==null&&(n=o.retryLane);break;case 19:r=e.stateNode;break;default:throw Error(me(314))}r!==null&&r.delete(t),RC(e,n)}var IC;IC=function(e,t,n){if(e!==null)if(e.memoizedProps!==t.pendingProps||Vn.current)Wn=!0;else{if((e.lanes&n)===0&&(t.flags&128)===0)return Wn=!1,nO(e,t,n);Wn=(e.flags&131072)!==0}else Wn=!1,Ft&&(t.flags&1048576)!==0&&NS(t,Eu,t.index);switch(t.lanes=0,t.tag){case 2:var r=t.type;qc(e,t),e=t.pendingProps;var o=Fa(t,On.current);Pa(t,n),o=fh(null,t,r,e,o,n);var i=vh();return t.flags|=1,typeof o=="object"&&o!==null&&typeof o.render=="function"&&o.$$typeof===void 0?(t.tag=1,t.memoizedState=null,t.updateQueue=null,Un(r)?(i=!0,wu(t)):i=!1,t.memoizedState=o.state!==null&&o.state!==void 0?o.state:null,lh(t),o.updater=md,t.stateNode=o,o._reactInternals=t,cp(t,r,e,n),t=fp(null,t,r,!0,i,n)):(t.tag=0,Ft&&i&&eh(t),Nn(null,t,o,n),t=t.child),t;case 16:r=t.elementType;e:{switch(qc(e,t),e=t.pendingProps,o=r._init,r=o(r._payload),t.type=r,o=t.tag=mO(r),e=Rr(r,e),o){case 0:t=dp(null,t,r,e,n);break e;case 1:t=D0(null,t,r,e,n);break e;case 11:t=_0(null,t,r,e,n);break e;case 14:t=A0(null,t,r,Rr(r.type,e),n);break e}throw Error(me(306,r,""))}return t;case 0:return r=t.type,o=t.pendingProps,o=t.elementType===r?o:Rr(r,o),dp(e,t,r,o,n);case 1:return r=t.type,o=t.pendingProps,o=t.elementType===r?o:Rr(r,o),D0(e,t,r,o,n);case 3:e:{if(fC(t),e===null)throw Error(me(387));r=t.pendingProps,i=t.memoizedState,o=i.element,LS(e,t),Ru(t,r,null,n);var a=t.memoizedState;if(r=a.element,i.isDehydrated)if(i={element:r,isDehydrated:!1,cache:a.cache,pendingSuspenseBoundaries:a.pendingSuspenseBoundaries,transitions:a.transitions},t.updateQueue.baseState=i,t.memoizedState=i,t.flags&256){o=Ha(Error(me(423)),t),t=L0(e,t,r,n,o);break e}else if(r!==o){o=Ha(Error(me(424)),t),t=L0(e,t,r,n,o);break e}else for(tr=jo(t.stateNode.containerInfo.firstChild),rr=t,Ft=!0,_r=null,n=BS(t,null,r,n),t.child=n;n;)n.flags=n.flags&-3|4096,n=n.sibling;else{if(ka(),r===o){t=mo(e,t,n);break e}Nn(e,t,r,n)}t=t.child}return t;case 5:return jS(t),e===null&&ap(t),r=t.type,o=t.pendingProps,i=e!==null?e.memoizedProps:null,a=o.children,tp(r,o)?a=null:i!==null&&tp(r,i)&&(t.flags|=32),dC(e,t),Nn(e,t,a,n),t.child;case 6:return e===null&&ap(t),null;case 13:return vC(e,t,n);case 4:return sh(t,t.stateNode.containerInfo),r=t.pendingProps,e===null?t.child=Ba(t,null,r,n):Nn(e,t,r,n),t.child;case 11:return r=t.type,o=t.pendingProps,o=t.elementType===r?o:Rr(r,o),_0(e,t,r,o,n);case 7:return Nn(e,t,t.pendingProps,n),t.child;case 8:return Nn(e,t,t.pendingProps.children,n),t.child;case 12:return Nn(e,t,t.pendingProps.children,n),t.child;case 10:e:{if(r=t.type._context,o=t.pendingProps,i=t.memoizedProps,a=o.value,_t(Mu,r._currentValue),r._currentValue=a,i!==null)if(Br(i.value,a)){if(i.children===o.children&&!Vn.current){t=mo(e,t,n);break e}}else for(i=t.child,i!==null&&(i.return=t);i!==null;){var l=i.dependencies;if(l!==null){a=i.child;for(var s=l.firstContext;s!==null;){if(s.context===r){if(i.tag===1){s=vo(-1,n&-n),s.tag=2;var c=i.updateQueue;if(c!==null){c=c.shared;var u=c.pending;u===null?s.next=s:(s.next=u.next,u.next=s),c.pending=s}}i.lanes|=n,s=i.alternate,s!==null&&(s.lanes|=n),lp(i.return,n,t),l.lanes|=n;break}s=s.next}}else if(i.tag===10)a=i.type===t.type?null:i.child;else if(i.tag===18){if(a=i.return,a===null)throw Error(me(341));a.lanes|=n,l=a.alternate,l!==null&&(l.lanes|=n),lp(a,n,t),a=i.sibling}else a=i.child;if(a!==null)a.return=i;else for(a=i;a!==null;){if(a===t){a=null;break}if(i=a.sibling,i!==null){i.return=a.return,a=i;break}a=a.return}i=a}Nn(e,t,o.children,n),t=t.child}return t;case 9:return o=t.type,r=t.pendingProps.children,Pa(t,n),o=yr(o),r=r(o),t.flags|=1,Nn(e,t,r,n),t.child;case 14:return r=t.type,o=Rr(r,t.pendingProps),o=Rr(r.type,o),A0(e,t,r,o,n);case 15:return cC(e,t,t.type,t.pendingProps,n);case 17:return r=t.type,o=t.pendingProps,o=t.elementType===r?o:Rr(r,o),qc(e,t),t.tag=1,Un(r)?(e=!0,wu(t)):e=!1,Pa(t,n),FS(t,r,o),cp(t,r,o,n),fp(null,t,r,!0,e,n);case 19:return pC(e,t,n);case 22:return uC(e,t,n)}throw Error(me(156,t.tag))};function PC(e,t){return nS(e,t)}function hO(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function gr(e,t,n,r){return new hO(e,t,n,r)}function wh(e){return e=e.prototype,!(!e||!e.isReactComponent)}function mO(e){if(typeof e=="function")return wh(e)?1:0;if(e!=null){if(e=e.$$typeof,e===Hg)return 11;if(e===Wg)return 14}return 2}function Uo(e,t){var n=e.alternate;return n===null?(n=gr(e.tag,t,e.key,e.mode),n.elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.subtreeFlags=0,n.deletions=null),n.flags=e.flags&14680064,n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=t===null?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function Zc(e,t,n,r,o,i){var a=2;if(r=e,typeof e=="function")wh(e)&&(a=1);else if(typeof e=="string")a=5;else e:switch(e){case ca:return $i(n.children,o,i,t);case jg:a=8,o|=8;break;case _v:return e=gr(12,n,t,o|2),e.elementType=_v,e.lanes=i,e;case Av:return e=gr(13,n,t,o),e.elementType=Av,e.lanes=i,e;case Dv:return e=gr(19,n,t,o),e.elementType=Dv,e.lanes=i,e;case k1:return Cd(n,o,i,t);default:if(typeof e=="object"&&e!==null)switch(e.$$typeof){case z1:a=10;break e;case F1:a=9;break e;case Hg:a=11;break e;case Wg:a=14;break e;case Ro:a=16,r=null;break e}throw Error(me(130,e==null?e:typeof e,""))}return t=gr(a,n,t,o),t.elementType=e,t.type=r,t.lanes=i,t}function $i(e,t,n,r){return e=gr(7,e,r,t),e.lanes=n,e}function Cd(e,t,n,r){return e=gr(22,e,r,t),e.elementType=k1,e.lanes=n,e.stateNode={isHidden:!1},e}function Gf(e,t,n){return e=gr(6,e,null,t),e.lanes=n,e}function Kf(e,t,n){return t=gr(4,e.children!==null?e.children:[],e.key,t),t.lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function yO(e,t,n,r,o){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=Rf(0),this.expirationTimes=Rf(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=Rf(0),this.identifierPrefix=r,this.onRecoverableError=o,this.mutableSourceEagerHydrationData=null}function $h(e,t,n,r,o,i,a,l,s){return e=new yO(e,t,n,l,s),t===1?(t=1,i===!0&&(t|=8)):t=0,i=gr(3,null,null,t),e.current=i,i.stateNode=e,i.memoizedState={element:r,isDehydrated:n,cache:null,transitions:null,pendingSuspenseBoundaries:null},lh(i),e}function bO(e,t,n){var r=3"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(t)}catch(n){console.error(n)}}t(),e.exports=ir})(Gn);const zu=ud(Gn.exports),$O=E1({__proto__:null,default:zu},[Gn.exports]);var AC,K0=Gn.exports;AC=K0.createRoot,K0.hydrateRoot;var $p={exports:{}},_i={},Rh={exports:{}},EO="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED",MO=EO,OO=MO;function DC(){}function LC(){}LC.resetWarningCache=DC;var RO=function(){function e(r,o,i,a,l,s){if(s!==OO){var c=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw c.name="Invariant Violation",c}}e.isRequired=e;function t(){return e}var n={array:e,bigint:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:LC,resetWarningCache:DC};return n.PropTypes=n,n};Rh.exports=RO();var Ep={exports:{}},Wr={},Fu={exports:{}};(function(e,t){Object.defineProperty(t,"__esModule",{value:!0}),t.default=u;/*! + * Adapted from jQuery UI core + * + * http://jqueryui.com + * + * Copyright 2014 jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/category/ui-core/ + */var n="none",r="contents",o=/input|select|textarea|button|object|iframe/;function i(d,v){return v.getPropertyValue("overflow")!=="visible"||d.scrollWidth<=0&&d.scrollHeight<=0}function a(d){var v=d.offsetWidth<=0&&d.offsetHeight<=0;if(v&&!d.innerHTML)return!0;try{var h=window.getComputedStyle(d),g=h.getPropertyValue("display");return v?g!==r&&i(d,h):g===n}catch{return console.warn("Failed to inspect element style"),!1}}function l(d){for(var v=d,h=d.getRootNode&&d.getRootNode();v&&v!==document.body;){if(h&&v===h&&(v=h.host.parentNode),a(v))return!1;v=v.parentNode}return!0}function s(d,v){var h=d.nodeName.toLowerCase(),g=o.test(h)&&!d.disabled||h==="a"&&d.href||v;return g&&l(d)}function c(d){var v=d.getAttribute("tabindex");v===null&&(v=void 0);var h=isNaN(v);return(h||v>=0)&&s(d,!h)}function u(d){var v=[].slice.call(d.querySelectorAll("*"),0).reduce(function(h,g){return h.concat(g.shadowRoot?u(g.shadowRoot):[g])},[]);return v.filter(c)}e.exports=t.default})(Fu,Fu.exports);Object.defineProperty(Wr,"__esModule",{value:!0});Wr.resetState=NO;Wr.log=_O;Wr.handleBlur=ys;Wr.handleFocus=bs;Wr.markForFocusLater=AO;Wr.returnFocus=DO;Wr.popWithoutFocus=LO;Wr.setupScopedFocus=zO;Wr.teardownScopedFocus=FO;var IO=Fu.exports,PO=TO(IO);function TO(e){return e&&e.__esModule?e:{default:e}}var Va=[],Sa=null,Mp=!1;function NO(){Va=[]}function _O(){}function ys(){Mp=!0}function bs(){if(Mp){if(Mp=!1,!Sa)return;setTimeout(function(){if(!Sa.contains(document.activeElement)){var e=(0,PO.default)(Sa)[0]||Sa;e.focus()}},0)}}function AO(){Va.push(document.activeElement)}function DO(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:!1,t=null;try{Va.length!==0&&(t=Va.pop(),t.focus({preventScroll:e}));return}catch{console.warn(["You tried to return focus to",t,"but it is not in the DOM anymore"].join(" "))}}function LO(){Va.length>0&&Va.pop()}function zO(e){Sa=e,window.addEventListener?(window.addEventListener("blur",ys,!1),document.addEventListener("focus",bs,!0)):(window.attachEvent("onBlur",ys),document.attachEvent("onFocus",bs))}function FO(){Sa=null,window.addEventListener?(window.removeEventListener("blur",ys),document.removeEventListener("focus",bs)):(window.detachEvent("onBlur",ys),document.detachEvent("onFocus",bs))}var Op={exports:{}};(function(e,t){Object.defineProperty(t,"__esModule",{value:!0}),t.default=a;var n=Fu.exports,r=o(n);function o(l){return l&&l.__esModule?l:{default:l}}function i(){var l=arguments.length>0&&arguments[0]!==void 0?arguments[0]:document;return l.activeElement.shadowRoot?i(l.activeElement.shadowRoot):l.activeElement}function a(l,s){var c=(0,r.default)(l);if(!c.length){s.preventDefault();return}var u=void 0,d=s.shiftKey,v=c[0],h=c[c.length-1],g=i();if(l===g){if(!d)return;u=h}if(h===g&&!d&&(u=v),v===g&&d&&(u=h),u){s.preventDefault(),u.focus();return}var p=/(\bChrome\b|\bSafari\b)\//.exec(navigator.userAgent),b=p!=null&&p[1]!="Chrome"&&/\biPod\b|\biPad\b/g.exec(navigator.userAgent)==null;if(!!b){var m=c.indexOf(g);if(m>-1&&(m+=d?-1:1),u=c[m],typeof u>"u"){s.preventDefault(),u=d?h:v,u.focus();return}s.preventDefault(),u.focus()}}e.exports=t.default})(Op,Op.exports);var Vr={},kO=function(){},BO=kO,Lr={},zC={exports:{}};/*! + Copyright (c) 2015 Jed Watson. + Based on code that is Copyright 2013-2015, Facebook, Inc. + All rights reserved. +*/(function(e){(function(){var t=!!(typeof window<"u"&&window.document&&window.document.createElement),n={canUseDOM:t,canUseWorkers:typeof Worker<"u",canUseEventListeners:t&&!!(window.addEventListener||window.attachEvent),canUseViewport:t&&!!window.screen};e.exports?e.exports=n:window.ExecutionEnvironment=n})()})(zC);Object.defineProperty(Lr,"__esModule",{value:!0});Lr.canUseDOM=Lr.SafeNodeList=Lr.SafeHTMLCollection=void 0;var jO=zC.exports,HO=WO(jO);function WO(e){return e&&e.__esModule?e:{default:e}}var Md=HO.default,VO=Md.canUseDOM?window.HTMLElement:{};Lr.SafeHTMLCollection=Md.canUseDOM?window.HTMLCollection:{};Lr.SafeNodeList=Md.canUseDOM?window.NodeList:{};Lr.canUseDOM=Md.canUseDOM;Lr.default=VO;Object.defineProperty(Vr,"__esModule",{value:!0});Vr.resetState=qO;Vr.log=XO;Vr.assertNodeList=FC;Vr.setElement=QO;Vr.validateElement=Ih;Vr.hide=ZO;Vr.show=JO;Vr.documentNotReadyOrSSRTesting=eR;var UO=BO,YO=KO(UO),GO=Lr;function KO(e){return e&&e.__esModule?e:{default:e}}var fr=null;function qO(){fr&&(fr.removeAttribute?fr.removeAttribute("aria-hidden"):fr.length!=null?fr.forEach(function(e){return e.removeAttribute("aria-hidden")}):document.querySelectorAll(fr).forEach(function(e){return e.removeAttribute("aria-hidden")})),fr=null}function XO(){}function FC(e,t){if(!e||!e.length)throw new Error("react-modal: No elements were found for selector "+t+".")}function QO(e){var t=e;if(typeof t=="string"&&GO.canUseDOM){var n=document.querySelectorAll(t);FC(n,t),t=n}return fr=t||fr,fr}function Ih(e){var t=e||fr;return t?Array.isArray(t)||t instanceof HTMLCollection||t instanceof NodeList?t:[t]:((0,YO.default)(!1,["react-modal: App element is not defined.","Please use `Modal.setAppElement(el)` or set `appElement={el}`.","This is needed so screen readers don't see main content","when modal is opened. It is not recommended, but you can opt-out","by setting `ariaHideApp={false}`."].join(" ")),[])}function ZO(e){var t=!0,n=!1,r=void 0;try{for(var o=Ih(e)[Symbol.iterator](),i;!(t=(i=o.next()).done);t=!0){var a=i.value;a.setAttribute("aria-hidden","true")}}catch(l){n=!0,r=l}finally{try{!t&&o.return&&o.return()}finally{if(n)throw r}}}function JO(e){var t=!0,n=!1,r=void 0;try{for(var o=Ih(e)[Symbol.iterator](),i;!(t=(i=o.next()).done);t=!0){var a=i.value;a.removeAttribute("aria-hidden")}}catch(l){n=!0,r=l}finally{try{!t&&o.return&&o.return()}finally{if(n)throw r}}}function eR(){fr=null}var el={};Object.defineProperty(el,"__esModule",{value:!0});el.resetState=tR;el.log=nR;var Ul={},Yl={};function q0(e,t){e.classList.remove(t)}function tR(){var e=document.getElementsByTagName("html")[0];for(var t in Ul)q0(e,Ul[t]);var n=document.body;for(var r in Yl)q0(n,Yl[r]);Ul={},Yl={}}function nR(){}var rR=function(t,n){return t[n]||(t[n]=0),t[n]+=1,n},oR=function(t,n){return t[n]&&(t[n]-=1),n},iR=function(t,n,r){r.forEach(function(o){rR(n,o),t.add(o)})},aR=function(t,n,r){r.forEach(function(o){oR(n,o),n[o]===0&&t.remove(o)})};el.add=function(t,n){return iR(t.classList,t.nodeName.toLowerCase()=="html"?Ul:Yl,n.split(" "))};el.remove=function(t,n){return aR(t.classList,t.nodeName.toLowerCase()=="html"?Ul:Yl,n.split(" "))};var tl={};Object.defineProperty(tl,"__esModule",{value:!0});tl.log=sR;tl.resetState=cR;function lR(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var kC=function e(){var t=this;lR(this,e),this.register=function(n){t.openInstances.indexOf(n)===-1&&(t.openInstances.push(n),t.emit("register"))},this.deregister=function(n){var r=t.openInstances.indexOf(n);r!==-1&&(t.openInstances.splice(r,1),t.emit("deregister"))},this.subscribe=function(n){t.subscribers.push(n)},this.emit=function(n){t.subscribers.forEach(function(r){return r(n,t.openInstances.slice())})},this.openInstances=[],this.subscribers=[]},ku=new kC;function sR(){console.log("portalOpenInstances ----------"),console.log(ku.openInstances.length),ku.openInstances.forEach(function(e){return console.log(e)}),console.log("end portalOpenInstances ----------")}function cR(){ku=new kC}tl.default=ku;var Ph={};Object.defineProperty(Ph,"__esModule",{value:!0});Ph.resetState=vR;Ph.log=pR;var uR=tl,dR=fR(uR);function fR(e){return e&&e.__esModule?e:{default:e}}var wn=void 0,Ir=void 0,Ei=[];function vR(){for(var e=[wn,Ir],t=0;t0?(document.body.firstChild!==wn&&document.body.insertBefore(wn,document.body.firstChild),document.body.lastChild!==Ir&&document.body.appendChild(Ir)):(wn.parentElement&&wn.parentElement.removeChild(wn),Ir.parentElement&&Ir.parentElement.removeChild(Ir))}dR.default.subscribe(gR);(function(e,t){Object.defineProperty(t,"__esModule",{value:!0});var n=Object.assign||function(T){for(var D=1;D0&&(z-=1,z===0&&h.show(L)),O.props.shouldFocusAfterRender&&(O.props.shouldReturnFocusAfterClose?(c.returnFocus(O.props.preventScroll),c.teardownScopedFocus()):c.popWithoutFocus()),O.props.onAfterClose&&O.props.onAfterClose(),S.default.deregister(O)},O.open=function(){O.beforeOpen(),O.state.afterOpen&&O.state.beforeClose?(clearTimeout(O.closeTimer),O.setState({beforeClose:!1})):(O.props.shouldFocusAfterRender&&(c.setupScopedFocus(O.node),c.markForFocusLater()),O.setState({isOpen:!0},function(){O.openAnimationFrame=requestAnimationFrame(function(){O.setState({afterOpen:!0}),O.props.isOpen&&O.props.onAfterOpen&&O.props.onAfterOpen({overlayEl:O.overlay,contentEl:O.content})})}))},O.close=function(){O.props.closeTimeoutMS>0?O.closeWithTimeout():O.closeWithoutTimeout()},O.focusContent=function(){return O.content&&!O.contentHasFocus()&&O.content.focus({preventScroll:!0})},O.closeWithTimeout=function(){var M=Date.now()+O.props.closeTimeoutMS;O.setState({beforeClose:!0,closesAt:M},function(){O.closeTimer=setTimeout(O.closeWithoutTimeout,O.state.closesAt-Date.now())})},O.closeWithoutTimeout=function(){O.setState({beforeClose:!1,isOpen:!1,afterOpen:!1,closesAt:null},O.afterClose)},O.handleKeyDown=function(M){N(M)&&(0,d.default)(O.content,M),O.props.shouldCloseOnEsc&&I(M)&&(M.stopPropagation(),O.requestClose(M))},O.handleOverlayOnClick=function(M){O.shouldClose===null&&(O.shouldClose=!0),O.shouldClose&&O.props.shouldCloseOnOverlayClick&&(O.ownerHandlesClose()?O.requestClose(M):O.focusContent()),O.shouldClose=null},O.handleContentOnMouseUp=function(){O.shouldClose=!1},O.handleOverlayOnMouseDown=function(M){!O.props.shouldCloseOnOverlayClick&&M.target==O.overlay&&M.preventDefault()},O.handleContentOnClick=function(){O.shouldClose=!1},O.handleContentOnMouseDown=function(){O.shouldClose=!1},O.requestClose=function(M){return O.ownerHandlesClose()&&O.props.onRequestClose(M)},O.ownerHandlesClose=function(){return O.props.onRequestClose},O.shouldBeClosed=function(){return!O.state.isOpen&&!O.state.beforeClose},O.contentHasFocus=function(){return document.activeElement===O.content||O.content.contains(document.activeElement)},O.buildClassName=function(M,L){var A=(typeof L>"u"?"undefined":r(L))==="object"?L:{base:P[M],afterOpen:P[M]+"--after-open",beforeClose:P[M]+"--before-close"},B=A.base;return O.state.afterOpen&&(B=B+" "+A.afterOpen),O.state.beforeClose&&(B=B+" "+A.beforeClose),typeof L=="string"&&L?B+" "+L:B},O.attributesFromObject=function(M,L){return Object.keys(L).reduce(function(A,B){return A[M+"-"+B]=L[B],A},{})},O.state={afterOpen:!1,beforeClose:!1},O.shouldClose=null,O.moveFromContentToOverlay=null,O}return o(D,[{key:"componentDidMount",value:function(){this.props.isOpen&&this.open()}},{key:"componentDidUpdate",value:function(O,M){this.props.isOpen&&!O.isOpen?this.open():!this.props.isOpen&&O.isOpen&&this.close(),this.props.shouldFocusAfterRender&&this.state.isOpen&&!M.isOpen&&this.focusContent()}},{key:"componentWillUnmount",value:function(){this.state.isOpen&&this.afterClose(),clearTimeout(this.closeTimer),cancelAnimationFrame(this.openAnimationFrame)}},{key:"beforeOpen",value:function(){var O=this.props,M=O.appElement,L=O.ariaHideApp,A=O.htmlOpenClassName,B=O.bodyOpenClassName,k=O.parentSelector,j=k&&k().ownerDocument||document;B&&p.add(j.body,B),A&&p.add(j.getElementsByTagName("html")[0],A),L&&(z+=1,h.hide(M)),S.default.register(this)}},{key:"render",value:function(){var O=this.props,M=O.id,L=O.className,A=O.overlayClassName,B=O.defaultStyles,k=O.children,j=L?{}:B.content,H=A?{}:B.overlay;if(this.shouldBeClosed())return null;var W={ref:this.setOverlayRef,className:this.buildClassName("overlay",A),style:n({},H,this.props.style.overlay),onClick:this.handleOverlayOnClick,onMouseDown:this.handleOverlayOnMouseDown},Y=n({id:M,ref:this.setContentRef,style:n({},j,this.props.style.content),className:this.buildClassName("content",L),tabIndex:"-1",onKeyDown:this.handleKeyDown,onMouseDown:this.handleContentOnMouseDown,onMouseUp:this.handleContentOnMouseUp,onClick:this.handleContentOnClick,role:this.props.role,"aria-label":this.props.contentLabel},this.attributesFromObject("aria",n({modal:!0},this.props.aria)),this.attributesFromObject("data",this.props.data||{}),{"data-testid":this.props.testId}),K=this.props.contentElement(Y,k);return this.props.overlayElement(W,K)}}]),D}(i.Component);F.defaultProps={style:{overlay:{},content:{}},defaultStyles:{}},F.propTypes={isOpen:l.default.bool.isRequired,defaultStyles:l.default.shape({content:l.default.object,overlay:l.default.object}),style:l.default.shape({content:l.default.object,overlay:l.default.object}),className:l.default.oneOfType([l.default.string,l.default.object]),overlayClassName:l.default.oneOfType([l.default.string,l.default.object]),parentSelector:l.default.func,bodyOpenClassName:l.default.string,htmlOpenClassName:l.default.string,ariaHideApp:l.default.bool,appElement:l.default.oneOfType([l.default.instanceOf(m.default),l.default.instanceOf(b.SafeHTMLCollection),l.default.instanceOf(b.SafeNodeList),l.default.arrayOf(l.default.instanceOf(m.default))]),onAfterOpen:l.default.func,onAfterClose:l.default.func,onRequestClose:l.default.func,closeTimeoutMS:l.default.number,shouldFocusAfterRender:l.default.bool,shouldCloseOnOverlayClick:l.default.bool,shouldReturnFocusAfterClose:l.default.bool,preventScroll:l.default.bool,role:l.default.string,contentLabel:l.default.string,aria:l.default.object,data:l.default.object,children:l.default.node,shouldCloseOnEsc:l.default.bool,overlayRef:l.default.func,contentRef:l.default.func,id:l.default.string,overlayElement:l.default.func,contentElement:l.default.func,testId:l.default.string},t.default=F,e.exports=t.default})(Ep,Ep.exports);function BC(){var e=this.constructor.getDerivedStateFromProps(this.props,this.state);e!=null&&this.setState(e)}function jC(e){function t(n){var r=this.constructor.getDerivedStateFromProps(e,n);return r!=null?r:null}this.setState(t.bind(this))}function HC(e,t){try{var n=this.props,r=this.state;this.props=e,this.state=t,this.__reactInternalSnapshotFlag=!0,this.__reactInternalSnapshot=this.getSnapshotBeforeUpdate(n,r)}finally{this.props=n,this.state=r}}BC.__suppressDeprecationWarning=!0;jC.__suppressDeprecationWarning=!0;HC.__suppressDeprecationWarning=!0;function hR(e){var t=e.prototype;if(!t||!t.isReactComponent)throw new Error("Can only polyfill class components");if(typeof e.getDerivedStateFromProps!="function"&&typeof t.getSnapshotBeforeUpdate!="function")return e;var n=null,r=null,o=null;if(typeof t.componentWillMount=="function"?n="componentWillMount":typeof t.UNSAFE_componentWillMount=="function"&&(n="UNSAFE_componentWillMount"),typeof t.componentWillReceiveProps=="function"?r="componentWillReceiveProps":typeof t.UNSAFE_componentWillReceiveProps=="function"&&(r="UNSAFE_componentWillReceiveProps"),typeof t.componentWillUpdate=="function"?o="componentWillUpdate":typeof t.UNSAFE_componentWillUpdate=="function"&&(o="UNSAFE_componentWillUpdate"),n!==null||r!==null||o!==null){var i=e.displayName||e.name,a=typeof e.getDerivedStateFromProps=="function"?"getDerivedStateFromProps()":"getSnapshotBeforeUpdate()";throw Error(`Unsafe legacy lifecycles will not be called for components using new component APIs. + +`+i+" uses "+a+" but also contains the following legacy lifecycles:"+(n!==null?` + `+n:"")+(r!==null?` + `+r:"")+(o!==null?` + `+o:"")+` + +The above lifecycles should be removed. Learn more about this warning here: +https://fb.me/react-async-component-lifecycle-hooks`)}if(typeof e.getDerivedStateFromProps=="function"&&(t.componentWillMount=BC,t.componentWillReceiveProps=jC),typeof t.getSnapshotBeforeUpdate=="function"){if(typeof t.componentDidUpdate!="function")throw new Error("Cannot polyfill getSnapshotBeforeUpdate() for components that do not define componentDidUpdate() on the prototype");t.componentWillUpdate=HC;var l=t.componentDidUpdate;t.componentDidUpdate=function(c,u,d){var v=this.__reactInternalSnapshotFlag?this.__reactInternalSnapshot:d;l.call(this,c,u,v)}}return e}const mR=Object.freeze(Object.defineProperty({__proto__:null,polyfill:hR},Symbol.toStringTag,{value:"Module"})),yR=aE(mR);Object.defineProperty(_i,"__esModule",{value:!0});_i.bodyOpenClassName=_i.portalClassName=void 0;var Q0=Object.assign||function(e){for(var t=1;te.length)&&(t=e.length);for(var n=0,r=new Array(t);n=0)&&(n[o]=e[o]);return n}function Je(e,t){if(e==null)return{};var n=AR(e,t),r,o;if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o=0)&&(!Object.prototype.propertyIsEnumerable.call(e,r)||(n[r]=e[r]))}return n}var GC={exports:{}};/*! + Copyright (c) 2018 Jed Watson. + Licensed under the MIT License (MIT), see + http://jedwatson.github.io/classnames +*/(function(e){(function(){var t={}.hasOwnProperty;function n(){for(var i="",a=0;a1)&&(e=1),e}function wc(e){return e<=1?"".concat(Number(e)*100,"%"):e}function bi(e){return e.length===1?"0"+e:String(e)}function zR(e,t,n){return{r:bn(e,255)*255,g:bn(t,255)*255,b:bn(n,255)*255}}function ry(e,t,n){e=bn(e,255),t=bn(t,255),n=bn(n,255);var r=Math.max(e,t,n),o=Math.min(e,t,n),i=0,a=0,l=(r+o)/2;if(r===o)a=0,i=0;else{var s=r-o;switch(a=l>.5?s/(2-r-o):s/(r+o),r){case e:i=(t-n)/s+(t1&&(n-=1),n<1/6?e+(t-e)*(6*n):n<1/2?t:n<2/3?e+(t-e)*(2/3-n)*6:e}function FR(e,t,n){var r,o,i;if(e=bn(e,360),t=bn(t,100),n=bn(n,100),t===0)o=n,i=n,r=n;else{var a=n<.5?n*(1+t):n+t-n*t,l=2*n-a;r=qf(l,a,e+1/3),o=qf(l,a,e),i=qf(l,a,e-1/3)}return{r:r*255,g:o*255,b:i*255}}function Ip(e,t,n){e=bn(e,255),t=bn(t,255),n=bn(n,255);var r=Math.max(e,t,n),o=Math.min(e,t,n),i=0,a=r,l=r-o,s=r===0?0:l/r;if(r===o)i=0;else{switch(r){case e:i=(t-n)/l+(t>16,g:(e&65280)>>8,b:e&255}}var Tp={aliceblue:"#f0f8ff",antiquewhite:"#faebd7",aqua:"#00ffff",aquamarine:"#7fffd4",azure:"#f0ffff",beige:"#f5f5dc",bisque:"#ffe4c4",black:"#000000",blanchedalmond:"#ffebcd",blue:"#0000ff",blueviolet:"#8a2be2",brown:"#a52a2a",burlywood:"#deb887",cadetblue:"#5f9ea0",chartreuse:"#7fff00",chocolate:"#d2691e",coral:"#ff7f50",cornflowerblue:"#6495ed",cornsilk:"#fff8dc",crimson:"#dc143c",cyan:"#00ffff",darkblue:"#00008b",darkcyan:"#008b8b",darkgoldenrod:"#b8860b",darkgray:"#a9a9a9",darkgreen:"#006400",darkgrey:"#a9a9a9",darkkhaki:"#bdb76b",darkmagenta:"#8b008b",darkolivegreen:"#556b2f",darkorange:"#ff8c00",darkorchid:"#9932cc",darkred:"#8b0000",darksalmon:"#e9967a",darkseagreen:"#8fbc8f",darkslateblue:"#483d8b",darkslategray:"#2f4f4f",darkslategrey:"#2f4f4f",darkturquoise:"#00ced1",darkviolet:"#9400d3",deeppink:"#ff1493",deepskyblue:"#00bfff",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1e90ff",firebrick:"#b22222",floralwhite:"#fffaf0",forestgreen:"#228b22",fuchsia:"#ff00ff",gainsboro:"#dcdcdc",ghostwhite:"#f8f8ff",goldenrod:"#daa520",gold:"#ffd700",gray:"#808080",green:"#008000",greenyellow:"#adff2f",grey:"#808080",honeydew:"#f0fff0",hotpink:"#ff69b4",indianred:"#cd5c5c",indigo:"#4b0082",ivory:"#fffff0",khaki:"#f0e68c",lavenderblush:"#fff0f5",lavender:"#e6e6fa",lawngreen:"#7cfc00",lemonchiffon:"#fffacd",lightblue:"#add8e6",lightcoral:"#f08080",lightcyan:"#e0ffff",lightgoldenrodyellow:"#fafad2",lightgray:"#d3d3d3",lightgreen:"#90ee90",lightgrey:"#d3d3d3",lightpink:"#ffb6c1",lightsalmon:"#ffa07a",lightseagreen:"#20b2aa",lightskyblue:"#87cefa",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#b0c4de",lightyellow:"#ffffe0",lime:"#00ff00",limegreen:"#32cd32",linen:"#faf0e6",magenta:"#ff00ff",maroon:"#800000",mediumaquamarine:"#66cdaa",mediumblue:"#0000cd",mediumorchid:"#ba55d3",mediumpurple:"#9370db",mediumseagreen:"#3cb371",mediumslateblue:"#7b68ee",mediumspringgreen:"#00fa9a",mediumturquoise:"#48d1cc",mediumvioletred:"#c71585",midnightblue:"#191970",mintcream:"#f5fffa",mistyrose:"#ffe4e1",moccasin:"#ffe4b5",navajowhite:"#ffdead",navy:"#000080",oldlace:"#fdf5e6",olive:"#808000",olivedrab:"#6b8e23",orange:"#ffa500",orangered:"#ff4500",orchid:"#da70d6",palegoldenrod:"#eee8aa",palegreen:"#98fb98",paleturquoise:"#afeeee",palevioletred:"#db7093",papayawhip:"#ffefd5",peachpuff:"#ffdab9",peru:"#cd853f",pink:"#ffc0cb",plum:"#dda0dd",powderblue:"#b0e0e6",purple:"#800080",rebeccapurple:"#663399",red:"#ff0000",rosybrown:"#bc8f8f",royalblue:"#4169e1",saddlebrown:"#8b4513",salmon:"#fa8072",sandybrown:"#f4a460",seagreen:"#2e8b57",seashell:"#fff5ee",sienna:"#a0522d",silver:"#c0c0c0",skyblue:"#87ceeb",slateblue:"#6a5acd",slategray:"#708090",slategrey:"#708090",snow:"#fffafa",springgreen:"#00ff7f",steelblue:"#4682b4",tan:"#d2b48c",teal:"#008080",thistle:"#d8bfd8",tomato:"#ff6347",turquoise:"#40e0d0",violet:"#ee82ee",wheat:"#f5deb3",white:"#ffffff",whitesmoke:"#f5f5f5",yellow:"#ffff00",yellowgreen:"#9acd32"};function la(e){var t={r:0,g:0,b:0},n=1,r=null,o=null,i=null,a=!1,l=!1;return typeof e=="string"&&(e=UR(e)),typeof e=="object"&&(oo(e.r)&&oo(e.g)&&oo(e.b)?(t=zR(e.r,e.g,e.b),a=!0,l=String(e.r).substr(-1)==="%"?"prgb":"rgb"):oo(e.h)&&oo(e.s)&&oo(e.v)?(r=wc(e.s),o=wc(e.v),t=kR(e.h,r,o),a=!0,l="hsv"):oo(e.h)&&oo(e.s)&&oo(e.l)&&(r=wc(e.s),i=wc(e.l),t=FR(e.h,r,i),a=!0,l="hsl"),Object.prototype.hasOwnProperty.call(e,"a")&&(n=e.a)),n=KC(n),{ok:a,format:e.format||l,r:Math.min(255,Math.max(t.r,0)),g:Math.min(255,Math.max(t.g,0)),b:Math.min(255,Math.max(t.b,0)),a:n}}var WR="[-\\+]?\\d+%?",VR="[-\\+]?\\d*\\.\\d+%?",Do="(?:".concat(VR,")|(?:").concat(WR,")"),Xf="[\\s|\\(]+(".concat(Do,")[,|\\s]+(").concat(Do,")[,|\\s]+(").concat(Do,")\\s*\\)?"),Qf="[\\s|\\(]+(".concat(Do,")[,|\\s]+(").concat(Do,")[,|\\s]+(").concat(Do,")[,|\\s]+(").concat(Do,")\\s*\\)?"),Or={CSS_UNIT:new RegExp(Do),rgb:new RegExp("rgb"+Xf),rgba:new RegExp("rgba"+Qf),hsl:new RegExp("hsl"+Xf),hsla:new RegExp("hsla"+Qf),hsv:new RegExp("hsv"+Xf),hsva:new RegExp("hsva"+Qf),hex3:/^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,hex6:/^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/,hex4:/^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,hex8:/^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/};function UR(e){if(e=e.trim().toLowerCase(),e.length===0)return!1;var t=!1;if(Tp[e])e=Tp[e],t=!0;else if(e==="transparent")return{r:0,g:0,b:0,a:0,format:"name"};var n=Or.rgb.exec(e);return n?{r:n[1],g:n[2],b:n[3]}:(n=Or.rgba.exec(e),n?{r:n[1],g:n[2],b:n[3],a:n[4]}:(n=Or.hsl.exec(e),n?{h:n[1],s:n[2],l:n[3]}:(n=Or.hsla.exec(e),n?{h:n[1],s:n[2],l:n[3],a:n[4]}:(n=Or.hsv.exec(e),n?{h:n[1],s:n[2],v:n[3]}:(n=Or.hsva.exec(e),n?{h:n[1],s:n[2],v:n[3],a:n[4]}:(n=Or.hex8.exec(e),n?{r:Jn(n[1]),g:Jn(n[2]),b:Jn(n[3]),a:oy(n[4]),format:t?"name":"hex8"}:(n=Or.hex6.exec(e),n?{r:Jn(n[1]),g:Jn(n[2]),b:Jn(n[3]),format:t?"name":"hex"}:(n=Or.hex4.exec(e),n?{r:Jn(n[1]+n[1]),g:Jn(n[2]+n[2]),b:Jn(n[3]+n[3]),a:oy(n[4]+n[4]),format:t?"name":"hex8"}:(n=Or.hex3.exec(e),n?{r:Jn(n[1]+n[1]),g:Jn(n[2]+n[2]),b:Jn(n[3]+n[3]),format:t?"name":"hex"}:!1)))))))))}function oo(e){return Boolean(Or.CSS_UNIT.exec(String(e)))}var Mt=function(){function e(t,n){t===void 0&&(t=""),n===void 0&&(n={});var r;if(t instanceof e)return t;typeof t=="number"&&(t=HR(t)),this.originalInput=t;var o=la(t);this.originalInput=t,this.r=o.r,this.g=o.g,this.b=o.b,this.a=o.a,this.roundA=Math.round(100*this.a)/100,this.format=(r=n.format)!==null&&r!==void 0?r:o.format,this.gradientType=n.gradientType,this.r<1&&(this.r=Math.round(this.r)),this.g<1&&(this.g=Math.round(this.g)),this.b<1&&(this.b=Math.round(this.b)),this.isValid=o.ok}return e.prototype.isDark=function(){return this.getBrightness()<128},e.prototype.isLight=function(){return!this.isDark()},e.prototype.getBrightness=function(){var t=this.toRgb();return(t.r*299+t.g*587+t.b*114)/1e3},e.prototype.getLuminance=function(){var t=this.toRgb(),n,r,o,i=t.r/255,a=t.g/255,l=t.b/255;return i<=.03928?n=i/12.92:n=Math.pow((i+.055)/1.055,2.4),a<=.03928?r=a/12.92:r=Math.pow((a+.055)/1.055,2.4),l<=.03928?o=l/12.92:o=Math.pow((l+.055)/1.055,2.4),.2126*n+.7152*r+.0722*o},e.prototype.getAlpha=function(){return this.a},e.prototype.setAlpha=function(t){return this.a=KC(t),this.roundA=Math.round(100*this.a)/100,this},e.prototype.isMonochrome=function(){var t=this.toHsl().s;return t===0},e.prototype.toHsv=function(){var t=Ip(this.r,this.g,this.b);return{h:t.h*360,s:t.s,v:t.v,a:this.a}},e.prototype.toHsvString=function(){var t=Ip(this.r,this.g,this.b),n=Math.round(t.h*360),r=Math.round(t.s*100),o=Math.round(t.v*100);return this.a===1?"hsv(".concat(n,", ").concat(r,"%, ").concat(o,"%)"):"hsva(".concat(n,", ").concat(r,"%, ").concat(o,"%, ").concat(this.roundA,")")},e.prototype.toHsl=function(){var t=ry(this.r,this.g,this.b);return{h:t.h*360,s:t.s,l:t.l,a:this.a}},e.prototype.toHslString=function(){var t=ry(this.r,this.g,this.b),n=Math.round(t.h*360),r=Math.round(t.s*100),o=Math.round(t.l*100);return this.a===1?"hsl(".concat(n,", ").concat(r,"%, ").concat(o,"%)"):"hsla(".concat(n,", ").concat(r,"%, ").concat(o,"%, ").concat(this.roundA,")")},e.prototype.toHex=function(t){return t===void 0&&(t=!1),Pp(this.r,this.g,this.b,t)},e.prototype.toHexString=function(t){return t===void 0&&(t=!1),"#"+this.toHex(t)},e.prototype.toHex8=function(t){return t===void 0&&(t=!1),BR(this.r,this.g,this.b,this.a,t)},e.prototype.toHex8String=function(t){return t===void 0&&(t=!1),"#"+this.toHex8(t)},e.prototype.toHexShortString=function(t){return t===void 0&&(t=!1),this.a===1?this.toHexString(t):this.toHex8String(t)},e.prototype.toRgb=function(){return{r:Math.round(this.r),g:Math.round(this.g),b:Math.round(this.b),a:this.a}},e.prototype.toRgbString=function(){var t=Math.round(this.r),n=Math.round(this.g),r=Math.round(this.b);return this.a===1?"rgb(".concat(t,", ").concat(n,", ").concat(r,")"):"rgba(".concat(t,", ").concat(n,", ").concat(r,", ").concat(this.roundA,")")},e.prototype.toPercentageRgb=function(){var t=function(n){return"".concat(Math.round(bn(n,255)*100),"%")};return{r:t(this.r),g:t(this.g),b:t(this.b),a:this.a}},e.prototype.toPercentageRgbString=function(){var t=function(n){return Math.round(bn(n,255)*100)};return this.a===1?"rgb(".concat(t(this.r),"%, ").concat(t(this.g),"%, ").concat(t(this.b),"%)"):"rgba(".concat(t(this.r),"%, ").concat(t(this.g),"%, ").concat(t(this.b),"%, ").concat(this.roundA,")")},e.prototype.toName=function(){if(this.a===0)return"transparent";if(this.a<1)return!1;for(var t="#"+Pp(this.r,this.g,this.b,!1),n=0,r=Object.entries(Tp);n=0,i=!n&&o&&(t.startsWith("hex")||t==="name");return i?t==="name"&&this.a===0?this.toName():this.toRgbString():(t==="rgb"&&(r=this.toRgbString()),t==="prgb"&&(r=this.toPercentageRgbString()),(t==="hex"||t==="hex6")&&(r=this.toHexString()),t==="hex3"&&(r=this.toHexString(!0)),t==="hex4"&&(r=this.toHex8String(!0)),t==="hex8"&&(r=this.toHex8String()),t==="name"&&(r=this.toName()),t==="hsl"&&(r=this.toHslString()),t==="hsv"&&(r=this.toHsvString()),r||this.toHexString())},e.prototype.toNumber=function(){return(Math.round(this.r)<<16)+(Math.round(this.g)<<8)+Math.round(this.b)},e.prototype.clone=function(){return new e(this.toString())},e.prototype.lighten=function(t){t===void 0&&(t=10);var n=this.toHsl();return n.l+=t/100,n.l=xc(n.l),new e(n)},e.prototype.brighten=function(t){t===void 0&&(t=10);var n=this.toRgb();return n.r=Math.max(0,Math.min(255,n.r-Math.round(255*-(t/100)))),n.g=Math.max(0,Math.min(255,n.g-Math.round(255*-(t/100)))),n.b=Math.max(0,Math.min(255,n.b-Math.round(255*-(t/100)))),new e(n)},e.prototype.darken=function(t){t===void 0&&(t=10);var n=this.toHsl();return n.l-=t/100,n.l=xc(n.l),new e(n)},e.prototype.tint=function(t){return t===void 0&&(t=10),this.mix("white",t)},e.prototype.shade=function(t){return t===void 0&&(t=10),this.mix("black",t)},e.prototype.desaturate=function(t){t===void 0&&(t=10);var n=this.toHsl();return n.s-=t/100,n.s=xc(n.s),new e(n)},e.prototype.saturate=function(t){t===void 0&&(t=10);var n=this.toHsl();return n.s+=t/100,n.s=xc(n.s),new e(n)},e.prototype.greyscale=function(){return this.desaturate(100)},e.prototype.spin=function(t){var n=this.toHsl(),r=(n.h+t)%360;return n.h=r<0?360+r:r,new e(n)},e.prototype.mix=function(t,n){n===void 0&&(n=50);var r=this.toRgb(),o=new e(t).toRgb(),i=n/100,a={r:(o.r-r.r)*i+r.r,g:(o.g-r.g)*i+r.g,b:(o.b-r.b)*i+r.b,a:(o.a-r.a)*i+r.a};return new e(a)},e.prototype.analogous=function(t,n){t===void 0&&(t=6),n===void 0&&(n=30);var r=this.toHsl(),o=360/n,i=[this];for(r.h=(r.h-(o*t>>1)+720)%360;--t;)r.h=(r.h+o)%360,i.push(new e(r));return i},e.prototype.complement=function(){var t=this.toHsl();return t.h=(t.h+180)%360,new e(t)},e.prototype.monochromatic=function(t){t===void 0&&(t=6);for(var n=this.toHsv(),r=n.h,o=n.s,i=n.v,a=[],l=1/t;t--;)a.push(new e({h:r,s:o,v:i})),i=(i+l)%1;return a},e.prototype.splitcomplement=function(){var t=this.toHsl(),n=t.h;return[this,new e({h:(n+72)%360,s:t.s,l:t.l}),new e({h:(n+216)%360,s:t.s,l:t.l})]},e.prototype.onBackground=function(t){var n=this.toRgb(),r=new e(t).toRgb(),o=n.a+r.a*(1-n.a);return new e({r:(n.r*n.a+r.r*r.a*(1-n.a))/o,g:(n.g*n.a+r.g*r.a*(1-n.a))/o,b:(n.b*n.a+r.b*r.a*(1-n.a))/o,a:o})},e.prototype.triad=function(){return this.polyad(3)},e.prototype.tetrad=function(){return this.polyad(4)},e.prototype.polyad=function(t){for(var n=this.toHsl(),r=n.h,o=[this],i=360/t,a=1;a=60&&Math.round(e.h)<=240?r=n?Math.round(e.h)-$c*t:Math.round(e.h)+$c*t:r=n?Math.round(e.h)+$c*t:Math.round(e.h)-$c*t,r<0?r+=360:r>=360&&(r-=360),r}function sy(e,t,n){if(e.h===0&&e.s===0)return e.s;var r;return n?r=e.s-iy*t:t===XC?r=e.s+iy:r=e.s+YR*t,r>1&&(r=1),n&&t===qC&&r>.1&&(r=.1),r<.06&&(r=.06),Number(r.toFixed(2))}function cy(e,t,n){var r;return n?r=e.v+GR*t:r=e.v-KR*t,r>1&&(r=1),Number(r.toFixed(2))}function Ai(e){for(var t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},n=[],r=la(e),o=qC;o>0;o-=1){var i=ay(r),a=Ec(la({h:ly(i,o,!0),s:sy(i,o,!0),v:cy(i,o,!0)}));n.push(a)}n.push(Ec(r));for(var l=1;l<=XC;l+=1){var s=ay(r),c=Ec(la({h:ly(s,l),s:sy(s,l),v:cy(s,l)}));n.push(c)}return t.theme==="dark"?qR.map(function(u){var d=u.index,v=u.opacity,h=Ec(XR(la(t.backgroundColor||"#141414"),la(n[d]),v*100));return h}):n}var Na={red:"#F5222D",volcano:"#FA541C",orange:"#FA8C16",gold:"#FAAD14",yellow:"#FADB14",lime:"#A0D911",green:"#52C41A",cyan:"#13C2C2",blue:"#1677FF",geekblue:"#2F54EB",purple:"#722ED1",magenta:"#EB2F96",grey:"#666666"},Jc={},Zf={};Object.keys(Na).forEach(function(e){Jc[e]=Ai(Na[e]),Jc[e].primary=Jc[e][5],Zf[e]=Ai(Na[e],{theme:"dark",backgroundColor:"#141414"}),Zf[e].primary=Zf[e][5]});var QR=Jc.blue;function uy(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter(function(o){return Object.getOwnPropertyDescriptor(e,o).enumerable})),n.push.apply(n,r)}return n}function U(e){for(var t=1;t0&&arguments[0]!==void 0?arguments[0]:{},t=e.mark;return t?t.startsWith("data-")?t:"data-".concat(t):ZR}function Od(e){if(e.attachTo)return e.attachTo;var t=document.querySelector("head");return t||document.body}function JR(e){return e==="queue"?"prependQueue":e?"prepend":"append"}function _h(e){return Array.from((_p.get(e)||e).children).filter(function(t){return t.tagName==="STYLE"})}function ZC(e){var t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};if(!Rn())return null;var n=t.csp,r=t.prepend,o=t.priority,i=o===void 0?0:o,a=JR(r),l=a==="prependQueue",s=document.createElement("style");s.setAttribute(dy,a),l&&i&&s.setAttribute(fy,"".concat(i)),n!=null&&n.nonce&&(s.nonce=n==null?void 0:n.nonce),s.innerHTML=e;var c=Od(t),u=c.firstChild;if(r){if(l){var d=(t.styles||_h(c)).filter(function(v){if(!["prepend","prependQueue"].includes(v.getAttribute(dy)))return!1;var h=Number(v.getAttribute(fy)||0);return i>=h});if(d.length)return c.insertBefore(s,d[d.length-1].nextSibling),s}c.insertBefore(s,u)}else c.appendChild(s);return s}function JC(e){var t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},n=Od(t);return(t.styles||_h(n)).find(function(r){return r.getAttribute(QC(t))===e})}function Ss(e){var t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},n=JC(e,t);if(n){var r=Od(t);r.removeChild(n)}}function eI(e,t){var n=_p.get(e);if(!n||!Np(document,n)){var r=ZC("",t),o=r.parentNode;_p.set(e,o),e.removeChild(r)}}function Xo(e,t){var n=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{},r=Od(n),o=_h(r),i=U(U({},n),{},{styles:o});eI(r,i);var a=JC(t,i);if(a){var l,s;if((l=i.csp)!==null&&l!==void 0&&l.nonce&&a.nonce!==((s=i.csp)===null||s===void 0?void 0:s.nonce)){var c;a.nonce=(c=i.csp)===null||c===void 0?void 0:c.nonce}return a.innerHTML!==e&&(a.innerHTML=e),a}var u=ZC(e,i);return u.setAttribute(QC(i),t),u}function ex(e){var t;return e==null||(t=e.getRootNode)===null||t===void 0?void 0:t.call(e)}function tI(e){return ex(e)instanceof ShadowRoot}function Hu(e){return tI(e)?ex(e):null}var Ap={},nI=function(t){};function rI(e,t){}function oI(e,t){}function iI(){Ap={}}function tx(e,t,n){!t&&!Ap[n]&&(e(!1,n),Ap[n]=!0)}function Mn(e,t){tx(rI,e,t)}function nx(e,t){tx(oI,e,t)}Mn.preMessage=nI;Mn.resetWarned=iI;Mn.noteOnce=nx;function aI(e){return e.replace(/-(.)/g,function(t,n){return n.toUpperCase()})}function lI(e,t){Mn(e,"[@ant-design/icons] ".concat(t))}function vy(e){return Qe(e)==="object"&&typeof e.name=="string"&&typeof e.theme=="string"&&(Qe(e.icon)==="object"||typeof e.icon=="function")}function py(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};return Object.keys(e).reduce(function(t,n){var r=e[n];switch(n){case"class":t.className=r,delete t.class;break;default:delete t[n],t[aI(n)]=r}return t},{})}function Dp(e,t,n){return n?lt.createElement(e.tag,U(U({key:t},py(e.attrs)),n),(e.children||[]).map(function(r,o){return Dp(r,"".concat(t,"-").concat(e.tag,"-").concat(o))})):lt.createElement(e.tag,U({key:t},py(e.attrs)),(e.children||[]).map(function(r,o){return Dp(r,"".concat(t,"-").concat(e.tag,"-").concat(o))}))}function rx(e){return Ai(e)[0]}function ox(e){return e?Array.isArray(e)?e:[e]:[]}var sI=` +.anticon { + display: inline-block; + color: inherit; + font-style: normal; + line-height: 0; + text-align: center; + text-transform: none; + vertical-align: -0.125em; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.anticon > * { + line-height: 1; +} + +.anticon svg { + display: inline-block; +} + +.anticon::before { + display: none; +} + +.anticon .anticon-icon { + display: block; +} + +.anticon[tabindex] { + cursor: pointer; +} + +.anticon-spin::before, +.anticon-spin { + display: inline-block; + -webkit-animation: loadingCircle 1s infinite linear; + animation: loadingCircle 1s infinite linear; +} + +@-webkit-keyframes loadingCircle { + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} + +@keyframes loadingCircle { + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} +`,cI=function(t){var n=f.exports.useContext(Th),r=n.csp,o=n.prefixCls,i=sI;o&&(i=i.replace(/anticon/g,o)),f.exports.useEffect(function(){var a=t.current,l=Hu(a);Xo(i,"@ant-design-icons",{prepend:!0,csp:r,attachTo:l})},[])},uI=["icon","className","onClick","style","primaryColor","secondaryColor"],Gl={primaryColor:"#333",secondaryColor:"#E6E6E6",calculated:!1};function dI(e){var t=e.primaryColor,n=e.secondaryColor;Gl.primaryColor=t,Gl.secondaryColor=n||rx(t),Gl.calculated=!!n}function fI(){return U({},Gl)}var Rd=function(t){var n=t.icon,r=t.className,o=t.onClick,i=t.style,a=t.primaryColor,l=t.secondaryColor,s=Je(t,uI),c=f.exports.useRef(),u=Gl;if(a&&(u={primaryColor:a,secondaryColor:l||rx(a)}),cI(c),lI(vy(n),"icon should be icon definiton, but got ".concat(n)),!vy(n))return null;var d=n;return d&&typeof d.icon=="function"&&(d=U(U({},d),{},{icon:d.icon(u.primaryColor,u.secondaryColor)})),Dp(d.icon,"svg-".concat(d.name),U(U({className:r,onClick:o,style:i,"data-icon":d.name,width:"1em",height:"1em",fill:"currentColor","aria-hidden":"true"},s),{},{ref:c}))};Rd.displayName="IconReact";Rd.getTwoToneColors=fI;Rd.setTwoToneColors=dI;const Ah=Rd;function ix(e){var t=ox(e),n=G(t,2),r=n[0],o=n[1];return Ah.setTwoToneColors({primaryColor:r,secondaryColor:o})}function vI(){var e=Ah.getTwoToneColors();return e.calculated?[e.primaryColor,e.secondaryColor]:e.primaryColor}var Id={exports:{}},Pd={};/** + * @license React + * react-jsx-runtime.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var pI=f.exports,gI=Symbol.for("react.element"),hI=Symbol.for("react.fragment"),mI=Object.prototype.hasOwnProperty,yI=pI.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,bI={key:!0,ref:!0,__self:!0,__source:!0};function ax(e,t,n){var r,o={},i=null,a=null;n!==void 0&&(i=""+n),t.key!==void 0&&(i=""+t.key),t.ref!==void 0&&(a=t.ref);for(r in t)mI.call(t,r)&&!bI.hasOwnProperty(r)&&(o[r]=t[r]);if(e&&e.defaultProps)for(r in t=e.defaultProps,t)o[r]===void 0&&(o[r]=t[r]);return{$$typeof:gI,type:e,key:i,ref:a,props:o,_owner:yI.current}}Pd.Fragment=hI;Pd.jsx=ax;Pd.jsxs=ax;(function(e){e.exports=Pd})(Id);const Tt=Id.exports.Fragment,C=Id.exports.jsx,ie=Id.exports.jsxs;var SI=["className","icon","spin","rotate","tabIndex","onClick","twoToneColor"];ix(QR.primary);var Td=f.exports.forwardRef(function(e,t){var n=e.className,r=e.icon,o=e.spin,i=e.rotate,a=e.tabIndex,l=e.onClick,s=e.twoToneColor,c=Je(e,SI),u=f.exports.useContext(Th),d=u.prefixCls,v=d===void 0?"anticon":d,h=u.rootClassName,g=te(h,v,V(V({},"".concat(v,"-").concat(r.name),!!r.name),"".concat(v,"-spin"),!!o||r.name==="loading"),n),p=a;p===void 0&&l&&(p=-1);var b=i?{msTransform:"rotate(".concat(i,"deg)"),transform:"rotate(".concat(i,"deg)")}:void 0,m=ox(s),y=G(m,2),S=y[0],x=y[1];return C("span",{role:"img","aria-label":r.name,...c,ref:t,tabIndex:p,onClick:l,className:g,children:C(Ah,{icon:r,primaryColor:S,secondaryColor:x,style:b})})});Td.displayName="AntdIcon";Td.getTwoToneColor=vI;Td.setTwoToneColor=ix;const Et=Td;var CI={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M464 144H160c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V160c0-8.8-7.2-16-16-16zm-52 268H212V212h200v200zm452-268H560c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V160c0-8.8-7.2-16-16-16zm-52 268H612V212h200v200zM464 544H160c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V560c0-8.8-7.2-16-16-16zm-52 268H212V612h200v200zm452-268H560c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V560c0-8.8-7.2-16-16-16zm-52 268H612V612h200v200z"}}]},name:"appstore",theme:"outlined"};const xI=CI;var wI=function(t,n){return C(Et,{...t,ref:n,icon:xI})};const $I=f.exports.forwardRef(wI);var EI={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M842 454c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 140.3-113.7 254-254 254S258 594.3 258 454c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 168.7 126.6 307.9 290 327.6V884H326.7c-13.7 0-24.7 14.3-24.7 32v36c0 4.4 2.8 8 6.2 8h407.6c3.4 0 6.2-3.6 6.2-8v-36c0-17.7-11-32-24.7-32H548V782.1c165.3-18 294-158 294-328.1zM512 624c93.9 0 170-75.2 170-168V232c0-92.8-76.1-168-170-168s-170 75.2-170 168v224c0 92.8 76.1 168 170 168zm-94-392c0-50.6 41.9-92 94-92s94 41.4 94 92v224c0 50.6-41.9 92-94 92s-94-41.4-94-92V232z"}}]},name:"audio",theme:"outlined"};const MI=EI;var OI=function(t,n){return C(Et,{...t,ref:n,icon:MI})};const RI=f.exports.forwardRef(OI);var II={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm193.5 301.7l-210.6 292a31.8 31.8 0 01-51.7 0L318.5 484.9c-3.8-5.3 0-12.7 6.5-12.7h46.9c10.2 0 19.9 4.9 25.9 13.3l71.2 98.8 157.2-218c6-8.3 15.6-13.3 25.9-13.3H699c6.5 0 10.3 7.4 6.5 12.7z"}}]},name:"check-circle",theme:"filled"};const PI=II;var TI=function(t,n){return C(Et,{...t,ref:n,icon:PI})};const NI=f.exports.forwardRef(TI);var _I={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 00-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z"}}]},name:"check",theme:"outlined"};const AI=_I;var DI=function(t,n){return C(Et,{...t,ref:n,icon:AI})};const lx=f.exports.forwardRef(DI);var LI={icon:{tag:"svg",attrs:{"fill-rule":"evenodd",viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M512 64c247.4 0 448 200.6 448 448S759.4 960 512 960 64 759.4 64 512 264.6 64 512 64zm127.98 274.82h-.04l-.08.06L512 466.75 384.14 338.88c-.04-.05-.06-.06-.08-.06a.12.12 0 00-.07 0c-.03 0-.05.01-.09.05l-45.02 45.02a.2.2 0 00-.05.09.12.12 0 000 .07v.02a.27.27 0 00.06.06L466.75 512 338.88 639.86c-.05.04-.06.06-.06.08a.12.12 0 000 .07c0 .03.01.05.05.09l45.02 45.02a.2.2 0 00.09.05.12.12 0 00.07 0c.02 0 .04-.01.08-.05L512 557.25l127.86 127.87c.04.04.06.05.08.05a.12.12 0 00.07 0c.03 0 .05-.01.09-.05l45.02-45.02a.2.2 0 00.05-.09.12.12 0 000-.07v-.02a.27.27 0 00-.05-.06L557.25 512l127.87-127.86c.04-.04.05-.06.05-.08a.12.12 0 000-.07c0-.03-.01-.05-.05-.09l-45.02-45.02a.2.2 0 00-.09-.05.12.12 0 00-.07 0z"}}]},name:"close-circle",theme:"filled"};const zI=LI;var FI=function(t,n){return C(Et,{...t,ref:n,icon:zI})};const Nd=f.exports.forwardRef(FI);var kI={icon:{tag:"svg",attrs:{"fill-rule":"evenodd",viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M799.86 166.31c.02 0 .04.02.08.06l57.69 57.7c.04.03.05.05.06.08a.12.12 0 010 .06c0 .03-.02.05-.06.09L569.93 512l287.7 287.7c.04.04.05.06.06.09a.12.12 0 010 .07c0 .02-.02.04-.06.08l-57.7 57.69c-.03.04-.05.05-.07.06a.12.12 0 01-.07 0c-.03 0-.05-.02-.09-.06L512 569.93l-287.7 287.7c-.04.04-.06.05-.09.06a.12.12 0 01-.07 0c-.02 0-.04-.02-.08-.06l-57.69-57.7c-.04-.03-.05-.05-.06-.07a.12.12 0 010-.07c0-.03.02-.05.06-.09L454.07 512l-287.7-287.7c-.04-.04-.05-.06-.06-.09a.12.12 0 010-.07c0-.02.02-.04.06-.08l57.7-57.69c.03-.04.05-.05.07-.06a.12.12 0 01.07 0c.03 0 .05.02.09.06L512 454.07l287.7-287.7c.04-.04.06-.05.09-.06a.12.12 0 01.07 0z"}}]},name:"close",theme:"outlined"};const BI=kI;var jI=function(t,n){return C(Et,{...t,ref:n,icon:BI})};const eo=f.exports.forwardRef(jI);var HI={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M888 792H200V168c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v688c0 4.4 3.6 8 8 8h752c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM288 604a64 64 0 10128 0 64 64 0 10-128 0zm118-224a48 48 0 1096 0 48 48 0 10-96 0zm158 228a96 96 0 10192 0 96 96 0 10-192 0zm148-314a56 56 0 10112 0 56 56 0 10-112 0z"}}]},name:"dot-chart",theme:"outlined"};const WI=HI;var VI=function(t,n){return C(Et,{...t,ref:n,icon:WI})};const UI=f.exports.forwardRef(VI);var YI={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"}}]},name:"down",theme:"outlined"};const GI=YI;var KI=function(t,n){return C(Et,{...t,ref:n,icon:GI})};const qI=f.exports.forwardRef(KI);var XI={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M176 511a56 56 0 10112 0 56 56 0 10-112 0zm280 0a56 56 0 10112 0 56 56 0 10-112 0zm280 0a56 56 0 10112 0 56 56 0 10-112 0z"}}]},name:"ellipsis",theme:"outlined"};const QI=XI;var ZI=function(t,n){return C(Et,{...t,ref:n,icon:QI})};const JI=f.exports.forwardRef(ZI);var eP={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M942.2 486.2Q889.47 375.11 816.7 305l-50.88 50.88C807.31 395.53 843.45 447.4 874.7 512 791.5 684.2 673.4 766 512 766q-72.67 0-133.87-22.38L323 798.75Q408 838 512 838q288.3 0 430.2-300.3a60.29 60.29 0 000-51.5zm-63.57-320.64L836 122.88a8 8 0 00-11.32 0L715.31 232.2Q624.86 186 512 186q-288.3 0-430.2 300.3a60.3 60.3 0 000 51.5q56.69 119.4 136.5 191.41L112.48 835a8 8 0 000 11.31L155.17 889a8 8 0 0011.31 0l712.15-712.12a8 8 0 000-11.32zM149.3 512C232.6 339.8 350.7 258 512 258c54.54 0 104.13 9.36 149.12 28.39l-70.3 70.3a176 176 0 00-238.13 238.13l-83.42 83.42C223.1 637.49 183.3 582.28 149.3 512zm246.7 0a112.11 112.11 0 01146.2-106.69L401.31 546.2A112 112 0 01396 512z"}},{tag:"path",attrs:{d:"M508 624c-3.46 0-6.87-.16-10.25-.47l-52.82 52.82a176.09 176.09 0 00227.42-227.42l-52.82 52.82c.31 3.38.47 6.79.47 10.25a111.94 111.94 0 01-112 112z"}}]},name:"eye-invisible",theme:"outlined"};const tP=eP;var nP=function(t,n){return C(Et,{...t,ref:n,icon:tP})};const rP=f.exports.forwardRef(nP);var oP={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M942.2 486.2C847.4 286.5 704.1 186 512 186c-192.2 0-335.4 100.5-430.2 300.3a60.3 60.3 0 000 51.5C176.6 737.5 319.9 838 512 838c192.2 0 335.4-100.5 430.2-300.3 7.7-16.2 7.7-35 0-51.5zM512 766c-161.3 0-279.4-81.8-362.7-254C232.6 339.8 350.7 258 512 258c161.3 0 279.4 81.8 362.7 254C791.5 684.2 673.4 766 512 766zm-4-430c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176zm0 288c-61.9 0-112-50.1-112-112s50.1-112 112-112 112 50.1 112 112-50.1 112-112 112z"}}]},name:"eye",theme:"outlined"};const iP=oP;var aP=function(t,n){return C(Et,{...t,ref:n,icon:iP})};const sx=f.exports.forwardRef(aP);var lP={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M854.6 288.6L639.4 73.4c-6-6-14.1-9.4-22.6-9.4H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V311.3c0-8.5-3.4-16.7-9.4-22.7zM790.2 326H602V137.8L790.2 326zm1.8 562H232V136h302v216a42 42 0 0042 42h216v494z"}}]},name:"file",theme:"outlined"};const sP=lP;var cP=function(t,n){return C(Et,{...t,ref:n,icon:sP})};const cx=f.exports.forwardRef(cP);var uP={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M724 218.3V141c0-6.7-7.7-10.4-12.9-6.3L260.3 486.8a31.86 31.86 0 000 50.3l450.8 352.1c5.3 4.1 12.9.4 12.9-6.3v-77.3c0-4.9-2.3-9.6-6.1-12.6l-360-281 360-281.1c3.8-3 6.1-7.7 6.1-12.6z"}}]},name:"left",theme:"outlined"};const dP=uP;var fP=function(t,n){return C(Et,{...t,ref:n,icon:dP})};const vP=f.exports.forwardRef(fP);var pP={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M574 665.4a8.03 8.03 0 00-11.3 0L446.5 781.6c-53.8 53.8-144.6 59.5-204 0-59.5-59.5-53.8-150.2 0-204l116.2-116.2c3.1-3.1 3.1-8.2 0-11.3l-39.8-39.8a8.03 8.03 0 00-11.3 0L191.4 526.5c-84.6 84.6-84.6 221.5 0 306s221.5 84.6 306 0l116.2-116.2c3.1-3.1 3.1-8.2 0-11.3L574 665.4zm258.6-474c-84.6-84.6-221.5-84.6-306 0L410.3 307.6a8.03 8.03 0 000 11.3l39.7 39.7c3.1 3.1 8.2 3.1 11.3 0l116.2-116.2c53.8-53.8 144.6-59.5 204 0 59.5 59.5 53.8 150.2 0 204L665.3 562.6a8.03 8.03 0 000 11.3l39.8 39.8c3.1 3.1 8.2 3.1 11.3 0l116.2-116.2c84.5-84.6 84.5-221.5 0-306.1zM610.1 372.3a8.03 8.03 0 00-11.3 0L372.3 598.7a8.03 8.03 0 000 11.3l39.6 39.6c3.1 3.1 8.2 3.1 11.3 0l226.4-226.4c3.1-3.1 3.1-8.2 0-11.3l-39.5-39.6z"}}]},name:"link",theme:"outlined"};const gP=pP;var hP=function(t,n){return C(Et,{...t,ref:n,icon:gP})};const mP=f.exports.forwardRef(hP);var yP={icon:{tag:"svg",attrs:{viewBox:"0 0 1024 1024",focusable:"false"},children:[{tag:"path",attrs:{d:"M988 548c-19.9 0-36-16.1-36-36 0-59.4-11.6-117-34.6-171.3a440.45 440.45 0 00-94.3-139.9 437.71 437.71 0 00-139.9-94.3C629 83.6 571.4 72 512 72c-19.9 0-36-16.1-36-36s16.1-36 36-36c69.1 0 136.2 13.5 199.3 40.3C772.3 66 827 103 874 150c47 47 83.9 101.8 109.7 162.7 26.7 63.1 40.2 130.2 40.2 199.3.1 19.9-16 36-35.9 36z"}}]},name:"loading",theme:"outlined"};const bP=yP;var SP=function(t,n){return C(Et,{...t,ref:n,icon:bP})};const ux=f.exports.forwardRef(SP);var CP={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M464 512a48 48 0 1096 0 48 48 0 10-96 0zm200 0a48 48 0 1096 0 48 48 0 10-96 0zm-400 0a48 48 0 1096 0 48 48 0 10-96 0zm661.2-173.6c-22.6-53.7-55-101.9-96.3-143.3a444.35 444.35 0 00-143.3-96.3C630.6 75.7 572.2 64 512 64h-2c-60.6.3-119.3 12.3-174.5 35.9a445.35 445.35 0 00-142 96.5c-40.9 41.3-73 89.3-95.2 142.8-23 55.4-34.6 114.3-34.3 174.9A449.4 449.4 0 00112 714v152a46 46 0 0046 46h152.1A449.4 449.4 0 00510 960h2.1c59.9 0 118-11.6 172.7-34.3a444.48 444.48 0 00142.8-95.2c41.3-40.9 73.8-88.7 96.5-142 23.6-55.2 35.6-113.9 35.9-174.5.3-60.9-11.5-120-34.8-175.6zm-151.1 438C704 845.8 611 884 512 884h-1.7c-60.3-.3-120.2-15.3-173.1-43.5l-8.4-4.5H188V695.2l-4.5-8.4C155.3 633.9 140.3 574 140 513.7c-.4-99.7 37.7-193.3 107.6-263.8 69.8-70.5 163.1-109.5 262.8-109.9h1.7c50 0 98.5 9.7 144.2 28.9 44.6 18.7 84.6 45.6 119 80 34.3 34.3 61.3 74.4 80 119 19.4 46.2 29.1 95.2 28.9 145.8-.6 99.6-39.7 192.9-110.1 262.7z"}}]},name:"message",theme:"outlined"};const xP=CP;var wP=function(t,n){return C(Et,{...t,ref:n,icon:xP})};const $P=f.exports.forwardRef(wP);var EP={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M872 474H152c-4.4 0-8 3.6-8 8v60c0 4.4 3.6 8 8 8h720c4.4 0 8-3.6 8-8v-60c0-4.4-3.6-8-8-8z"}}]},name:"minus",theme:"outlined"};const MP=EP;var OP=function(t,n){return C(Et,{...t,ref:n,icon:MP})};const RP=f.exports.forwardRef(OP);var IP={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M328 544h368c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8H328c-4.4 0-8 3.6-8 8v48c0 4.4 3.6 8 8 8z"}},{tag:"path",attrs:{d:"M880 112H144c-17.7 0-32 14.3-32 32v736c0 17.7 14.3 32 32 32h736c17.7 0 32-14.3 32-32V144c0-17.7-14.3-32-32-32zm-40 728H184V184h656v656z"}}]},name:"minus-square",theme:"outlined"};const PP=IP;var TP=function(t,n){return C(Et,{...t,ref:n,icon:PP})};const NP=f.exports.forwardRef(TP);var _P={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M928 160H96c-17.7 0-32 14.3-32 32v640c0 17.7 14.3 32 32 32h832c17.7 0 32-14.3 32-32V192c0-17.7-14.3-32-32-32zm-40 632H136v-39.9l138.5-164.3 150.1 178L658.1 489 888 761.6V792zm0-129.8L664.2 396.8c-3.2-3.8-9-3.8-12.2 0L424.6 666.4l-144-170.7c-3.2-3.8-9-3.8-12.2 0L136 652.7V232h752v430.2zM304 456a88 88 0 100-176 88 88 0 000 176zm0-116c15.5 0 28 12.5 28 28s-12.5 28-28 28-28-12.5-28-28 12.5-28 28-28z"}}]},name:"picture",theme:"outlined"};const AP=_P;var DP=function(t,n){return C(Et,{...t,ref:n,icon:AP})};const LP=f.exports.forwardRef(DP);var zP={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M482 152h60q8 0 8 8v704q0 8-8 8h-60q-8 0-8-8V160q0-8 8-8z"}},{tag:"path",attrs:{d:"M192 474h672q8 0 8 8v60q0 8-8 8H160q-8 0-8-8v-60q0-8 8-8z"}}]},name:"plus",theme:"outlined"};const FP=zP;var kP=function(t,n){return C(Et,{...t,ref:n,icon:FP})};const BP=f.exports.forwardRef(kP);var jP={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M328 544h152v152c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8V544h152c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8H544V328c0-4.4-3.6-8-8-8h-48c-4.4 0-8 3.6-8 8v152H328c-4.4 0-8 3.6-8 8v48c0 4.4 3.6 8 8 8z"}},{tag:"path",attrs:{d:"M880 112H144c-17.7 0-32 14.3-32 32v736c0 17.7 14.3 32 32 32h736c17.7 0 32-14.3 32-32V144c0-17.7-14.3-32-32-32zm-40 728H184V184h656v656z"}}]},name:"plus-square",theme:"outlined"};const HP=jP;var WP=function(t,n){return C(Et,{...t,ref:n,icon:HP})};const VP=f.exports.forwardRef(WP);var UP={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M765.7 486.8L314.9 134.7A7.97 7.97 0 00302 141v77.3c0 4.9 2.3 9.6 6.1 12.6l360 281.1-360 281.1c-3.9 3-6.1 7.7-6.1 12.6V883c0 6.7 7.7 10.4 12.9 6.3l450.8-352.1a31.96 31.96 0 000-50.4z"}}]},name:"right",theme:"outlined"};const YP=UP;var GP=function(t,n){return C(Et,{...t,ref:n,icon:YP})};const KP=f.exports.forwardRef(GP);var qP={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"defs",attrs:{},children:[{tag:"style",attrs:{}}]},{tag:"path",attrs:{d:"M672 418H144c-17.7 0-32 14.3-32 32v414c0 17.7 14.3 32 32 32h528c17.7 0 32-14.3 32-32V450c0-17.7-14.3-32-32-32zm-44 402H188V494h440v326z"}},{tag:"path",attrs:{d:"M819.3 328.5c-78.8-100.7-196-153.6-314.6-154.2l-.2-64c0-6.5-7.6-10.1-12.6-6.1l-128 101c-4 3.1-3.9 9.1 0 12.3L492 318.6c5.1 4 12.7.4 12.6-6.1v-63.9c12.9.1 25.9.9 38.8 2.5 42.1 5.2 82.1 18.2 119 38.7 38.1 21.2 71.2 49.7 98.4 84.3 27.1 34.7 46.7 73.7 58.1 115.8a325.95 325.95 0 016.5 140.9h74.9c14.8-103.6-11.3-213-81-302.3z"}}]},name:"rotate-left",theme:"outlined"};const XP=qP;var QP=function(t,n){return C(Et,{...t,ref:n,icon:XP})};const ZP=f.exports.forwardRef(QP);var JP={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"defs",attrs:{},children:[{tag:"style",attrs:{}}]},{tag:"path",attrs:{d:"M480.5 251.2c13-1.6 25.9-2.4 38.8-2.5v63.9c0 6.5 7.5 10.1 12.6 6.1L660 217.6c4-3.2 4-9.2 0-12.3l-128-101c-5.1-4-12.6-.4-12.6 6.1l-.2 64c-118.6.5-235.8 53.4-314.6 154.2A399.75 399.75 0 00123.5 631h74.9c-.9-5.3-1.7-10.7-2.4-16.1-5.1-42.1-2.1-84.1 8.9-124.8 11.4-42.2 31-81.1 58.1-115.8 27.2-34.7 60.3-63.2 98.4-84.3 37-20.6 76.9-33.6 119.1-38.8z"}},{tag:"path",attrs:{d:"M880 418H352c-17.7 0-32 14.3-32 32v414c0 17.7 14.3 32 32 32h528c17.7 0 32-14.3 32-32V450c0-17.7-14.3-32-32-32zm-44 402H396V494h440v326z"}}]},name:"rotate-right",theme:"outlined"};const e4=JP;var t4=function(t,n){return C(Et,{...t,ref:n,icon:e4})};const n4=f.exports.forwardRef(t4);var r4={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"}}]},name:"search",theme:"outlined"};const o4=r4;var i4=function(t,n){return C(Et,{...t,ref:n,icon:o4})};const _d=f.exports.forwardRef(i4);var a4={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M924.8 625.7l-65.5-56c3.1-19 4.7-38.4 4.7-57.8s-1.6-38.8-4.7-57.8l65.5-56a32.03 32.03 0 009.3-35.2l-.9-2.6a443.74 443.74 0 00-79.7-137.9l-1.8-2.1a32.12 32.12 0 00-35.1-9.5l-81.3 28.9c-30-24.6-63.5-44-99.7-57.6l-15.7-85a32.05 32.05 0 00-25.8-25.7l-2.7-.5c-52.1-9.4-106.9-9.4-159 0l-2.7.5a32.05 32.05 0 00-25.8 25.7l-15.8 85.4a351.86 351.86 0 00-99 57.4l-81.9-29.1a32 32 0 00-35.1 9.5l-1.8 2.1a446.02 446.02 0 00-79.7 137.9l-.9 2.6c-4.5 12.5-.8 26.5 9.3 35.2l66.3 56.6c-3.1 18.8-4.6 38-4.6 57.1 0 19.2 1.5 38.4 4.6 57.1L99 625.5a32.03 32.03 0 00-9.3 35.2l.9 2.6c18.1 50.4 44.9 96.9 79.7 137.9l1.8 2.1a32.12 32.12 0 0035.1 9.5l81.9-29.1c29.8 24.5 63.1 43.9 99 57.4l15.8 85.4a32.05 32.05 0 0025.8 25.7l2.7.5a449.4 449.4 0 00159 0l2.7-.5a32.05 32.05 0 0025.8-25.7l15.7-85a350 350 0 0099.7-57.6l81.3 28.9a32 32 0 0035.1-9.5l1.8-2.1c34.8-41.1 61.6-87.5 79.7-137.9l.9-2.6c4.5-12.3.8-26.3-9.3-35zM788.3 465.9c2.5 15.1 3.8 30.6 3.8 46.1s-1.3 31-3.8 46.1l-6.6 40.1 74.7 63.9a370.03 370.03 0 01-42.6 73.6L721 702.8l-31.4 25.8c-23.9 19.6-50.5 35-79.3 45.8l-38.1 14.3-17.9 97a377.5 377.5 0 01-85 0l-17.9-97.2-37.8-14.5c-28.5-10.8-55-26.2-78.7-45.7l-31.4-25.9-93.4 33.2c-17-22.9-31.2-47.6-42.6-73.6l75.5-64.5-6.5-40c-2.4-14.9-3.7-30.3-3.7-45.5 0-15.3 1.2-30.6 3.7-45.5l6.5-40-75.5-64.5c11.3-26.1 25.6-50.7 42.6-73.6l93.4 33.2 31.4-25.9c23.7-19.5 50.2-34.9 78.7-45.7l37.9-14.3 17.9-97.2c28.1-3.2 56.8-3.2 85 0l17.9 97 38.1 14.3c28.7 10.8 55.4 26.2 79.3 45.8l31.4 25.8 92.8-32.9c17 22.9 31.2 47.6 42.6 73.6L781.8 426l6.5 39.9zM512 326c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176zm79.2 255.2A111.6 111.6 0 01512 614c-29.9 0-58-11.7-79.2-32.8A111.6 111.6 0 01400 502c0-29.9 11.7-58 32.8-79.2C454 401.6 482.1 390 512 390c29.9 0 58 11.6 79.2 32.8A111.6 111.6 0 01624 502c0 29.9-11.7 58-32.8 79.2z"}}]},name:"setting",theme:"outlined"};const l4=a4;var s4=function(t,n){return C(Et,{...t,ref:n,icon:l4})};const c4=f.exports.forwardRef(s4);var u4={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M288 421a48 48 0 1096 0 48 48 0 10-96 0zm352 0a48 48 0 1096 0 48 48 0 10-96 0zM512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm263 711c-34.2 34.2-74 61-118.3 79.8C611 874.2 562.3 884 512 884c-50.3 0-99-9.8-144.8-29.2A370.4 370.4 0 01248.9 775c-34.2-34.2-61-74-79.8-118.3C149.8 611 140 562.3 140 512s9.8-99 29.2-144.8A370.4 370.4 0 01249 248.9c34.2-34.2 74-61 118.3-79.8C413 149.8 461.7 140 512 140c50.3 0 99 9.8 144.8 29.2A370.4 370.4 0 01775.1 249c34.2 34.2 61 74 79.8 118.3C874.2 413 884 461.7 884 512s-9.8 99-29.2 144.8A368.89 368.89 0 01775 775zM664 533h-48.1c-4.2 0-7.8 3.2-8.1 7.4C604 589.9 562.5 629 512 629s-92.1-39.1-95.8-88.6c-.3-4.2-3.9-7.4-8.1-7.4H360a8 8 0 00-8 8.4c4.4 84.3 74.5 151.6 160 151.6s155.6-67.3 160-151.6a8 8 0 00-8-8.4z"}}]},name:"smile",theme:"outlined"};const d4=u4;var f4=function(t,n){return C(Et,{...t,ref:n,icon:d4})};const v4=f.exports.forwardRef(f4);var p4={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M847.9 592H152c-4.4 0-8 3.6-8 8v60c0 4.4 3.6 8 8 8h605.2L612.9 851c-4.1 5.2-.4 13 6.3 13h72.5c4.9 0 9.5-2.2 12.6-6.1l168.8-214.1c16.5-21 1.6-51.8-25.2-51.8zM872 356H266.8l144.3-183c4.1-5.2.4-13-6.3-13h-72.5c-4.9 0-9.5 2.2-12.6 6.1L150.9 380.2c-16.5 21-1.6 51.8 25.1 51.8h696c4.4 0 8-3.6 8-8v-60c0-4.4-3.6-8-8-8z"}}]},name:"swap",theme:"outlined"};const g4=p4;var h4=function(t,n){return C(Et,{...t,ref:n,icon:g4})};const gy=f.exports.forwardRef(h4);var m4={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M912 302.3L784 376V224c0-35.3-28.7-64-64-64H128c-35.3 0-64 28.7-64 64v576c0 35.3 28.7 64 64 64h592c35.3 0 64-28.7 64-64V648l128 73.7c21.3 12.3 48-3.1 48-27.6V330c0-24.6-26.7-40-48-27.7zM712 792H136V232h576v560zm176-167l-104-59.8V458.9L888 399v226zM208 360h112c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8H208c-4.4 0-8 3.6-8 8v48c0 4.4 3.6 8 8 8z"}}]},name:"video-camera",theme:"outlined"};const y4=m4;var b4=function(t,n){return C(Et,{...t,ref:n,icon:y4})};const S4=f.exports.forwardRef(b4);var C4={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M690.1 377.4c5.9 0 11.8.2 17.6.5-24.4-128.7-158.3-227.1-319.9-227.1C209 150.8 64 271.4 64 420.2c0 81.1 43.6 154.2 111.9 203.6a21.5 21.5 0 019.1 17.6c0 2.4-.5 4.6-1.1 6.9-5.5 20.3-14.2 52.8-14.6 54.3-.7 2.6-1.7 5.2-1.7 7.9 0 5.9 4.8 10.8 10.8 10.8 2.3 0 4.2-.9 6.2-2l70.9-40.9c5.3-3.1 11-5 17.2-5 3.2 0 6.4.5 9.5 1.4 33.1 9.5 68.8 14.8 105.7 14.8 6 0 11.9-.1 17.8-.4-7.1-21-10.9-43.1-10.9-66 0-135.8 132.2-245.8 295.3-245.8zm-194.3-86.5c23.8 0 43.2 19.3 43.2 43.1s-19.3 43.1-43.2 43.1c-23.8 0-43.2-19.3-43.2-43.1s19.4-43.1 43.2-43.1zm-215.9 86.2c-23.8 0-43.2-19.3-43.2-43.1s19.3-43.1 43.2-43.1 43.2 19.3 43.2 43.1-19.4 43.1-43.2 43.1zm586.8 415.6c56.9-41.2 93.2-102 93.2-169.7 0-124-120.8-224.5-269.9-224.5-149 0-269.9 100.5-269.9 224.5S540.9 847.5 690 847.5c30.8 0 60.6-4.4 88.1-12.3 2.6-.8 5.2-1.2 7.9-1.2 5.2 0 9.9 1.6 14.3 4.1l59.1 34c1.7 1 3.3 1.7 5.2 1.7a9 9 0 006.4-2.6 9 9 0 002.6-6.4c0-2.2-.9-4.4-1.4-6.6-.3-1.2-7.6-28.3-12.2-45.3-.5-1.9-.9-3.8-.9-5.7.1-5.9 3.1-11.2 7.6-14.5zM600.2 587.2c-19.9 0-36-16.1-36-35.9 0-19.8 16.1-35.9 36-35.9s36 16.1 36 35.9c0 19.8-16.2 35.9-36 35.9zm179.9 0c-19.9 0-36-16.1-36-35.9 0-19.8 16.1-35.9 36-35.9s36 16.1 36 35.9a36.08 36.08 0 01-36 35.9z"}}]},name:"wechat",theme:"outlined"};const x4=C4;var w4=function(t,n){return C(Et,{...t,ref:n,icon:x4})};const $4=f.exports.forwardRef(w4);var E4={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M637 443H519V309c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v134H325c-4.4 0-8 3.6-8 8v60c0 4.4 3.6 8 8 8h118v134c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V519h118c4.4 0 8-3.6 8-8v-60c0-4.4-3.6-8-8-8zm284 424L775 721c122.1-148.9 113.6-369.5-26-509-148-148.1-388.4-148.1-537 0-148.1 148.6-148.1 389 0 537 139.5 139.6 360.1 148.1 509 26l146 146c3.2 2.8 8.3 2.8 11 0l43-43c2.8-2.7 2.8-7.8 0-11zM696 696c-118.8 118.7-311.2 118.7-430 0-118.7-118.8-118.7-311.2 0-430 118.8-118.7 311.2-118.7 430 0 118.7 118.8 118.7 311.2 0 430z"}}]},name:"zoom-in",theme:"outlined"};const M4=E4;var O4=function(t,n){return C(Et,{...t,ref:n,icon:M4})};const R4=f.exports.forwardRef(O4);var I4={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M637 443H325c-4.4 0-8 3.6-8 8v60c0 4.4 3.6 8 8 8h312c4.4 0 8-3.6 8-8v-60c0-4.4-3.6-8-8-8zm284 424L775 721c122.1-148.9 113.6-369.5-26-509-148-148.1-388.4-148.1-537 0-148.1 148.6-148.1 389 0 537 139.5 139.6 360.1 148.1 509 26l146 146c3.2 2.8 8.3 2.8 11 0l43-43c2.8-2.7 2.8-7.8 0-11zM696 696c-118.8 118.7-311.2 118.7-430 0-118.7-118.8-118.7-311.2 0-430 118.8-118.7 311.2-118.7 430 0 118.7 118.8 118.7 311.2 0 430z"}}]},name:"zoom-out",theme:"outlined"};const P4=I4;var T4=function(t,n){return C(Et,{...t,ref:n,icon:P4})};const N4=f.exports.forwardRef(T4);var Kl={exports:{}},Rt={};/** + * @license React + * react-is.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var Dh=Symbol.for("react.element"),Lh=Symbol.for("react.portal"),Ad=Symbol.for("react.fragment"),Dd=Symbol.for("react.strict_mode"),Ld=Symbol.for("react.profiler"),zd=Symbol.for("react.provider"),Fd=Symbol.for("react.context"),_4=Symbol.for("react.server_context"),kd=Symbol.for("react.forward_ref"),Bd=Symbol.for("react.suspense"),jd=Symbol.for("react.suspense_list"),Hd=Symbol.for("react.memo"),Wd=Symbol.for("react.lazy"),A4=Symbol.for("react.offscreen"),dx;dx=Symbol.for("react.module.reference");function Cr(e){if(typeof e=="object"&&e!==null){var t=e.$$typeof;switch(t){case Dh:switch(e=e.type,e){case Ad:case Ld:case Dd:case Bd:case jd:return e;default:switch(e=e&&e.$$typeof,e){case _4:case Fd:case kd:case Wd:case Hd:case zd:return e;default:return t}}case Lh:return t}}}Rt.ContextConsumer=Fd;Rt.ContextProvider=zd;Rt.Element=Dh;Rt.ForwardRef=kd;Rt.Fragment=Ad;Rt.Lazy=Wd;Rt.Memo=Hd;Rt.Portal=Lh;Rt.Profiler=Ld;Rt.StrictMode=Dd;Rt.Suspense=Bd;Rt.SuspenseList=jd;Rt.isAsyncMode=function(){return!1};Rt.isConcurrentMode=function(){return!1};Rt.isContextConsumer=function(e){return Cr(e)===Fd};Rt.isContextProvider=function(e){return Cr(e)===zd};Rt.isElement=function(e){return typeof e=="object"&&e!==null&&e.$$typeof===Dh};Rt.isForwardRef=function(e){return Cr(e)===kd};Rt.isFragment=function(e){return Cr(e)===Ad};Rt.isLazy=function(e){return Cr(e)===Wd};Rt.isMemo=function(e){return Cr(e)===Hd};Rt.isPortal=function(e){return Cr(e)===Lh};Rt.isProfiler=function(e){return Cr(e)===Ld};Rt.isStrictMode=function(e){return Cr(e)===Dd};Rt.isSuspense=function(e){return Cr(e)===Bd};Rt.isSuspenseList=function(e){return Cr(e)===jd};Rt.isValidElementType=function(e){return typeof e=="string"||typeof e=="function"||e===Ad||e===Ld||e===Dd||e===Bd||e===jd||e===A4||typeof e=="object"&&e!==null&&(e.$$typeof===Wd||e.$$typeof===Hd||e.$$typeof===zd||e.$$typeof===Fd||e.$$typeof===kd||e.$$typeof===dx||e.getModuleId!==void 0)};Rt.typeOf=Cr;(function(e){e.exports=Rt})(Kl);function Hs(e,t,n){var r=f.exports.useRef({});return(!("value"in r.current)||n(r.current.condition,t))&&(r.current.value=e(),r.current.condition=t),r.current.value}function zh(e,t){typeof e=="function"?e(t):Qe(e)==="object"&&e&&"current"in e&&(e.current=t)}function xr(){for(var e=arguments.length,t=new Array(e),n=0;n1&&arguments[1]!==void 0?arguments[1]:{},n=[];return lt.Children.forEach(e,function(r){r==null&&!t.keepEmpty||(Array.isArray(r)?n=n.concat(Qo(r)):Kl.exports.isFragment(r)&&r.props?n=n.concat(Qo(r.props.children,t)):n.push(r))}),n}function Wu(e){return e instanceof HTMLElement||e instanceof SVGElement}function ql(e){return Wu(e)?e:e instanceof lt.Component?zu.findDOMNode(e):null}var Lp=f.exports.createContext(null);function D4(e){var t=e.children,n=e.onBatchResize,r=f.exports.useRef(0),o=f.exports.useRef([]),i=f.exports.useContext(Lp),a=f.exports.useCallback(function(l,s,c){r.current+=1;var u=r.current;o.current.push({size:l,element:s,data:c}),Promise.resolve().then(function(){u===r.current&&(n==null||n(o.current),o.current=[])}),i==null||i(l,s,c)},[n,i]);return C(Lp.Provider,{value:a,children:t})}var fx=function(){if(typeof Map<"u")return Map;function e(t,n){var r=-1;return t.some(function(o,i){return o[0]===n?(r=i,!0):!1}),r}return function(){function t(){this.__entries__=[]}return Object.defineProperty(t.prototype,"size",{get:function(){return this.__entries__.length},enumerable:!0,configurable:!0}),t.prototype.get=function(n){var r=e(this.__entries__,n),o=this.__entries__[r];return o&&o[1]},t.prototype.set=function(n,r){var o=e(this.__entries__,n);~o?this.__entries__[o][1]=r:this.__entries__.push([n,r])},t.prototype.delete=function(n){var r=this.__entries__,o=e(r,n);~o&&r.splice(o,1)},t.prototype.has=function(n){return!!~e(this.__entries__,n)},t.prototype.clear=function(){this.__entries__.splice(0)},t.prototype.forEach=function(n,r){r===void 0&&(r=null);for(var o=0,i=this.__entries__;o0},e.prototype.connect_=function(){!zp||this.connected_||(document.addEventListener("transitionend",this.onTransitionEnd_),window.addEventListener("resize",this.refresh),j4?(this.mutationsObserver_=new MutationObserver(this.refresh),this.mutationsObserver_.observe(document,{attributes:!0,childList:!0,characterData:!0,subtree:!0})):(document.addEventListener("DOMSubtreeModified",this.refresh),this.mutationEventsAdded_=!0),this.connected_=!0)},e.prototype.disconnect_=function(){!zp||!this.connected_||(document.removeEventListener("transitionend",this.onTransitionEnd_),window.removeEventListener("resize",this.refresh),this.mutationsObserver_&&this.mutationsObserver_.disconnect(),this.mutationEventsAdded_&&document.removeEventListener("DOMSubtreeModified",this.refresh),this.mutationsObserver_=null,this.mutationEventsAdded_=!1,this.connected_=!1)},e.prototype.onTransitionEnd_=function(t){var n=t.propertyName,r=n===void 0?"":n,o=B4.some(function(i){return!!~r.indexOf(i)});o&&this.refresh()},e.getInstance=function(){return this.instance_||(this.instance_=new e),this.instance_},e.instance_=null,e}(),vx=function(e,t){for(var n=0,r=Object.keys(t);n"u"||!(Element instanceof Object))){if(!(t instanceof Ua(t).Element))throw new TypeError('parameter 1 is not of type "Element".');var n=this.observations_;n.has(t)||(n.set(t,new X4(t)),this.controller_.addObserver(this),this.controller_.refresh())}},e.prototype.unobserve=function(t){if(!arguments.length)throw new TypeError("1 argument required, but only 0 present.");if(!(typeof Element>"u"||!(Element instanceof Object))){if(!(t instanceof Ua(t).Element))throw new TypeError('parameter 1 is not of type "Element".');var n=this.observations_;!n.has(t)||(n.delete(t),n.size||this.controller_.removeObserver(this))}},e.prototype.disconnect=function(){this.clearActive(),this.observations_.clear(),this.controller_.removeObserver(this)},e.prototype.gatherActive=function(){var t=this;this.clearActive(),this.observations_.forEach(function(n){n.isActive()&&t.activeObservations_.push(n)})},e.prototype.broadcastActive=function(){if(!!this.hasActive()){var t=this.callbackCtx_,n=this.activeObservations_.map(function(r){return new Q4(r.target,r.broadcastRect())});this.callback_.call(t,n,t),this.clearActive()}},e.prototype.clearActive=function(){this.activeObservations_.splice(0)},e.prototype.hasActive=function(){return this.activeObservations_.length>0},e}(),gx=typeof WeakMap<"u"?new WeakMap:new fx,hx=function(){function e(t){if(!(this instanceof e))throw new TypeError("Cannot call a class as a function.");if(!arguments.length)throw new TypeError("1 argument required, but only 0 present.");var n=H4.getInstance(),r=new Z4(t,n,this);gx.set(this,r)}return e}();["observe","unobserve","disconnect"].forEach(function(e){hx.prototype[e]=function(){var t;return(t=gx.get(this))[e].apply(t,arguments)}});var J4=function(){return typeof Vu.ResizeObserver<"u"?Vu.ResizeObserver:hx}(),Lo=new Map;function eT(e){e.forEach(function(t){var n,r=t.target;(n=Lo.get(r))===null||n===void 0||n.forEach(function(o){return o(r)})})}var mx=new J4(eT);function tT(e,t){Lo.has(e)||(Lo.set(e,new Set),mx.observe(e)),Lo.get(e).add(t)}function nT(e,t){Lo.has(e)&&(Lo.get(e).delete(t),Lo.get(e).size||(mx.unobserve(e),Lo.delete(e)))}function zn(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function my(e,t){for(var n=0;n1&&arguments[1]!==void 0?arguments[1]:1;yy+=1;var r=yy;function o(i){if(i===0)Cx(r),t();else{var a=bx(function(){o(i-1)});kh.set(r,a)}}return o(n),r};St.cancel=function(e){var t=kh.get(e);return Cx(e),Sx(t)};function Yu(e){for(var t=0,n,r=0,o=e.length;o>=4;++r,o-=4)n=e.charCodeAt(r)&255|(e.charCodeAt(++r)&255)<<8|(e.charCodeAt(++r)&255)<<16|(e.charCodeAt(++r)&255)<<24,n=(n&65535)*1540483477+((n>>>16)*59797<<16),n^=n>>>24,t=(n&65535)*1540483477+((n>>>16)*59797<<16)^(t&65535)*1540483477+((t>>>16)*59797<<16);switch(o){case 3:t^=(e.charCodeAt(r+2)&255)<<16;case 2:t^=(e.charCodeAt(r+1)&255)<<8;case 1:t^=e.charCodeAt(r)&255,t=(t&65535)*1540483477+((t>>>16)*59797<<16)}return t^=t>>>13,t=(t&65535)*1540483477+((t>>>16)*59797<<16),((t^t>>>15)>>>0).toString(36)}function Vs(e,t){var n=arguments.length>2&&arguments[2]!==void 0?arguments[2]:!1,r=new Set;function o(i,a){var l=arguments.length>2&&arguments[2]!==void 0?arguments[2]:1,s=r.has(i);if(Mn(!s,"Warning: There may be circular references"),s)return!1;if(i===a)return!0;if(n&&l>1)return!1;r.add(i);var c=l+1;if(Array.isArray(i)){if(!Array.isArray(a)||i.length!==a.length)return!1;for(var u=0;u1&&arguments[1]!==void 0?arguments[1]:!1,a={map:this.cache};return n.forEach(function(l){if(!a)a=void 0;else{var s;a=(s=a)===null||s===void 0||(s=s.map)===null||s===void 0?void 0:s.get(l)}}),(r=a)!==null&&r!==void 0&&r.value&&i&&(a.value[1]=this.cacheCallTimes++),(o=a)===null||o===void 0?void 0:o.value}},{key:"get",value:function(n){var r;return(r=this.internalGet(n,!0))===null||r===void 0?void 0:r[0]}},{key:"has",value:function(n){return!!this.internalGet(n)}},{key:"set",value:function(n,r){var o=this;if(!this.has(n)){if(this.size()+1>e.MAX_CACHE_SIZE+e.MAX_CACHE_OFFSET){var i=this.keys.reduce(function(c,u){var d=G(c,2),v=d[1];return o.internalGet(u)[1]0,void 0),by+=1}return Fn(e,[{key:"getDerivativeToken",value:function(n){return this.derivatives.reduce(function(r,o){return o(n,r)},void 0)}}]),e}(),Jf=new Bh;function Bp(e){var t=Array.isArray(e)?e:[e];return Jf.has(t)||Jf.set(t,new xx(t)),Jf.get(t)}var pT=new WeakMap,ev={};function gT(e,t){for(var n=pT,r=0;r3&&arguments[3]!==void 0?arguments[3]:{},i=arguments.length>4&&arguments[4]!==void 0?arguments[4]:!1;if(i)return e;var a=U(U({},o),{},(r={},V(r,Ya,t),V(r,zr,n),r)),l=Object.keys(a).map(function(s){var c=a[s];return c?"".concat(s,'="').concat(c,'"'):null}).filter(function(s){return s}).join(" ");return"")}var $x=function(t){var n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:"";return"--".concat(n?"".concat(n,"-"):"").concat(t).replace(/([a-z0-9])([A-Z])/g,"$1-$2").replace(/([A-Z]+)([A-Z][a-z0-9]+)/g,"$1-$2").replace(/([a-z])([A-Z0-9])/g,"$1-$2").toLowerCase()},yT=function(t,n,r){return Object.keys(t).length?".".concat(n).concat(r!=null&&r.scope?".".concat(r.scope):"","{").concat(Object.entries(t).map(function(o){var i=G(o,2),a=i[0],l=i[1];return"".concat(a,":").concat(l,";")}).join(""),"}"):""},Ex=function(t,n,r){var o={},i={};return Object.entries(t).forEach(function(a){var l,s,c=G(a,2),u=c[0],d=c[1];if(r!=null&&(l=r.preserve)!==null&&l!==void 0&&l[u])i[u]=d;else if((typeof d=="string"||typeof d=="number")&&!(r!=null&&(s=r.ignore)!==null&&s!==void 0&&s[u])){var v,h=$x(u,r==null?void 0:r.prefix);o[h]=typeof d=="number"&&!(r!=null&&(v=r.unitless)!==null&&v!==void 0&&v[u])?"".concat(d,"px"):String(d),i[u]="var(".concat(h,")")}}),[i,yT(o,n,{scope:r==null?void 0:r.scope})]},xy=Rn()?f.exports.useLayoutEffect:f.exports.useEffect,Nt=function(t,n){var r=f.exports.useRef(!0);xy(function(){return t(r.current)},n),xy(function(){return r.current=!1,function(){r.current=!0}},[])},Hp=function(t,n){Nt(function(r){if(!r)return t()},n)},bT=U({},As),wy=bT.useInsertionEffect,ST=function(t,n,r){f.exports.useMemo(t,r),Nt(function(){return n(!0)},r)},CT=wy?function(e,t,n){return wy(function(){return e(),t()},n)}:ST,xT=U({},As),wT=xT.useInsertionEffect,$T=function(t){var n=[],r=!1;function o(i){r||n.push(i)}return f.exports.useEffect(function(){return r=!1,function(){r=!0,n.length&&n.forEach(function(i){return i()})}},t),o},ET=function(){return function(t){t()}},MT=typeof wT<"u"?$T:ET;function jh(e,t,n,r,o){var i=f.exports.useContext(Yd),a=i.cache,l=[e].concat(Oe(t)),s=kp(l),c=MT([s]),u=function(g){a.opUpdate(s,function(p){var b=p||[void 0,void 0],m=G(b,2),y=m[0],S=y===void 0?0:y,x=m[1],$=x,E=$||n(),w=[S,E];return g?g(w):w})};f.exports.useMemo(function(){u()},[s]);var d=a.opGet(s),v=d[1];return CT(function(){o==null||o(v)},function(h){return u(function(g){var p=G(g,2),b=p[0],m=p[1];return h&&b===0&&(o==null||o(v)),[b+1,m]}),function(){a.opUpdate(s,function(g){var p=g||[],b=G(p,2),m=b[0],y=m===void 0?0:m,S=b[1],x=y-1;return x===0?(c(function(){(h||!a.opGet(s))&&(r==null||r(S,!1))}),null):[y-1,S]})}},[s]),v}var OT={},RT="css",gi=new Map;function IT(e){gi.set(e,(gi.get(e)||0)+1)}function PT(e,t){if(typeof document<"u"){var n=document.querySelectorAll("style[".concat(Ya,'="').concat(e,'"]'));n.forEach(function(r){if(r[zo]===t){var o;(o=r.parentNode)===null||o===void 0||o.removeChild(r)}})}}var TT=0;function NT(e,t){gi.set(e,(gi.get(e)||0)-1);var n=Array.from(gi.keys()),r=n.filter(function(o){var i=gi.get(o)||0;return i<=0});n.length-r.length>TT&&r.forEach(function(o){PT(o,t),gi.delete(o)})}var _T=function(t,n,r,o){var i=r.getDerivativeToken(t),a=U(U({},i),n);return o&&(a=o(a)),a},Mx="token";function AT(e,t){var n=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{},r=f.exports.useContext(Yd),o=r.cache.instanceId,i=r.container,a=n.salt,l=a===void 0?"":a,s=n.override,c=s===void 0?OT:s,u=n.formatToken,d=n.getComputedToken,v=n.cssVar,h=gT(function(){return Object.assign.apply(Object,[{}].concat(Oe(t)))},t),g=Xl(h),p=Xl(c),b=v?Xl(v):"",m=jh(Mx,[l,e.id,g,p,b],function(){var y,S=d?d(h,c,e):_T(h,c,e,u),x=U({},S),$="";if(v){var E=Ex(S,v.key,{prefix:v.prefix,ignore:v.ignore,unitless:v.unitless,preserve:v.preserve}),w=G(E,2);S=w[0],$=w[1]}var R=Cy(S,l);S._tokenKey=R,x._tokenKey=Cy(x,l);var P=(y=v==null?void 0:v.key)!==null&&y!==void 0?y:R;S._themeKey=P,IT(P);var N="".concat(RT,"-").concat(Yu(R));return S._hashId=N,[S,N,x,$,(v==null?void 0:v.key)||""]},function(y){NT(y[0]._themeKey,o)},function(y){var S=G(y,4),x=S[0],$=S[3];if(v&&$){var E=Xo($,Yu("css-variables-".concat(x._themeKey)),{mark:zr,prepend:"queue",attachTo:i,priority:-999});E[zo]=o,E.setAttribute(Ya,x._themeKey)}});return m}var DT=function(t,n,r){var o=G(t,5),i=o[2],a=o[3],l=o[4],s=r||{},c=s.plain;if(!a)return null;var u=i._tokenKey,d=-999,v={"data-rc-order":"prependQueue","data-rc-priority":"".concat(d)},h=Gu(a,l,u,v,c);return[d,u,h]},LT={animationIterationCount:1,borderImageOutset:1,borderImageSlice:1,borderImageWidth:1,boxFlex:1,boxFlexGroup:1,boxOrdinalGroup:1,columnCount:1,columns:1,flex:1,flexGrow:1,flexPositive:1,flexShrink:1,flexNegative:1,flexOrder:1,gridRow:1,gridRowEnd:1,gridRowSpan:1,gridRowStart:1,gridColumn:1,gridColumnEnd:1,gridColumnSpan:1,gridColumnStart:1,msGridRow:1,msGridRowSpan:1,msGridColumn:1,msGridColumnSpan:1,fontWeight:1,lineHeight:1,opacity:1,order:1,orphans:1,tabSize:1,widows:1,zIndex:1,zoom:1,WebkitLineClamp:1,fillOpacity:1,floodOpacity:1,stopOpacity:1,strokeDasharray:1,strokeDashoffset:1,strokeMiterlimit:1,strokeOpacity:1,strokeWidth:1},Ox="comm",Rx="rule",Ix="decl",zT="@import",FT="@keyframes",kT="@layer",Px=Math.abs,Hh=String.fromCharCode;function Tx(e){return e.trim()}function eu(e,t,n){return e.replace(t,n)}function BT(e,t,n){return e.indexOf(t,n)}function Cs(e,t){return e.charCodeAt(t)|0}function xs(e,t,n){return e.slice(t,n)}function so(e){return e.length}function jT(e){return e.length}function Mc(e,t){return t.push(e),e}var Gd=1,Ga=1,Nx=0,Sr=0,en=0,nl="";function Wh(e,t,n,r,o,i,a,l){return{value:e,root:t,parent:n,type:r,props:o,children:i,line:Gd,column:Ga,length:a,return:"",siblings:l}}function HT(){return en}function WT(){return en=Sr>0?Cs(nl,--Sr):0,Ga--,en===10&&(Ga=1,Gd--),en}function Fr(){return en=Sr2||Wp(en)>3?"":" "}function GT(e,t){for(;--t&&Fr()&&!(en<48||en>102||en>57&&en<65||en>70&&en<97););return Kd(e,tu()+(t<6&&Mi()==32&&Fr()==32))}function Vp(e){for(;Fr();)switch(en){case e:return Sr;case 34:case 39:e!==34&&e!==39&&Vp(en);break;case 40:e===41&&Vp(e);break;case 92:Fr();break}return Sr}function KT(e,t){for(;Fr()&&e+en!==47+10;)if(e+en===42+42&&Mi()===47)break;return"/*"+Kd(t,Sr-1)+"*"+Hh(e===47?e:Fr())}function qT(e){for(;!Wp(Mi());)Fr();return Kd(e,Sr)}function XT(e){return UT(nu("",null,null,null,[""],e=VT(e),0,[0],e))}function nu(e,t,n,r,o,i,a,l,s){for(var c=0,u=0,d=a,v=0,h=0,g=0,p=1,b=1,m=1,y=0,S="",x=o,$=i,E=r,w=S;b;)switch(g=y,y=Fr()){case 40:if(g!=108&&Cs(w,d-1)==58){BT(w+=eu(nv(y),"&","&\f"),"&\f",Px(c?l[c-1]:0))!=-1&&(m=-1);break}case 34:case 39:case 91:w+=nv(y);break;case 9:case 10:case 13:case 32:w+=YT(g);break;case 92:w+=GT(tu()-1,7);continue;case 47:switch(Mi()){case 42:case 47:Mc(QT(KT(Fr(),tu()),t,n,s),s);break;default:w+="/"}break;case 123*p:l[c++]=so(w)*m;case 125*p:case 59:case 0:switch(y){case 0:case 125:b=0;case 59+u:m==-1&&(w=eu(w,/\f/g,"")),h>0&&so(w)-d&&Mc(h>32?Ey(w+";",r,n,d-1,s):Ey(eu(w," ","")+";",r,n,d-2,s),s);break;case 59:w+=";";default:if(Mc(E=$y(w,t,n,c,u,o,l,S,x=[],$=[],d,i),i),y===123)if(u===0)nu(w,t,E,E,x,i,d,l,$);else switch(v===99&&Cs(w,3)===110?100:v){case 100:case 108:case 109:case 115:nu(e,E,E,r&&Mc($y(e,E,E,0,0,o,l,S,o,x=[],d,$),$),o,$,d,l,r?x:$);break;default:nu(w,E,E,E,[""],$,0,l,$)}}c=u=h=0,p=m=1,S=w="",d=a;break;case 58:d=1+so(w),h=g;default:if(p<1){if(y==123)--p;else if(y==125&&p++==0&&WT()==125)continue}switch(w+=Hh(y),y*p){case 38:m=u>0?1:(w+="\f",-1);break;case 44:l[c++]=(so(w)-1)*m,m=1;break;case 64:Mi()===45&&(w+=nv(Fr())),v=Mi(),u=d=so(S=w+=qT(tu())),y++;break;case 45:g===45&&so(w)==2&&(p=0)}}return i}function $y(e,t,n,r,o,i,a,l,s,c,u,d){for(var v=o-1,h=o===0?i:[""],g=jT(h),p=0,b=0,m=0;p0?h[y]+" "+S:eu(S,/&\f/g,h[y])))&&(s[m++]=x);return Wh(e,t,n,o===0?Rx:l,s,c,u,d)}function QT(e,t,n,r){return Wh(e,t,n,Ox,Hh(HT()),xs(e,2,-2),0,r)}function Ey(e,t,n,r,o){return Wh(e,t,n,Ix,xs(e,0,r),xs(e,r+1,-1),r,o)}function Up(e,t){for(var n="",r=0;r1&&arguments[1]!==void 0?arguments[1]:{},r=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{root:!0,parentSelectors:[]},o=r.root,i=r.injectHash,a=r.parentSelectors,l=n.hashId,s=n.layer;n.path;var c=n.hashPriority,u=n.transformers,d=u===void 0?[]:u;n.linters;var v="",h={};function g(S){var x=S.getName(l);if(!h[x]){var $=e(S.style,n,{root:!1,parentSelectors:a}),E=G($,1),w=E[0];h[x]="@keyframes ".concat(S.getName(l)).concat(w)}}function p(S){var x=arguments.length>1&&arguments[1]!==void 0?arguments[1]:[];return S.forEach(function($){Array.isArray($)?p($,x):$&&x.push($)}),x}var b=p(Array.isArray(t)?t:[t]);if(b.forEach(function(S){var x=typeof S=="string"&&!o?{}:S;if(typeof x=="string")v+="".concat(x,` +`);else if(x._keyframe)g(x);else{var $=d.reduce(function(E,w){var R;return(w==null||(R=w.visit)===null||R===void 0?void 0:R.call(w,E))||E},x);Object.keys($).forEach(function(E){var w=$[E];if(Qe(w)==="object"&&w&&(E!=="animationName"||!w._keyframe)&&!r3(w)){var R=!1,P=E.trim(),N=!1;(o||i)&&l?P.startsWith("@")?R=!0:P=o3(E,l,c):o&&!l&&(P==="&"||P==="")&&(P="",N=!0);var I=e(w,n,{root:N,injectHash:R,parentSelectors:[].concat(Oe(a),[P])}),z=G(I,2),F=z[0],T=z[1];h=U(U({},h),T),v+="".concat(P).concat(F)}else{let M=function(L,A){var B=L.replace(/[A-Z]/g,function(j){return"-".concat(j.toLowerCase())}),k=A;!LT[L]&&typeof k=="number"&&k!==0&&(k="".concat(k,"px")),L==="animationName"&&A!==null&&A!==void 0&&A._keyframe&&(g(A),k=A.getName(l)),v+="".concat(B,":").concat(k,";")};var O=M,D,_=(D=w==null?void 0:w.value)!==null&&D!==void 0?D:w;Qe(w)==="object"&&w!==null&&w!==void 0&&w[Dx]&&Array.isArray(_)?_.forEach(function(L){M(E,L)}):M(E,_)}})}}),!o)v="{".concat(v,"}");else if(s&&mT()){var m=s.split(","),y=m[m.length-1].trim();v="@layer ".concat(y," {").concat(v,"}"),m.length>1&&(v="@layer ".concat(s,"{%%%:%}").concat(v))}return[v,h]};function Lx(e,t){return Yu("".concat(e.join("%")).concat(t))}function a3(){return null}var zx="style";function Gp(e,t){var n=e.token,r=e.path,o=e.hashId,i=e.layer,a=e.nonce,l=e.clientOnly,s=e.order,c=s===void 0?0:s,u=f.exports.useContext(Yd),d=u.autoClear;u.mock;var v=u.defaultCache,h=u.hashPriority,g=u.container,p=u.ssrInline,b=u.transformers,m=u.linters,y=u.cache,S=n._tokenKey,x=[S].concat(Oe(r)),$=jp,E=jh(zx,x,function(){var I=x.join("|");if(e3(I)){var z=t3(I),F=G(z,2),T=F[0],D=F[1];if(T)return[T,S,D,{},l,c]}var _=t(),O=i3(_,{hashId:o,hashPriority:h,layer:i,path:r.join("-"),transformers:b,linters:m}),M=G(O,2),L=M[0],A=M[1],B=Yp(L),k=Lx(x,B);return[B,S,k,A,l,c]},function(I,z){var F=G(I,3),T=F[2];(z||d)&&jp&&Ss(T,{mark:zr})},function(I){var z=G(I,4),F=z[0];z[1];var T=z[2],D=z[3];if($&&F!==_x){var _={mark:zr,prepend:"queue",attachTo:g,priority:c},O=typeof a=="function"?a():a;O&&(_.csp={nonce:O});var M=Xo(F,T,_);M[zo]=y.instanceId,M.setAttribute(Ya,S),Object.keys(D).forEach(function(L){Xo(Yp(D[L]),"_effect-".concat(L),_)})}}),w=G(E,3),R=w[0],P=w[1],N=w[2];return function(I){var z;if(!p||$||!v)z=C(a3,{});else{var F;z=C("style",{...(F={},V(F,Ya,P),V(F,zr,N),F),dangerouslySetInnerHTML:{__html:R}})}return ie(Tt,{children:[z,I]})}}var l3=function(t,n,r){var o=G(t,6),i=o[0],a=o[1],l=o[2],s=o[3],c=o[4],u=o[5],d=r||{},v=d.plain;if(c)return null;var h=i,g={"data-rc-order":"prependQueue","data-rc-priority":"".concat(u)};return h=Gu(i,a,l,g,v),s&&Object.keys(s).forEach(function(p){if(!n[p]){n[p]=!0;var b=Yp(s[p]);h+=Gu(b,a,"_effect-".concat(p),g,v)}}),[u,l,h]},Fx="cssVar",s3=function(t,n){var r=t.key,o=t.prefix,i=t.unitless,a=t.ignore,l=t.token,s=t.scope,c=s===void 0?"":s,u=f.exports.useContext(Yd),d=u.cache.instanceId,v=u.container,h=l._tokenKey,g=[].concat(Oe(t.path),[r,c,h]),p=jh(Fx,g,function(){var b=n(),m=Ex(b,r,{prefix:o,unitless:i,ignore:a,scope:c}),y=G(m,2),S=y[0],x=y[1],$=Lx(g,x);return[S,x,$,r]},function(b){var m=G(b,3),y=m[2];jp&&Ss(y,{mark:zr})},function(b){var m=G(b,3),y=m[1],S=m[2];if(!!y){var x=Xo(y,S,{mark:zr,prepend:"queue",attachTo:v,priority:-999});x[zo]=d,x.setAttribute(Ya,r)}});return p},c3=function(t,n,r){var o=G(t,4),i=o[1],a=o[2],l=o[3],s=r||{},c=s.plain;if(!i)return null;var u=-999,d={"data-rc-order":"prependQueue","data-rc-priority":"".concat(u)},v=Gu(i,l,a,d,c);return[u,a,v]},bl;bl={},V(bl,zx,l3),V(bl,Mx,DT),V(bl,Fx,c3);var Ct=function(){function e(t,n){zn(this,e),V(this,"name",void 0),V(this,"style",void 0),V(this,"_keyframe",!0),this.name=t,this.style=n}return Fn(e,[{key:"getName",value:function(){var n=arguments.length>0&&arguments[0]!==void 0?arguments[0]:"";return n?"".concat(n,"-").concat(this.name):this.name}}]),e}();function Yi(e){return e.notSplit=!0,e}Yi(["borderTop","borderBottom"]),Yi(["borderTop"]),Yi(["borderBottom"]),Yi(["borderLeft","borderRight"]),Yi(["borderLeft"]),Yi(["borderRight"]);function kx(e){return VC(e)||yx(e)||Nh(e)||UC()}function qr(e,t){for(var n=e,r=0;r3&&arguments[3]!==void 0?arguments[3]:!1;return t.length&&r&&n===void 0&&!qr(e,t.slice(0,-1))?e:Bx(e,t,n,r)}function u3(e){return Qe(e)==="object"&&e!==null&&Object.getPrototypeOf(e)===Object.prototype}function Oy(e){return Array.isArray(e)?[]:{}}var d3=typeof Reflect>"u"?Object.keys:Reflect.ownKeys;function Ca(){for(var e=arguments.length,t=new Array(e),n=0;n{const e=()=>{};return e.deprecated=f3,e},p3=f.exports.createContext(void 0);var g3={items_per_page:"/ page",jump_to:"Go to",jump_to_confirm:"confirm",page:"Page",prev_page:"Previous Page",next_page:"Next Page",prev_5:"Previous 5 Pages",next_5:"Next 5 Pages",prev_3:"Previous 3 Pages",next_3:"Next 3 Pages",page_size:"Page Size"},h3={locale:"en_US",today:"Today",now:"Now",backToToday:"Back to today",ok:"OK",clear:"Clear",month:"Month",year:"Year",timeSelect:"select time",dateSelect:"select date",weekSelect:"Choose a week",monthSelect:"Choose a month",yearSelect:"Choose a year",decadeSelect:"Choose a decade",yearFormat:"YYYY",dateFormat:"M/D/YYYY",dayFormat:"D",dateTimeFormat:"M/D/YYYY HH:mm:ss",monthBeforeYear:!0,previousMonth:"Previous month (PageUp)",nextMonth:"Next month (PageDown)",previousYear:"Last year (Control + left)",nextYear:"Next year (Control + right)",previousDecade:"Last decade",nextDecade:"Next decade",previousCentury:"Last century",nextCentury:"Next century"};const m3={placeholder:"Select time",rangePlaceholder:["Start time","End time"]},Hx=m3,y3={lang:Object.assign({placeholder:"Select date",yearPlaceholder:"Select year",quarterPlaceholder:"Select quarter",monthPlaceholder:"Select month",weekPlaceholder:"Select week",rangePlaceholder:["Start date","End date"],rangeYearPlaceholder:["Start year","End year"],rangeQuarterPlaceholder:["Start quarter","End quarter"],rangeMonthPlaceholder:["Start month","End month"],rangeWeekPlaceholder:["Start week","End week"]},h3),timePickerLocale:Object.assign({},Hx)},Kp=y3,Qn="${label} is not a valid ${type}",b3={locale:"en",Pagination:g3,DatePicker:Kp,TimePicker:Hx,Calendar:Kp,global:{placeholder:"Please select"},Table:{filterTitle:"Filter menu",filterConfirm:"OK",filterReset:"Reset",filterEmptyText:"No filters",filterCheckall:"Select all items",filterSearchPlaceholder:"Search in filters",emptyText:"No data",selectAll:"Select current page",selectInvert:"Invert current page",selectNone:"Clear all data",selectionAll:"Select all data",sortTitle:"Sort",expand:"Expand row",collapse:"Collapse row",triggerDesc:"Click to sort descending",triggerAsc:"Click to sort ascending",cancelSort:"Click to cancel sorting"},Tour:{Next:"Next",Previous:"Previous",Finish:"Finish"},Modal:{okText:"OK",cancelText:"Cancel",justOkText:"OK"},Popconfirm:{okText:"OK",cancelText:"Cancel"},Transfer:{titles:["",""],searchPlaceholder:"Search here",itemUnit:"item",itemsUnit:"items",remove:"Remove",selectCurrent:"Select current page",removeCurrent:"Remove current page",selectAll:"Select all data",removeAll:"Remove all data",selectInvert:"Invert current page"},Upload:{uploading:"Uploading...",removeFile:"Remove file",uploadError:"Upload error",previewFile:"Preview file",downloadFile:"Download file"},Empty:{description:"No data"},Icon:{icon:"icon"},Text:{edit:"Edit",copy:"Copy",copied:"Copied",expand:"Expand"},Form:{optional:"(optional)",defaultValidateMessages:{default:"Field validation error for ${label}",required:"Please enter ${label}",enum:"${label} must be one of [${enum}]",whitespace:"${label} cannot be a blank character",date:{format:"${label} date format is invalid",parse:"${label} cannot be converted to a date",invalid:"${label} is an invalid date"},types:{string:Qn,method:Qn,array:Qn,object:Qn,number:Qn,date:Qn,boolean:Qn,integer:Qn,float:Qn,regexp:Qn,email:Qn,url:Qn,hex:Qn},string:{len:"${label} must be ${len} characters",min:"${label} must be at least ${min} characters",max:"${label} must be up to ${max} characters",range:"${label} must be between ${min}-${max} characters"},number:{len:"${label} must be equal to ${len}",min:"${label} must be minimum ${min}",max:"${label} must be maximum ${max}",range:"${label} must be between ${min}-${max}"},array:{len:"Must be ${len} ${label}",min:"At least ${min} ${label}",max:"At most ${max} ${label}",range:"The amount of ${label} must be between ${min}-${max}"},pattern:{mismatch:"${label} does not match the pattern ${pattern}"}}},Image:{preview:"Preview"},QRCode:{expired:"QR code expired",refresh:"Refresh",scanned:"Scanned"},ColorPicker:{presetEmpty:"Empty"}},Jo=b3;Object.assign({},Jo.Modal);let ru=[];const Ry=()=>ru.reduce((e,t)=>Object.assign(Object.assign({},e),t),Jo.Modal);function S3(e){if(e){const t=Object.assign({},e);return ru.push(t),Ry(),()=>{ru=ru.filter(n=>n!==t),Ry()}}Object.assign({},Jo.Modal)}const C3=f.exports.createContext(void 0),Vh=C3,x3=(e,t)=>{const n=f.exports.useContext(Vh),r=f.exports.useMemo(()=>{var i;const a=t||Jo[e],l=(i=n==null?void 0:n[e])!==null&&i!==void 0?i:{};return Object.assign(Object.assign({},typeof a=="function"?a():a),l||{})},[e,t,n]),o=f.exports.useMemo(()=>{const i=n==null?void 0:n.locale;return(n==null?void 0:n.exist)&&!i?Jo.locale:i},[n]);return[r,o]},Wx=x3,w3="internalMark",$3=e=>{const{locale:t={},children:n,_ANT_MARK__:r}=e;f.exports.useEffect(()=>S3(t&&t.Modal),[t]);const o=f.exports.useMemo(()=>Object.assign(Object.assign({},t),{exist:!0}),[t]);return C(Vh.Provider,{value:o,children:n})},E3=$3,M3=e=>{const{controlHeight:t}=e;return{controlHeightSM:t*.75,controlHeightXS:t*.5,controlHeightLG:t*1.25}},O3=M3;function R3(e){const{sizeUnit:t,sizeStep:n}=e;return{sizeXXL:t*(n+8),sizeXL:t*(n+4),sizeLG:t*(n+2),sizeMD:t*(n+1),sizeMS:t*n,size:t*n,sizeSM:t*(n-1),sizeXS:t*(n-2),sizeXXS:t*(n-3)}}const Vx={blue:"#1677ff",purple:"#722ED1",cyan:"#13C2C2",green:"#52C41A",magenta:"#EB2F96",pink:"#eb2f96",red:"#F5222D",orange:"#FA8C16",yellow:"#FADB14",volcano:"#FA541C",geekblue:"#2F54EB",gold:"#FAAD14",lime:"#A0D911"},I3=Object.assign(Object.assign({},Vx),{colorPrimary:"#1677ff",colorSuccess:"#52c41a",colorWarning:"#faad14",colorError:"#ff4d4f",colorInfo:"#1677ff",colorLink:"",colorTextBase:"",colorBgBase:"",fontFamily:`-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, +'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', +'Noto Color Emoji'`,fontFamilyCode:"'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace",fontSize:14,lineWidth:1,lineType:"solid",motionUnit:.1,motionBase:0,motionEaseOutCirc:"cubic-bezier(0.08, 0.82, 0.17, 1)",motionEaseInOutCirc:"cubic-bezier(0.78, 0.14, 0.15, 0.86)",motionEaseOut:"cubic-bezier(0.215, 0.61, 0.355, 1)",motionEaseInOut:"cubic-bezier(0.645, 0.045, 0.355, 1)",motionEaseOutBack:"cubic-bezier(0.12, 0.4, 0.29, 1.46)",motionEaseInBack:"cubic-bezier(0.71, -0.46, 0.88, 0.6)",motionEaseInQuint:"cubic-bezier(0.755, 0.05, 0.855, 0.06)",motionEaseOutQuint:"cubic-bezier(0.23, 1, 0.32, 1)",borderRadius:6,sizeUnit:4,sizeStep:4,sizePopupArrow:16,controlHeight:32,zIndexBase:0,zIndexPopupBase:1e3,opacityImage:1,wireframe:!1,motion:!0}),ws=I3;function P3(e,t){let{generateColorPalettes:n,generateNeutralColorPalettes:r}=t;const{colorSuccess:o,colorWarning:i,colorError:a,colorInfo:l,colorPrimary:s,colorBgBase:c,colorTextBase:u}=e,d=n(s),v=n(o),h=n(i),g=n(a),p=n(l),b=r(c,u),m=e.colorLink||e.colorInfo,y=n(m);return Object.assign(Object.assign({},b),{colorPrimaryBg:d[1],colorPrimaryBgHover:d[2],colorPrimaryBorder:d[3],colorPrimaryBorderHover:d[4],colorPrimaryHover:d[5],colorPrimary:d[6],colorPrimaryActive:d[7],colorPrimaryTextHover:d[8],colorPrimaryText:d[9],colorPrimaryTextActive:d[10],colorSuccessBg:v[1],colorSuccessBgHover:v[2],colorSuccessBorder:v[3],colorSuccessBorderHover:v[4],colorSuccessHover:v[4],colorSuccess:v[6],colorSuccessActive:v[7],colorSuccessTextHover:v[8],colorSuccessText:v[9],colorSuccessTextActive:v[10],colorErrorBg:g[1],colorErrorBgHover:g[2],colorErrorBorder:g[3],colorErrorBorderHover:g[4],colorErrorHover:g[5],colorError:g[6],colorErrorActive:g[7],colorErrorTextHover:g[8],colorErrorText:g[9],colorErrorTextActive:g[10],colorWarningBg:h[1],colorWarningBgHover:h[2],colorWarningBorder:h[3],colorWarningBorderHover:h[4],colorWarningHover:h[4],colorWarning:h[6],colorWarningActive:h[7],colorWarningTextHover:h[8],colorWarningText:h[9],colorWarningTextActive:h[10],colorInfoBg:p[1],colorInfoBgHover:p[2],colorInfoBorder:p[3],colorInfoBorderHover:p[4],colorInfoHover:p[4],colorInfo:p[6],colorInfoActive:p[7],colorInfoTextHover:p[8],colorInfoText:p[9],colorInfoTextActive:p[10],colorLinkHover:y[4],colorLink:y[6],colorLinkActive:y[7],colorBgMask:new Mt("#000").setAlpha(.45).toRgbString(),colorWhite:"#fff"})}const T3=e=>{let t=e,n=e,r=e,o=e;return e<6&&e>=5?t=e+1:e<16&&e>=6?t=e+2:e>=16&&(t=16),e<7&&e>=5?n=4:e<8&&e>=7?n=5:e<14&&e>=8?n=6:e<16&&e>=14?n=7:e>=16&&(n=8),e<6&&e>=2?r=1:e>=6&&(r=2),e>4&&e<8?o=4:e>=8&&(o=6),{borderRadius:e,borderRadiusXS:r,borderRadiusSM:n,borderRadiusLG:t,borderRadiusOuter:o}},N3=T3;function _3(e){const{motionUnit:t,motionBase:n,borderRadius:r,lineWidth:o}=e;return Object.assign({motionDurationFast:`${(n+t).toFixed(1)}s`,motionDurationMid:`${(n+t*2).toFixed(1)}s`,motionDurationSlow:`${(n+t*3).toFixed(1)}s`,lineWidthBold:o+1},N3(r))}const io=(e,t)=>new Mt(e).setAlpha(t).toRgbString(),Sl=(e,t)=>new Mt(e).darken(t).toHexString(),A3=e=>{const t=Ai(e);return{1:t[0],2:t[1],3:t[2],4:t[3],5:t[4],6:t[5],7:t[6],8:t[4],9:t[5],10:t[6]}},D3=(e,t)=>{const n=e||"#fff",r=t||"#000";return{colorBgBase:n,colorTextBase:r,colorText:io(r,.88),colorTextSecondary:io(r,.65),colorTextTertiary:io(r,.45),colorTextQuaternary:io(r,.25),colorFill:io(r,.15),colorFillSecondary:io(r,.06),colorFillTertiary:io(r,.04),colorFillQuaternary:io(r,.02),colorBgLayout:Sl(n,4),colorBgContainer:Sl(n,0),colorBgElevated:Sl(n,0),colorBgSpotlight:io(r,.85),colorBgBlur:"transparent",colorBorder:Sl(n,15),colorBorderSecondary:Sl(n,6)}};function ou(e){return(e+8)/e}function L3(e){const t=new Array(10).fill(null).map((n,r)=>{const o=r-1,i=e*Math.pow(2.71828,o/5),a=r>1?Math.floor(i):Math.ceil(i);return Math.floor(a/2)*2});return t[1]=e,t.map(n=>({size:n,lineHeight:ou(n)}))}const z3=e=>{const t=L3(e),n=t.map(u=>u.size),r=t.map(u=>u.lineHeight),o=n[1],i=n[0],a=n[2],l=r[1],s=r[0],c=r[2];return{fontSizeSM:i,fontSize:o,fontSizeLG:a,fontSizeXL:n[3],fontSizeHeading1:n[6],fontSizeHeading2:n[5],fontSizeHeading3:n[4],fontSizeHeading4:n[3],fontSizeHeading5:n[2],lineHeight:l,lineHeightLG:c,lineHeightSM:s,fontHeight:Math.round(l*o),fontHeightLG:Math.round(c*a),fontHeightSM:Math.round(s*i),lineHeightHeading1:r[6],lineHeightHeading2:r[5],lineHeightHeading3:r[4],lineHeightHeading4:r[3],lineHeightHeading5:r[2]}},F3=z3;function k3(e){const t=Object.keys(Vx).map(n=>{const r=Ai(e[n]);return new Array(10).fill(1).reduce((o,i,a)=>(o[`${n}-${a+1}`]=r[a],o[`${n}${a+1}`]=r[a],o),{})}).reduce((n,r)=>(n=Object.assign(Object.assign({},n),r),n),{});return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({},e),t),P3(e,{generateColorPalettes:A3,generateNeutralColorPalettes:D3})),F3(e.fontSize)),R3(e)),O3(e)),_3(e))}const Ux=Bp(k3),qp={token:ws,override:{override:ws},hashed:!0},Yx=lt.createContext(qp),Gx="anticon",B3=(e,t)=>t||(e?`ant-${e}`:"ant"),ot=f.exports.createContext({getPrefixCls:B3,iconPrefixCls:Gx}),j3=`-ant-${Date.now()}-${Math.random()}`;function H3(e,t){const n={},r=(a,l)=>{let s=a.clone();return s=(l==null?void 0:l(s))||s,s.toRgbString()},o=(a,l)=>{const s=new Mt(a),c=Ai(s.toRgbString());n[`${l}-color`]=r(s),n[`${l}-color-disabled`]=c[1],n[`${l}-color-hover`]=c[4],n[`${l}-color-active`]=c[6],n[`${l}-color-outline`]=s.clone().setAlpha(.2).toRgbString(),n[`${l}-color-deprecated-bg`]=c[0],n[`${l}-color-deprecated-border`]=c[2]};if(t.primaryColor){o(t.primaryColor,"primary");const a=new Mt(t.primaryColor),l=Ai(a.toRgbString());l.forEach((c,u)=>{n[`primary-${u+1}`]=c}),n["primary-color-deprecated-l-35"]=r(a,c=>c.lighten(35)),n["primary-color-deprecated-l-20"]=r(a,c=>c.lighten(20)),n["primary-color-deprecated-t-20"]=r(a,c=>c.tint(20)),n["primary-color-deprecated-t-50"]=r(a,c=>c.tint(50)),n["primary-color-deprecated-f-12"]=r(a,c=>c.setAlpha(c.getAlpha()*.12));const s=new Mt(l[0]);n["primary-color-active-deprecated-f-30"]=r(s,c=>c.setAlpha(c.getAlpha()*.3)),n["primary-color-active-deprecated-d-02"]=r(s,c=>c.darken(2))}return t.successColor&&o(t.successColor,"success"),t.warningColor&&o(t.warningColor,"warning"),t.errorColor&&o(t.errorColor,"error"),t.infoColor&&o(t.infoColor,"info"),` + :root { + ${Object.keys(n).map(a=>`--${e}-${a}: ${n[a]};`).join(` +`)} + } + `.trim()}function W3(e,t){const n=H3(e,t);Rn()&&Xo(n,`${j3}-dynamic-theme`)}const Xp=f.exports.createContext(!1),V3=e=>{let{children:t,disabled:n}=e;const r=f.exports.useContext(Xp);return C(Xp.Provider,{value:n!=null?n:r,children:t})},rl=Xp,Qp=f.exports.createContext(void 0),U3=e=>{let{children:t,size:n}=e;const r=f.exports.useContext(Qp);return C(Qp.Provider,{value:n||r,children:t})},qd=Qp;function Y3(){const e=f.exports.useContext(rl),t=f.exports.useContext(qd);return{componentDisabled:e,componentSize:t}}const $s=["blue","purple","cyan","green","magenta","pink","red","orange","yellow","volcano","geekblue","lime","gold"],G3="5.14.2";function rv(e){return e>=0&&e<=255}function Oc(e,t){const{r:n,g:r,b:o,a:i}=new Mt(e).toRgb();if(i<1)return e;const{r:a,g:l,b:s}=new Mt(t).toRgb();for(let c=.01;c<=1;c+=.01){const u=Math.round((n-a*(1-c))/c),d=Math.round((r-l*(1-c))/c),v=Math.round((o-s*(1-c))/c);if(rv(u)&&rv(d)&&rv(v))return new Mt({r:u,g:d,b:v,a:Math.round(c*100)/100}).toRgbString()}return new Mt({r:n,g:r,b:o,a:1}).toRgbString()}var K3=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{delete r[v]});const o=Object.assign(Object.assign({},n),r),i=480,a=576,l=768,s=992,c=1200,u=1600;if(o.motion===!1){const v="0s";o.motionDurationFast=v,o.motionDurationMid=v,o.motionDurationSlow=v}return Object.assign(Object.assign(Object.assign({},o),{colorFillContent:o.colorFillSecondary,colorFillContentHover:o.colorFill,colorFillAlter:o.colorFillQuaternary,colorBgContainerDisabled:o.colorFillTertiary,colorBorderBg:o.colorBgContainer,colorSplit:Oc(o.colorBorderSecondary,o.colorBgContainer),colorTextPlaceholder:o.colorTextQuaternary,colorTextDisabled:o.colorTextQuaternary,colorTextHeading:o.colorText,colorTextLabel:o.colorTextSecondary,colorTextDescription:o.colorTextTertiary,colorTextLightSolid:o.colorWhite,colorHighlight:o.colorError,colorBgTextHover:o.colorFillSecondary,colorBgTextActive:o.colorFill,colorIcon:o.colorTextTertiary,colorIconHover:o.colorText,colorErrorOutline:Oc(o.colorErrorBg,o.colorBgContainer),colorWarningOutline:Oc(o.colorWarningBg,o.colorBgContainer),fontSizeIcon:o.fontSizeSM,lineWidthFocus:o.lineWidth*4,lineWidth:o.lineWidth,controlOutlineWidth:o.lineWidth*2,controlInteractiveSize:o.controlHeight/2,controlItemBgHover:o.colorFillTertiary,controlItemBgActive:o.colorPrimaryBg,controlItemBgActiveHover:o.colorPrimaryBgHover,controlItemBgActiveDisabled:o.colorFill,controlTmpOutline:o.colorFillQuaternary,controlOutline:Oc(o.colorPrimaryBg,o.colorBgContainer),lineType:o.lineType,borderRadius:o.borderRadius,borderRadiusXS:o.borderRadiusXS,borderRadiusSM:o.borderRadiusSM,borderRadiusLG:o.borderRadiusLG,fontWeightStrong:600,opacityLoading:.65,linkDecoration:"none",linkHoverDecoration:"none",linkFocusDecoration:"none",controlPaddingHorizontal:12,controlPaddingHorizontalSM:8,paddingXXS:o.sizeXXS,paddingXS:o.sizeXS,paddingSM:o.sizeSM,padding:o.size,paddingMD:o.sizeMD,paddingLG:o.sizeLG,paddingXL:o.sizeXL,paddingContentHorizontalLG:o.sizeLG,paddingContentVerticalLG:o.sizeMS,paddingContentHorizontal:o.sizeMS,paddingContentVertical:o.sizeSM,paddingContentHorizontalSM:o.size,paddingContentVerticalSM:o.sizeXS,marginXXS:o.sizeXXS,marginXS:o.sizeXS,marginSM:o.sizeSM,margin:o.size,marginMD:o.sizeMD,marginLG:o.sizeLG,marginXL:o.sizeXL,marginXXL:o.sizeXXL,boxShadow:` + 0 6px 16px 0 rgba(0, 0, 0, 0.08), + 0 3px 6px -4px rgba(0, 0, 0, 0.12), + 0 9px 28px 8px rgba(0, 0, 0, 0.05) + `,boxShadowSecondary:` + 0 6px 16px 0 rgba(0, 0, 0, 0.08), + 0 3px 6px -4px rgba(0, 0, 0, 0.12), + 0 9px 28px 8px rgba(0, 0, 0, 0.05) + `,boxShadowTertiary:` + 0 1px 2px 0 rgba(0, 0, 0, 0.03), + 0 1px 6px -1px rgba(0, 0, 0, 0.02), + 0 2px 4px 0 rgba(0, 0, 0, 0.02) + `,screenXS:i,screenXSMin:i,screenXSMax:a-1,screenSM:a,screenSMMin:a,screenSMMax:l-1,screenMD:l,screenMDMin:l,screenMDMax:s-1,screenLG:s,screenLGMin:s,screenLGMax:c-1,screenXL:c,screenXLMin:c,screenXLMax:u-1,screenXXL:u,screenXXLMin:u,boxShadowPopoverArrow:"2px 2px 5px rgba(0, 0, 0, 0.05)",boxShadowCard:` + 0 1px 2px -2px ${new Mt("rgba(0, 0, 0, 0.16)").toRgbString()}, + 0 3px 6px 0 ${new Mt("rgba(0, 0, 0, 0.12)").toRgbString()}, + 0 5px 12px 4px ${new Mt("rgba(0, 0, 0, 0.09)").toRgbString()} + `,boxShadowDrawerRight:` + -6px 0 16px 0 rgba(0, 0, 0, 0.08), + -3px 0 6px -4px rgba(0, 0, 0, 0.12), + -9px 0 28px 8px rgba(0, 0, 0, 0.05) + `,boxShadowDrawerLeft:` + 6px 0 16px 0 rgba(0, 0, 0, 0.08), + 3px 0 6px -4px rgba(0, 0, 0, 0.12), + 9px 0 28px 8px rgba(0, 0, 0, 0.05) + `,boxShadowDrawerUp:` + 0 6px 16px 0 rgba(0, 0, 0, 0.08), + 0 3px 6px -4px rgba(0, 0, 0, 0.12), + 0 9px 28px 8px rgba(0, 0, 0, 0.05) + `,boxShadowDrawerDown:` + 0 -6px 16px 0 rgba(0, 0, 0, 0.08), + 0 -3px 6px -4px rgba(0, 0, 0, 0.12), + 0 -9px 28px 8px rgba(0, 0, 0, 0.05) + `,boxShadowTabsOverflowLeft:"inset 10px 0 8px -8px rgba(0, 0, 0, 0.08)",boxShadowTabsOverflowRight:"inset -10px 0 8px -8px rgba(0, 0, 0, 0.08)",boxShadowTabsOverflowTop:"inset 0 10px 8px -8px rgba(0, 0, 0, 0.08)",boxShadowTabsOverflowBottom:"inset 0 -10px 8px -8px rgba(0, 0, 0, 0.08)"}),r)}var Iy=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{const r=n.getDerivativeToken(e),{override:o}=t,i=Iy(t,["override"]);let a=Object.assign(Object.assign({},r),{override:o});return a=Kx(a),i&&Object.entries(i).forEach(l=>{let[s,c]=l;const{theme:u}=c,d=Iy(c,["theme"]);let v=d;u&&(v=Qx(Object.assign(Object.assign({},a),d),{override:d},u)),a[s]=v}),a};function Kn(){const{token:e,hashed:t,theme:n,override:r,cssVar:o}=lt.useContext(Yx),i=`${G3}-${t||""}`,a=n||Ux,[l,s,c]=AT(a,[ws,e],{salt:i,override:r,getComputedToken:Qx,formatToken:Kx,cssVar:o&&{prefix:o.prefix,key:o.key,unitless:qx,ignore:Xx,preserve:q3}});return[a,c,t?s:"",l,o]}function hn(e){var t=f.exports.useRef();t.current=e;var n=f.exports.useCallback(function(){for(var r,o=arguments.length,i=new Array(o),a=0;a1&&arguments[1]!==void 0?arguments[1]:!1;return{boxSizing:"border-box",margin:0,padding:0,color:e.colorText,fontSize:e.fontSize,lineHeight:e.lineHeight,listStyle:"none",fontFamily:t?"inherit":e.fontFamily}},Uh=()=>({display:"inline-flex",alignItems:"center",color:"inherit",fontStyle:"normal",lineHeight:0,textAlign:"center",textTransform:"none",verticalAlign:"-0.125em",textRendering:"optimizeLegibility","-webkit-font-smoothing":"antialiased","-moz-osx-font-smoothing":"grayscale","> *":{lineHeight:1},svg:{display:"inline-block"}}),Us=()=>({"&::before":{display:"table",content:'""'},"&::after":{display:"table",clear:"both",content:'""'}}),X3=e=>({a:{color:e.colorLink,textDecoration:e.linkDecoration,backgroundColor:"transparent",outline:"none",cursor:"pointer",transition:`color ${e.motionDurationSlow}`,"-webkit-text-decoration-skip":"objects","&:hover":{color:e.colorLinkHover},"&:active":{color:e.colorLinkActive},[`&:active, + &:hover`]:{textDecoration:e.linkHoverDecoration,outline:0},"&:focus":{textDecoration:e.linkFocusDecoration,outline:0},"&[disabled]":{color:e.colorTextDisabled,cursor:"not-allowed"}}}),Q3=(e,t,n)=>{const{fontFamily:r,fontSize:o}=e,i=`[class^="${t}"], [class*=" ${t}"]`;return{[n?`.${n}`:i]:{fontFamily:r,fontSize:o,boxSizing:"border-box","&::before, &::after":{boxSizing:"border-box"},[i]:{boxSizing:"border-box","&::before, &::after":{boxSizing:"border-box"}}}}},Yh=e=>({outline:`${X(e.lineWidthFocus)} solid ${e.colorPrimaryBorder}`,outlineOffset:1,transition:"outline-offset 0s, outline 0s"}),Xd=e=>({"&:focus-visible":Object.assign({},Yh(e))});let Z3=Fn(function e(){zn(this,e)});const Zx=Z3;function J3(e,t,n){return t=Zo(t),Fh(e,Ud()?Reflect.construct(t,n||[],Zo(e).constructor):t.apply(e,n))}let e5=function(e){Bi(t,e);function t(n){var r;return zn(this,t),r=J3(this,t),r.result=0,n instanceof t?r.result=n.result:typeof n=="number"&&(r.result=n),r}return Fn(t,[{key:"add",value:function(r){return r instanceof t?this.result+=r.result:typeof r=="number"&&(this.result+=r),this}},{key:"sub",value:function(r){return r instanceof t?this.result-=r.result:typeof r=="number"&&(this.result-=r),this}},{key:"mul",value:function(r){return r instanceof t?this.result*=r.result:typeof r=="number"&&(this.result*=r),this}},{key:"div",value:function(r){return r instanceof t?this.result/=r.result:typeof r=="number"&&(this.result/=r),this}},{key:"equal",value:function(){return this.result}}]),t}(Zx);function t5(e,t,n){return t=Zo(t),Fh(e,Ud()?Reflect.construct(t,n||[],Zo(e).constructor):t.apply(e,n))}const Jx="CALC_UNIT";function iv(e){return typeof e=="number"?`${e}${Jx}`:e}let n5=function(e){Bi(t,e);function t(n){var r;return zn(this,t),r=t5(this,t),r.result="",n instanceof t?r.result=`(${n.result})`:typeof n=="number"?r.result=iv(n):typeof n=="string"&&(r.result=n),r}return Fn(t,[{key:"add",value:function(r){return r instanceof t?this.result=`${this.result} + ${r.getResult()}`:(typeof r=="number"||typeof r=="string")&&(this.result=`${this.result} + ${iv(r)}`),this.lowPriority=!0,this}},{key:"sub",value:function(r){return r instanceof t?this.result=`${this.result} - ${r.getResult()}`:(typeof r=="number"||typeof r=="string")&&(this.result=`${this.result} - ${iv(r)}`),this.lowPriority=!0,this}},{key:"mul",value:function(r){return this.lowPriority&&(this.result=`(${this.result})`),r instanceof t?this.result=`${this.result} * ${r.getResult(!0)}`:(typeof r=="number"||typeof r=="string")&&(this.result=`${this.result} * ${r}`),this.lowPriority=!1,this}},{key:"div",value:function(r){return this.lowPriority&&(this.result=`(${this.result})`),r instanceof t?this.result=`${this.result} / ${r.getResult(!0)}`:(typeof r=="number"||typeof r=="string")&&(this.result=`${this.result} / ${r}`),this.lowPriority=!1,this}},{key:"getResult",value:function(r){return this.lowPriority||r?`(${this.result})`:this.result}},{key:"equal",value:function(r){const{unit:o=!0}=r||{},i=new RegExp(`${Jx}`,"g");return this.result=this.result.replace(i,o?"px":""),typeof this.lowPriority<"u"?`calc(${this.result})`:this.result}}]),t}(Zx);const r5=e=>{const t=e==="css"?n5:e5;return n=>new t(n)},o5=r5;function i5(e){return e==="js"?{max:Math.max,min:Math.min}:{max:function(){for(var t=arguments.length,n=new Array(t),r=0;rX(o)).join(",")})`},min:function(){for(var t=arguments.length,n=new Array(t),r=0;rX(o)).join(",")})`}}}const ew=typeof CSSINJS_STATISTIC<"u";let Zp=!0;function $t(){for(var e=arguments.length,t=new Array(e),n=0;n{Object.keys(o).forEach(a=>{Object.defineProperty(r,a,{configurable:!0,enumerable:!0,get:()=>o[a]})})}),Zp=!0,r}const Py={};function a5(){}const l5=e=>{let t,n=e,r=a5;return ew&&typeof Proxy<"u"&&(t=new Set,n=new Proxy(e,{get(o,i){return Zp&&t.add(i),o[i]}}),r=(o,i)=>{var a;Py[o]={global:Array.from(t),component:Object.assign(Object.assign({},(a=Py[o])===null||a===void 0?void 0:a.component),i)}}),{token:n,keys:t,flush:r}},s5=(e,t)=>{const[n,r]=Kn();return Gp({theme:n,token:r,hashId:"",path:["ant-design-icons",e],nonce:()=>t==null?void 0:t.nonce},()=>[{[`.${e}`]:Object.assign(Object.assign({},Uh()),{[`.${e} .${e}-icon`]:{display:"block"}})}])},tw=s5,nw=(e,t,n)=>{var r;return typeof n=="function"?n($t(t,(r=t[e])!==null&&r!==void 0?r:{})):n!=null?n:{}},rw=(e,t,n,r)=>{const o=Object.assign({},t[e]);if(r!=null&&r.deprecatedTokens){const{deprecatedTokens:a}=r;a.forEach(l=>{let[s,c]=l;var u;((o==null?void 0:o[s])||(o==null?void 0:o[c]))&&((u=o[c])!==null&&u!==void 0||(o[c]=o==null?void 0:o[s]))})}const i=Object.assign(Object.assign({},n),o);return Object.keys(i).forEach(a=>{i[a]===t[a]&&delete i[a]}),i},c5=(e,t)=>`${[t,e.replace(/([A-Z]+)([A-Z][a-z]+)/g,"$1-$2").replace(/([a-z])([A-Z])/g,"$1-$2")].filter(Boolean).join("-")}`;function Gh(e,t,n){let r=arguments.length>3&&arguments[3]!==void 0?arguments[3]:{};const o=Array.isArray(e)?e:[e,e],[i]=o,a=o.join("-");return function(l){let s=arguments.length>1&&arguments[1]!==void 0?arguments[1]:l;const[c,u,d,v,h]=Kn(),{getPrefixCls:g,iconPrefixCls:p,csp:b}=f.exports.useContext(ot),m=g(),y=h?"css":"js",S=o5(y),{max:x,min:$}=i5(y),E={theme:c,token:v,hashId:d,nonce:()=>b==null?void 0:b.nonce,clientOnly:r.clientOnly,order:r.order||-999};return Gp(Object.assign(Object.assign({},E),{clientOnly:!1,path:["Shared",m]}),()=>[{"&":X3(v)}]),tw(p,b),[Gp(Object.assign(Object.assign({},E),{path:[a,l,p]}),()=>{if(r.injectStyle===!1)return[];const{token:R,flush:P}=l5(v),N=nw(i,u,n),I=`.${l}`,z=rw(i,u,N,{deprecatedTokens:r.deprecatedTokens});h&&Object.keys(N).forEach(D=>{N[D]=`var(${$x(D,c5(i,h.prefix))})`});const F=$t(R,{componentCls:I,prefixCls:l,iconCls:`.${p}`,antCls:`.${m}`,calc:S,max:x,min:$},h?N:z),T=t(F,{hashId:d,prefixCls:l,rootPrefixCls:m,iconPrefixCls:p});return P(i,z),[r.resetStyle===!1?null:Q3(F,l,s),T]}),d]}}const Kh=(e,t,n,r)=>{const o=Gh(e,t,n,Object.assign({resetStyle:!1,order:-998},r));return a=>{let{prefixCls:l,rootCls:s=l}=a;return o(l,s),null}},u5=(e,t,n)=>{function r(c){return`${e}${c.slice(0,1).toUpperCase()}${c.slice(1)}`}const{unitless:o={},injectStyle:i=!0}=n!=null?n:{},a={[r("zIndexPopup")]:!0};Object.keys(o).forEach(c=>{a[r(c)]=o[c]});const l=c=>{let{rootCls:u,cssVar:d}=c;const[,v]=Kn();return s3({path:[e],prefix:d.prefix,key:d==null?void 0:d.key,unitless:Object.assign(Object.assign({},qx),a),ignore:Xx,token:v,scope:u},()=>{const h=nw(e,v,t),g=rw(e,v,h,{deprecatedTokens:n==null?void 0:n.deprecatedTokens});return Object.keys(h).forEach(p=>{g[r(p)]=g[p],delete g[p]}),g}),null};return c=>{const[,,,,u]=Kn();return[d=>i&&u?ie(Tt,{children:[C(l,{rootCls:c,cssVar:u,component:e}),d]}):d,u==null?void 0:u.key]}},vn=(e,t,n,r)=>{const o=Gh(e,t,n,r),i=u5(Array.isArray(e)?e[0]:e,n,r);return function(a){let l=arguments.length>1&&arguments[1]!==void 0?arguments[1]:a;const[,s]=o(a,l),[c,u]=i(l);return[c,s,u]}};function ow(e,t){return $s.reduce((n,r)=>{const o=e[`${r}1`],i=e[`${r}3`],a=e[`${r}6`],l=e[`${r}7`];return Object.assign(Object.assign({},n),t(r,{lightColor:o,lightBorderColor:i,darkColor:a,textColor:l}))},{})}const d5=Object.assign({},As),{useId:Ty}=d5,f5=()=>"",v5=typeof Ty>"u"?f5:Ty,p5=v5;function g5(e,t){var n;jx();const r=e||{},o=r.inherit===!1||!t?Object.assign(Object.assign({},qp),{hashed:(n=t==null?void 0:t.hashed)!==null&&n!==void 0?n:qp.hashed,cssVar:t==null?void 0:t.cssVar}):t,i=p5();return Hs(()=>{var a,l;if(!e)return t;const s=Object.assign({},o.components);Object.keys(e.components||{}).forEach(d=>{s[d]=Object.assign(Object.assign({},s[d]),e.components[d])});const c=`css-var-${i.replace(/:/g,"")}`,u=((a=r.cssVar)!==null&&a!==void 0?a:o.cssVar)&&Object.assign(Object.assign(Object.assign({prefix:"ant"},typeof o.cssVar=="object"?o.cssVar:{}),typeof r.cssVar=="object"?r.cssVar:{}),{key:typeof r.cssVar=="object"&&((l=r.cssVar)===null||l===void 0?void 0:l.key)||c});return Object.assign(Object.assign(Object.assign({},o),r),{token:Object.assign(Object.assign({},o.token),r.token),components:s,cssVar:u})},[r,o],(a,l)=>a.some((s,c)=>{const u=l[c];return!Vs(s,u,!0)}))}var h5=["children"],iw=f.exports.createContext({});function m5(e){var t=e.children,n=Je(e,h5);return C(iw.Provider,{value:n,children:t})}var y5=function(e){Bi(n,e);var t=Ws(n);function n(){return zn(this,n),t.apply(this,arguments)}return Fn(n,[{key:"render",value:function(){return this.props.children}}]),n}(f.exports.Component),vi="none",Rc="appear",Ic="enter",Pc="leave",Ny="none",Nr="prepare",xa="start",wa="active",qh="end",aw="prepared";function _y(e,t){var n={};return n[e.toLowerCase()]=t.toLowerCase(),n["Webkit".concat(e)]="webkit".concat(t),n["Moz".concat(e)]="moz".concat(t),n["ms".concat(e)]="MS".concat(t),n["O".concat(e)]="o".concat(t.toLowerCase()),n}function b5(e,t){var n={animationend:_y("Animation","AnimationEnd"),transitionend:_y("Transition","TransitionEnd")};return e&&("AnimationEvent"in t||delete n.animationend.animation,"TransitionEvent"in t||delete n.transitionend.transition),n}var S5=b5(Rn(),typeof window<"u"?window:{}),lw={};if(Rn()){var C5=document.createElement("div");lw=C5.style}var Tc={};function sw(e){if(Tc[e])return Tc[e];var t=S5[e];if(t)for(var n=Object.keys(t),r=n.length,o=0;o1&&arguments[1]!==void 0?arguments[1]:2;t();var i=St(function(){o<=1?r({isCanceled:function(){return i!==e.current}}):n(r,o-1)});e.current=i}return f.exports.useEffect(function(){return function(){t()}},[]),[n,t]};var $5=[Nr,xa,wa,qh],E5=[Nr,aw],vw=!1,M5=!0;function pw(e){return e===wa||e===qh}const O5=function(e,t,n){var r=_a(Ny),o=G(r,2),i=o[0],a=o[1],l=w5(),s=G(l,2),c=s[0],u=s[1];function d(){a(Nr,!0)}var v=t?E5:$5;return fw(function(){if(i!==Ny&&i!==qh){var h=v.indexOf(i),g=v[h+1],p=n(i);p===vw?a(g,!0):g&&c(function(b){function m(){b.isCanceled()||a(g,!0)}p===!0?m():Promise.resolve(p).then(m)})}},[e,i]),f.exports.useEffect(function(){return function(){u()}},[]),[d,i]};function R5(e,t,n,r){var o=r.motionEnter,i=o===void 0?!0:o,a=r.motionAppear,l=a===void 0?!0:a,s=r.motionLeave,c=s===void 0?!0:s,u=r.motionDeadline,d=r.motionLeaveImmediately,v=r.onAppearPrepare,h=r.onEnterPrepare,g=r.onLeavePrepare,p=r.onAppearStart,b=r.onEnterStart,m=r.onLeaveStart,y=r.onAppearActive,S=r.onEnterActive,x=r.onLeaveActive,$=r.onAppearEnd,E=r.onEnterEnd,w=r.onLeaveEnd,R=r.onVisibleChanged,P=_a(),N=G(P,2),I=N[0],z=N[1],F=_a(vi),T=G(F,2),D=T[0],_=T[1],O=_a(null),M=G(O,2),L=M[0],A=M[1],B=f.exports.useRef(!1),k=f.exports.useRef(null);function j(){return n()}var H=f.exports.useRef(!1);function W(){_(vi,!0),A(null,!0)}function Y(oe){var se=j();if(!(oe&&!oe.deadline&&oe.target!==se)){var le=H.current,Ce;D===Rc&&le?Ce=$==null?void 0:$(se,oe):D===Ic&&le?Ce=E==null?void 0:E(se,oe):D===Pc&&le&&(Ce=w==null?void 0:w(se,oe)),D!==vi&&le&&Ce!==!1&&W()}}var K=x5(Y),q=G(K,1),ee=q[0],Z=function(se){var le,Ce,ce;switch(se){case Rc:return le={},V(le,Nr,v),V(le,xa,p),V(le,wa,y),le;case Ic:return Ce={},V(Ce,Nr,h),V(Ce,xa,b),V(Ce,wa,S),Ce;case Pc:return ce={},V(ce,Nr,g),V(ce,xa,m),V(ce,wa,x),ce;default:return{}}},Q=f.exports.useMemo(function(){return Z(D)},[D]),ne=O5(D,!e,function(oe){if(oe===Nr){var se=Q[Nr];return se?se(j()):vw}if(re in Q){var le;A(((le=Q[re])===null||le===void 0?void 0:le.call(Q,j(),null))||null)}return re===wa&&(ee(j()),u>0&&(clearTimeout(k.current),k.current=setTimeout(function(){Y({deadline:!0})},u))),re===aw&&W(),M5}),ae=G(ne,2),J=ae[0],re=ae[1],fe=pw(re);H.current=fe,fw(function(){z(t);var oe=B.current;B.current=!0;var se;!oe&&t&&l&&(se=Rc),oe&&t&&i&&(se=Ic),(oe&&!t&&c||!oe&&d&&!t&&c)&&(se=Pc);var le=Z(se);se&&(e||le[Nr])?(_(se),J()):_(vi)},[t]),f.exports.useEffect(function(){(D===Rc&&!l||D===Ic&&!i||D===Pc&&!c)&&_(vi)},[l,i,c]),f.exports.useEffect(function(){return function(){B.current=!1,clearTimeout(k.current)}},[]);var ve=f.exports.useRef(!1);f.exports.useEffect(function(){I&&(ve.current=!0),I!==void 0&&D===vi&&((ve.current||I)&&(R==null||R(I)),ve.current=!0)},[I,D]);var pe=L;return Q[Nr]&&re===xa&&(pe=U({transition:"none"},pe)),[D,re,pe,I!=null?I:t]}function I5(e){var t=e;Qe(e)==="object"&&(t=e.transitionSupport);function n(o,i){return!!(o.motionName&&t&&i!==!1)}var r=f.exports.forwardRef(function(o,i){var a=o.visible,l=a===void 0?!0:a,s=o.removeOnLeave,c=s===void 0?!0:s,u=o.forceRender,d=o.children,v=o.motionName,h=o.leavedClassName,g=o.eventProps,p=f.exports.useContext(iw),b=p.motion,m=n(o,b),y=f.exports.useRef(),S=f.exports.useRef();function x(){try{return y.current instanceof HTMLElement?y.current:ql(S.current)}catch{return null}}var $=R5(m,l,x,o),E=G($,4),w=E[0],R=E[1],P=E[2],N=E[3],I=f.exports.useRef(N);N&&(I.current=!0);var z=f.exports.useCallback(function(A){y.current=A,zh(i,A)},[i]),F,T=U(U({},g),{},{visible:l});if(!d)F=null;else if(w===vi)N?F=d(U({},T),z):!c&&I.current&&h?F=d(U(U({},T),{},{className:h}),z):u||!c&&!h?F=d(U(U({},T),{},{style:{display:"none"}}),z):F=null;else{var D,_;R===Nr?_="prepare":pw(R)?_="active":R===xa&&(_="start");var O=Ly(v,"".concat(w,"-").concat(_));F=d(U(U({},T),{},{className:te(Ly(v,w),(D={},V(D,O,O&&_),V(D,v,typeof v=="string"),D)),style:P}),z)}if(f.exports.isValidElement(F)&&ki(F)){var M=F,L=M.ref;L||(F=f.exports.cloneElement(F,{ref:z}))}return C(y5,{ref:S,children:F})});return r.displayName="CSSMotion",r}const to=I5(dw);var Jp="add",eg="keep",tg="remove",av="removed";function P5(e){var t;return e&&Qe(e)==="object"&&"key"in e?t=e:t={key:e},U(U({},t),{},{key:String(t.key)})}function ng(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:[];return e.map(P5)}function T5(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:[],t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:[],n=[],r=0,o=t.length,i=ng(e),a=ng(t);i.forEach(function(c){for(var u=!1,d=r;d1});return s.forEach(function(c){n=n.filter(function(u){var d=u.key,v=u.status;return d!==c||v!==tg}),n.forEach(function(u){u.key===c&&(u.status=eg)})}),n}var N5=["component","children","onVisibleChanged","onAllRemoved"],_5=["status"],A5=["eventProps","visible","children","motionName","motionAppear","motionEnter","motionLeave","motionLeaveImmediately","motionDeadline","removeOnLeave","leavedClassName","onAppearPrepare","onAppearStart","onAppearActive","onAppearEnd","onEnterStart","onEnterActive","onEnterEnd","onLeaveStart","onLeaveActive","onLeaveEnd"];function D5(e){var t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:to,n=function(r){Bi(i,r);var o=Ws(i);function i(){var a;zn(this,i);for(var l=arguments.length,s=new Array(l),c=0;cnull;var F5=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);ot.endsWith("Color"))}const W5=e=>{const{prefixCls:t,iconPrefixCls:n,theme:r,holderRender:o}=e;t!==void 0&&(gw=t),r&&H5(r)&&W3(j5(),r)},V5=e=>{const{children:t,csp:n,autoInsertSpaceInButton:r,alert:o,anchor:i,form:a,locale:l,componentSize:s,direction:c,space:u,virtual:d,dropdownMatchSelectWidth:v,popupMatchSelectWidth:h,popupOverflow:g,legacyLocale:p,parentContext:b,iconPrefixCls:m,theme:y,componentDisabled:S,segmented:x,statistic:$,spin:E,calendar:w,carousel:R,cascader:P,collapse:N,typography:I,checkbox:z,descriptions:F,divider:T,drawer:D,skeleton:_,steps:O,image:M,layout:L,list:A,mentions:B,modal:k,progress:j,result:H,slider:W,breadcrumb:Y,menu:K,pagination:q,input:ee,empty:Z,badge:Q,radio:ne,rate:ae,switch:J,transfer:re,avatar:fe,message:ve,tag:pe,table:oe,card:se,tabs:le,timeline:Ce,timePicker:ce,upload:de,notification:xe,tree:he,colorPicker:ke,datePicker:we,rangePicker:ge,flex:Pe,wave:Se,dropdown:st,warning:nt,tour:Ne}=e,Ee=f.exports.useCallback((Re,be)=>{const{prefixCls:Ae}=e;if(be)return be;const Me=Ae||b.getPrefixCls("");return Re?`${Me}-${Re}`:Me},[b.getPrefixCls,e.prefixCls]),_e=m||b.iconPrefixCls||Gx,Be=n||b.csp;tw(_e,Be);const qe=g5(y,b.theme),it={csp:Be,autoInsertSpaceInButton:r,alert:o,anchor:i,locale:l||p,direction:c,space:u,virtual:d,popupMatchSelectWidth:h!=null?h:v,popupOverflow:g,getPrefixCls:Ee,iconPrefixCls:_e,theme:qe,segmented:x,statistic:$,spin:E,calendar:w,carousel:R,cascader:P,collapse:N,typography:I,checkbox:z,descriptions:F,divider:T,drawer:D,skeleton:_,steps:O,image:M,input:ee,layout:L,list:A,mentions:B,modal:k,progress:j,result:H,slider:W,breadcrumb:Y,menu:K,pagination:q,empty:Z,badge:Q,radio:ne,rate:ae,switch:J,transfer:re,avatar:fe,message:ve,tag:pe,table:oe,card:se,tabs:le,timeline:Ce,timePicker:ce,upload:de,notification:xe,tree:he,colorPicker:ke,datePicker:we,rangePicker:ge,flex:Pe,wave:Se,dropdown:st,warning:nt,tour:Ne},ft=Object.assign({},b);Object.keys(it).forEach(Re=>{it[Re]!==void 0&&(ft[Re]=it[Re])}),k5.forEach(Re=>{const be=e[Re];be&&(ft[Re]=be)});const ut=Hs(()=>ft,ft,(Re,be)=>{const Ae=Object.keys(Re),Me=Object.keys(be);return Ae.length!==Me.length||Ae.some($e=>Re[$e]!==be[$e])}),Ue=f.exports.useMemo(()=>({prefixCls:_e,csp:Be}),[_e,Be]);let He=ie(Tt,{children:[C(z5,{dropdownMatchSelectWidth:v}),t]});const Xe=f.exports.useMemo(()=>{var Re,be,Ae,Me;return Ca(((Re=Jo.Form)===null||Re===void 0?void 0:Re.defaultValidateMessages)||{},((Ae=(be=ut.locale)===null||be===void 0?void 0:be.Form)===null||Ae===void 0?void 0:Ae.defaultValidateMessages)||{},((Me=ut.form)===null||Me===void 0?void 0:Me.validateMessages)||{},(a==null?void 0:a.validateMessages)||{})},[ut,a==null?void 0:a.validateMessages]);Object.keys(Xe).length>0&&(He=C(p3.Provider,{value:Xe,children:He})),l&&(He=C(E3,{locale:l,_ANT_MARK__:w3,children:He})),(_e||Be)&&(He=C(Th.Provider,{value:Ue,children:He})),s&&(He=C(U3,{size:s,children:He})),He=C(L5,{children:He});const Le=f.exports.useMemo(()=>{const Re=qe||{},{algorithm:be,token:Ae,components:Me,cssVar:$e}=Re,Te=F5(Re,["algorithm","token","components","cssVar"]),ye=be&&(!Array.isArray(be)||be.length>0)?Bp(be):Ux,Ge={};Object.entries(Me||{}).forEach(et=>{let[ht,mt]=et;const ct=Object.assign({},mt);"algorithm"in ct&&(ct.algorithm===!0?ct.theme=ye:(Array.isArray(ct.algorithm)||typeof ct.algorithm=="function")&&(ct.theme=Bp(ct.algorithm)),delete ct.algorithm),Ge[ht]=ct});const Ze=Object.assign(Object.assign({},ws),Ae);return Object.assign(Object.assign({},Te),{theme:ye,token:Ze,components:Ge,override:Object.assign({override:Ze},Ge),cssVar:$e})},[qe]);return y&&(He=C(Yx.Provider,{value:Le,children:He})),ut.warning&&(He=C(v3.Provider,{value:ut.warning,children:He})),S!==void 0&&(He=C(V3,{disabled:S,children:He})),C(ot.Provider,{value:ut,children:He})},ai=e=>{const t=f.exports.useContext(ot),n=f.exports.useContext(Vh);return C(V5,{...Object.assign({parentContext:t,legacyLocale:n},e)})};ai.ConfigContext=ot;ai.SizeContext=qd;ai.config=W5;ai.useConfig=Y3;Object.defineProperty(ai,"SizeContext",{get:()=>qd});var U5=`accept acceptCharset accessKey action allowFullScreen allowTransparency + alt async autoComplete autoFocus autoPlay capture cellPadding cellSpacing challenge + charSet checked classID className colSpan cols content contentEditable contextMenu + controls coords crossOrigin data dateTime default defer dir disabled download draggable + encType form formAction formEncType formMethod formNoValidate formTarget frameBorder + headers height hidden high href hrefLang htmlFor httpEquiv icon id inputMode integrity + is keyParams keyType kind label lang list loop low manifest marginHeight marginWidth max maxLength media + mediaGroup method min minLength multiple muted name noValidate nonce open + optimum pattern placeholder poster preload radioGroup readOnly rel required + reversed role rowSpan rows sandbox scope scoped scrolling seamless selected + shape size sizes span spellCheck src srcDoc srcLang srcSet start step style + summary tabIndex target title type useMap value width wmode wrap`,Y5=`onCopy onCut onPaste onCompositionEnd onCompositionStart onCompositionUpdate onKeyDown + onKeyPress onKeyUp onFocus onBlur onChange onInput onSubmit onClick onContextMenu onDoubleClick + onDrag onDragEnd onDragEnter onDragExit onDragLeave onDragOver onDragStart onDrop onMouseDown + onMouseEnter onMouseLeave onMouseMove onMouseOut onMouseOver onMouseUp onSelect onTouchCancel + onTouchEnd onTouchMove onTouchStart onScroll onWheel onAbort onCanPlay onCanPlayThrough + onDurationChange onEmptied onEncrypted onEnded onError onLoadedData onLoadedMetadata + onLoadStart onPause onPlay onPlaying onProgress onRateChange onSeeked onSeeking onStalled onSuspend onTimeUpdate onVolumeChange onWaiting onLoad onError`,G5="".concat(U5," ").concat(Y5).split(/[\s\n]+/),K5="aria-",q5="data-";function zy(e,t){return e.indexOf(t)===0}function Ka(e){var t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1,n;t===!1?n={aria:!0,data:!0,attr:!0}:t===!0?n={aria:!0}:n=U({},t);var r={};return Object.keys(e).forEach(function(o){(n.aria&&(o==="role"||zy(o,K5))||n.data&&zy(o,q5)||n.attr&&G5.includes(o))&&(r[o]=e[o])}),r}const{isValidElement:Es}=As;function hw(e){return e&&Es(e)&&e.type===f.exports.Fragment}function X5(e,t,n){return Es(e)?f.exports.cloneElement(e,typeof n=="function"?n(e.props||{}):n):t}function ti(e,t){return X5(e,e,t)}const Q5=e=>{const[,,,,t]=Kn();return t?`${e}-css-var`:""},no=Q5;var ue={MAC_ENTER:3,BACKSPACE:8,TAB:9,NUM_CENTER:12,ENTER:13,SHIFT:16,CTRL:17,ALT:18,PAUSE:19,CAPS_LOCK:20,ESC:27,SPACE:32,PAGE_UP:33,PAGE_DOWN:34,END:35,HOME:36,LEFT:37,UP:38,RIGHT:39,DOWN:40,PRINT_SCREEN:44,INSERT:45,DELETE:46,ZERO:48,ONE:49,TWO:50,THREE:51,FOUR:52,FIVE:53,SIX:54,SEVEN:55,EIGHT:56,NINE:57,QUESTION_MARK:63,A:65,B:66,C:67,D:68,E:69,F:70,G:71,H:72,I:73,J:74,K:75,L:76,M:77,N:78,O:79,P:80,Q:81,R:82,S:83,T:84,U:85,V:86,W:87,X:88,Y:89,Z:90,META:91,WIN_KEY_RIGHT:92,CONTEXT_MENU:93,NUM_ZERO:96,NUM_ONE:97,NUM_TWO:98,NUM_THREE:99,NUM_FOUR:100,NUM_FIVE:101,NUM_SIX:102,NUM_SEVEN:103,NUM_EIGHT:104,NUM_NINE:105,NUM_MULTIPLY:106,NUM_PLUS:107,NUM_MINUS:109,NUM_PERIOD:110,NUM_DIVISION:111,F1:112,F2:113,F3:114,F4:115,F5:116,F6:117,F7:118,F8:119,F9:120,F10:121,F11:122,F12:123,NUMLOCK:144,SEMICOLON:186,DASH:189,EQUALS:187,COMMA:188,PERIOD:190,SLASH:191,APOSTROPHE:192,SINGLE_QUOTE:222,OPEN_SQUARE_BRACKET:219,BACKSLASH:220,CLOSE_SQUARE_BRACKET:221,WIN_KEY:224,MAC_FF_META:224,WIN_IME:229,isTextModifyingKeyEvent:function(t){var n=t.keyCode;if(t.altKey&&!t.ctrlKey||t.metaKey||n>=ue.F1&&n<=ue.F12)return!1;switch(n){case ue.ALT:case ue.CAPS_LOCK:case ue.CONTEXT_MENU:case ue.CTRL:case ue.DOWN:case ue.END:case ue.ESC:case ue.HOME:case ue.INSERT:case ue.LEFT:case ue.MAC_FF_META:case ue.META:case ue.NUMLOCK:case ue.NUM_CENTER:case ue.PAGE_DOWN:case ue.PAGE_UP:case ue.PAUSE:case ue.PRINT_SCREEN:case ue.RIGHT:case ue.SHIFT:case ue.UP:case ue.WIN_KEY:case ue.WIN_KEY_RIGHT:return!1;default:return!0}},isCharacterKey:function(t){if(t>=ue.ZERO&&t<=ue.NINE||t>=ue.NUM_ZERO&&t<=ue.NUM_MULTIPLY||t>=ue.A&&t<=ue.Z||window.navigator.userAgent.indexOf("WebKit")!==-1&&t===0)return!0;switch(t){case ue.SPACE:case ue.QUESTION_MARK:case ue.NUM_PLUS:case ue.NUM_MINUS:case ue.NUM_PERIOD:case ue.NUM_DIVISION:case ue.SEMICOLON:case ue.DASH:case ue.EQUALS:case ue.COMMA:case ue.PERIOD:case ue.SLASH:case ue.APOSTROPHE:case ue.SINGLE_QUOTE:case ue.OPEN_SQUARE_BRACKET:case ue.BACKSLASH:case ue.CLOSE_SQUARE_BRACKET:return!0;default:return!1}}};const Z5=lt.createContext(void 0),mw=Z5,pi=100,J5=10,eN=pi*J5,yw={Modal:pi,Drawer:pi,Popover:pi,Popconfirm:pi,Tooltip:pi,Tour:pi},tN={SelectLike:50,Dropdown:50,DatePicker:50,Menu:50,ImagePreview:1};function nN(e){return e in yw}function Qd(e,t){const[,n]=Kn(),r=lt.useContext(mw),o=nN(e);if(t!==void 0)return[t,t];let i=r!=null?r:0;return o?(i+=(r?0:n.zIndexPopupBase)+yw[e],i=Math.min(i,n.zIndexPopupBase+eN)):i+=tN[e],[r===void 0?t:i,i]}function An(){An=function(){return t};var e,t={},n=Object.prototype,r=n.hasOwnProperty,o=Object.defineProperty||function(_,O,M){_[O]=M.value},i=typeof Symbol=="function"?Symbol:{},a=i.iterator||"@@iterator",l=i.asyncIterator||"@@asyncIterator",s=i.toStringTag||"@@toStringTag";function c(_,O,M){return Object.defineProperty(_,O,{value:M,enumerable:!0,configurable:!0,writable:!0}),_[O]}try{c({},"")}catch{c=function(M,L,A){return M[L]=A}}function u(_,O,M,L){var A=O&&O.prototype instanceof m?O:m,B=Object.create(A.prototype),k=new T(L||[]);return o(B,"_invoke",{value:N(_,M,k)}),B}function d(_,O,M){try{return{type:"normal",arg:_.call(O,M)}}catch(L){return{type:"throw",arg:L}}}t.wrap=u;var v="suspendedStart",h="suspendedYield",g="executing",p="completed",b={};function m(){}function y(){}function S(){}var x={};c(x,a,function(){return this});var $=Object.getPrototypeOf,E=$&&$($(D([])));E&&E!==n&&r.call(E,a)&&(x=E);var w=S.prototype=m.prototype=Object.create(x);function R(_){["next","throw","return"].forEach(function(O){c(_,O,function(M){return this._invoke(O,M)})})}function P(_,O){function M(A,B,k,j){var H=d(_[A],_,B);if(H.type!=="throw"){var W=H.arg,Y=W.value;return Y&&Qe(Y)=="object"&&r.call(Y,"__await")?O.resolve(Y.__await).then(function(K){M("next",K,k,j)},function(K){M("throw",K,k,j)}):O.resolve(Y).then(function(K){W.value=K,k(W)},function(K){return M("throw",K,k,j)})}j(H.arg)}var L;o(this,"_invoke",{value:function(B,k){function j(){return new O(function(H,W){M(B,k,H,W)})}return L=L?L.then(j,j):j()}})}function N(_,O,M){var L=v;return function(A,B){if(L===g)throw new Error("Generator is already running");if(L===p){if(A==="throw")throw B;return{value:e,done:!0}}for(M.method=A,M.arg=B;;){var k=M.delegate;if(k){var j=I(k,M);if(j){if(j===b)continue;return j}}if(M.method==="next")M.sent=M._sent=M.arg;else if(M.method==="throw"){if(L===v)throw L=p,M.arg;M.dispatchException(M.arg)}else M.method==="return"&&M.abrupt("return",M.arg);L=g;var H=d(_,O,M);if(H.type==="normal"){if(L=M.done?p:h,H.arg===b)continue;return{value:H.arg,done:M.done}}H.type==="throw"&&(L=p,M.method="throw",M.arg=H.arg)}}}function I(_,O){var M=O.method,L=_.iterator[M];if(L===e)return O.delegate=null,M==="throw"&&_.iterator.return&&(O.method="return",O.arg=e,I(_,O),O.method==="throw")||M!=="return"&&(O.method="throw",O.arg=new TypeError("The iterator does not provide a '"+M+"' method")),b;var A=d(L,_.iterator,O.arg);if(A.type==="throw")return O.method="throw",O.arg=A.arg,O.delegate=null,b;var B=A.arg;return B?B.done?(O[_.resultName]=B.value,O.next=_.nextLoc,O.method!=="return"&&(O.method="next",O.arg=e),O.delegate=null,b):B:(O.method="throw",O.arg=new TypeError("iterator result is not an object"),O.delegate=null,b)}function z(_){var O={tryLoc:_[0]};1 in _&&(O.catchLoc=_[1]),2 in _&&(O.finallyLoc=_[2],O.afterLoc=_[3]),this.tryEntries.push(O)}function F(_){var O=_.completion||{};O.type="normal",delete O.arg,_.completion=O}function T(_){this.tryEntries=[{tryLoc:"root"}],_.forEach(z,this),this.reset(!0)}function D(_){if(_||_===""){var O=_[a];if(O)return O.call(_);if(typeof _.next=="function")return _;if(!isNaN(_.length)){var M=-1,L=function A(){for(;++M<_.length;)if(r.call(_,M))return A.value=_[M],A.done=!1,A;return A.value=e,A.done=!0,A};return L.next=L}}throw new TypeError(Qe(_)+" is not iterable")}return y.prototype=S,o(w,"constructor",{value:S,configurable:!0}),o(S,"constructor",{value:y,configurable:!0}),y.displayName=c(S,s,"GeneratorFunction"),t.isGeneratorFunction=function(_){var O=typeof _=="function"&&_.constructor;return!!O&&(O===y||(O.displayName||O.name)==="GeneratorFunction")},t.mark=function(_){return Object.setPrototypeOf?Object.setPrototypeOf(_,S):(_.__proto__=S,c(_,s,"GeneratorFunction")),_.prototype=Object.create(w),_},t.awrap=function(_){return{__await:_}},R(P.prototype),c(P.prototype,l,function(){return this}),t.AsyncIterator=P,t.async=function(_,O,M,L,A){A===void 0&&(A=Promise);var B=new P(u(_,O,M,L),A);return t.isGeneratorFunction(O)?B:B.next().then(function(k){return k.done?k.value:B.next()})},R(w),c(w,s,"Generator"),c(w,a,function(){return this}),c(w,"toString",function(){return"[object Generator]"}),t.keys=function(_){var O=Object(_),M=[];for(var L in O)M.push(L);return M.reverse(),function A(){for(;M.length;){var B=M.pop();if(B in O)return A.value=B,A.done=!1,A}return A.done=!0,A}},t.values=D,T.prototype={constructor:T,reset:function(O){if(this.prev=0,this.next=0,this.sent=this._sent=e,this.done=!1,this.delegate=null,this.method="next",this.arg=e,this.tryEntries.forEach(F),!O)for(var M in this)M.charAt(0)==="t"&&r.call(this,M)&&!isNaN(+M.slice(1))&&(this[M]=e)},stop:function(){this.done=!0;var O=this.tryEntries[0].completion;if(O.type==="throw")throw O.arg;return this.rval},dispatchException:function(O){if(this.done)throw O;var M=this;function L(W,Y){return k.type="throw",k.arg=O,M.next=W,Y&&(M.method="next",M.arg=e),!!Y}for(var A=this.tryEntries.length-1;A>=0;--A){var B=this.tryEntries[A],k=B.completion;if(B.tryLoc==="root")return L("end");if(B.tryLoc<=this.prev){var j=r.call(B,"catchLoc"),H=r.call(B,"finallyLoc");if(j&&H){if(this.prev=0;--L){var A=this.tryEntries[L];if(A.tryLoc<=this.prev&&r.call(A,"finallyLoc")&&this.prev=0;--M){var L=this.tryEntries[M];if(L.finallyLoc===O)return this.complete(L.completion,L.afterLoc),F(L),b}},catch:function(O){for(var M=this.tryEntries.length-1;M>=0;--M){var L=this.tryEntries[M];if(L.tryLoc===O){var A=L.completion;if(A.type==="throw"){var B=A.arg;F(L)}return B}}throw new Error("illegal catch attempt")},delegateYield:function(O,M,L){return this.delegate={iterator:D(O),resultName:M,nextLoc:L},this.method==="next"&&(this.arg=e),b}},t}function Fy(e,t,n,r,o,i,a){try{var l=e[i](a),s=l.value}catch(c){n(c);return}l.done?t(s):Promise.resolve(s).then(r,o)}function ji(e){return function(){var t=this,n=arguments;return new Promise(function(r,o){var i=e.apply(t,n);function a(s){Fy(i,r,o,a,l,"next",s)}function l(s){Fy(i,r,o,a,l,"throw",s)}a(void 0)})}}var Ys=U({},$O),rN=Ys.version,oN=Ys.render,iN=Ys.unmountComponentAtNode,Zd;try{var aN=Number((rN||"").split(".")[0]);aN>=18&&(Zd=Ys.createRoot)}catch{}function ky(e){var t=Ys.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;t&&Qe(t)==="object"&&(t.usingClientEntryPoint=e)}var Ku="__rc_react_root__";function lN(e,t){ky(!0);var n=t[Ku]||Zd(t);ky(!1),n.render(e),t[Ku]=n}function sN(e,t){oN(e,t)}function cN(e,t){if(Zd){lN(e,t);return}sN(e,t)}function uN(e){return rg.apply(this,arguments)}function rg(){return rg=ji(An().mark(function e(t){return An().wrap(function(r){for(;;)switch(r.prev=r.next){case 0:return r.abrupt("return",Promise.resolve().then(function(){var o;(o=t[Ku])===null||o===void 0||o.unmount(),delete t[Ku]}));case 1:case"end":return r.stop()}},e)})),rg.apply(this,arguments)}function dN(e){iN(e)}function fN(e){return og.apply(this,arguments)}function og(){return og=ji(An().mark(function e(t){return An().wrap(function(r){for(;;)switch(r.prev=r.next){case 0:if(Zd===void 0){r.next=2;break}return r.abrupt("return",uN(t));case 2:dN(t);case 3:case"end":return r.stop()}},e)})),og.apply(this,arguments)}const ni=(e,t,n)=>n!==void 0?n:`${e}-${t}`,Jd=function(e){if(!e)return!1;if(e instanceof Element){if(e.offsetParent)return!0;if(e.getBBox){var t=e.getBBox(),n=t.width,r=t.height;if(n||r)return!0}if(e.getBoundingClientRect){var o=e.getBoundingClientRect(),i=o.width,a=o.height;if(i||a)return!0}}return!1},vN=e=>{const{componentCls:t,colorPrimary:n}=e;return{[t]:{position:"absolute",background:"transparent",pointerEvents:"none",boxSizing:"border-box",color:`var(--wave-color, ${n})`,boxShadow:"0 0 0 0 currentcolor",opacity:.2,"&.wave-motion-appear":{transition:[`box-shadow 0.4s ${e.motionEaseOutCirc}`,`opacity 2s ${e.motionEaseOutCirc}`].join(","),"&-active":{boxShadow:"0 0 0 6px currentcolor",opacity:0},"&.wave-quick":{transition:[`box-shadow 0.3s ${e.motionEaseInOut}`,`opacity 0.35s ${e.motionEaseInOut}`].join(",")}}}}},pN=Gh("Wave",e=>[vN(e)]);function gN(e){const t=(e||"").match(/rgba?\((\d*), (\d*), (\d*)(, [\d.]*)?\)/);return t&&t[1]&&t[2]&&t[3]?!(t[1]===t[2]&&t[2]===t[3]):!0}function lv(e){return e&&e!=="#fff"&&e!=="#ffffff"&&e!=="rgb(255, 255, 255)"&&e!=="rgba(255, 255, 255, 1)"&&gN(e)&&!/rgba\((?:\d*, ){3}0\)/.test(e)&&e!=="transparent"}function hN(e){const{borderTopColor:t,borderColor:n,backgroundColor:r}=getComputedStyle(e);return lv(t)?t:lv(n)?n:lv(r)?r:null}const Xh="ant-wave-target";function sv(e){return Number.isNaN(e)?0:e}const mN=e=>{const{className:t,target:n,component:r}=e,o=f.exports.useRef(null),[i,a]=f.exports.useState(null),[l,s]=f.exports.useState([]),[c,u]=f.exports.useState(0),[d,v]=f.exports.useState(0),[h,g]=f.exports.useState(0),[p,b]=f.exports.useState(0),[m,y]=f.exports.useState(!1),S={left:c,top:d,width:h,height:p,borderRadius:l.map(E=>`${E}px`).join(" ")};i&&(S["--wave-color"]=i);function x(){const E=getComputedStyle(n);a(hN(n));const w=E.position==="static",{borderLeftWidth:R,borderTopWidth:P}=E;u(w?n.offsetLeft:sv(-parseFloat(R))),v(w?n.offsetTop:sv(-parseFloat(P))),g(n.offsetWidth),b(n.offsetHeight);const{borderTopLeftRadius:N,borderTopRightRadius:I,borderBottomLeftRadius:z,borderBottomRightRadius:F}=E;s([N,I,F,z].map(T=>sv(parseFloat(T))))}if(f.exports.useEffect(()=>{if(n){const E=St(()=>{x(),y(!0)});let w;return typeof ResizeObserver<"u"&&(w=new ResizeObserver(x),w.observe(n)),()=>{St.cancel(E),w==null||w.disconnect()}}},[]),!m)return null;const $=(r==="Checkbox"||r==="Radio")&&(n==null?void 0:n.classList.contains(Xh));return C(to,{visible:!0,motionAppear:!0,motionName:"wave-motion",motionDeadline:5e3,onAppearEnd:(E,w)=>{var R;if(w.deadline||w.propertyName==="opacity"){const P=(R=o.current)===null||R===void 0?void 0:R.parentElement;fN(P).then(()=>{P==null||P.remove()})}return!1},children:E=>{let{className:w}=E;return C("div",{ref:o,className:te(t,{"wave-quick":$},w),style:S})}})},yN=(e,t)=>{var n;const{component:r}=t;if(r==="Checkbox"&&!(!((n=e.querySelector("input"))===null||n===void 0)&&n.checked))return;const o=document.createElement("div");o.style.position="absolute",o.style.left="0px",o.style.top="0px",e==null||e.insertBefore(o,e==null?void 0:e.firstChild),cN(C(mN,{...Object.assign({},t,{target:e})}),o)},bN=yN;function SN(e,t,n){const{wave:r}=f.exports.useContext(ot),[,o,i]=Kn(),a=hn(c=>{const u=e.current;if((r==null?void 0:r.disabled)||!u)return;const d=u.querySelector(`.${Xh}`)||u,{showEffect:v}=r||{};(v||bN)(d,{className:t,token:o,component:n,event:c,hashId:i})}),l=f.exports.useRef();return c=>{St.cancel(l.current),l.current=St(()=>{a(c)})}}const CN=e=>{const{children:t,disabled:n,component:r}=e,{getPrefixCls:o}=f.exports.useContext(ot),i=f.exports.useRef(null),a=o("wave"),[,l]=pN(a),s=SN(i,te(a,l),r);if(lt.useEffect(()=>{const u=i.current;if(!u||u.nodeType!==1||n)return;const d=v=>{!Jd(v.target)||!u.getAttribute||u.getAttribute("disabled")||u.disabled||u.className.includes("disabled")||u.className.includes("-leave")||s(v)};return u.addEventListener("click",d,!0),()=>{u.removeEventListener("click",d,!0)}},[n]),!lt.isValidElement(t))return t!=null?t:null;const c=ki(t)?xr(t.ref,i):i;return ti(t,{ref:c})},Qh=CN,xN=e=>{const t=lt.useContext(qd);return lt.useMemo(()=>e?typeof e=="string"?e!=null?e:t:e instanceof Function?e(t):t:t,[e,t])},So=xN;globalThis&&globalThis.__rest;const bw=f.exports.createContext(null),ef=(e,t)=>{const n=f.exports.useContext(bw),r=f.exports.useMemo(()=>{if(!n)return"";const{compactDirection:o,isFirstItem:i,isLastItem:a}=n,l=o==="vertical"?"-vertical-":"-";return te(`${e}-compact${l}item`,{[`${e}-compact${l}first-item`]:i,[`${e}-compact${l}last-item`]:a,[`${e}-compact${l}item-rtl`]:t==="rtl"})},[e,t,n]);return{compactSize:n==null?void 0:n.compactSize,compactDirection:n==null?void 0:n.compactDirection,compactItemClassnames:r}},ig=e=>{let{children:t}=e;return C(bw.Provider,{value:null,children:t})};var wN=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{const{getPrefixCls:t,direction:n}=f.exports.useContext(ot),{prefixCls:r,size:o,className:i}=e,a=wN(e,["prefixCls","size","className"]),l=t("btn-group",r),[,,s]=Kn();let c="";switch(o){case"large":c="lg";break;case"small":c="sm";break}const u=te(l,{[`${l}-${c}`]:c,[`${l}-rtl`]:n==="rtl"},i,s);return C(Sw.Provider,{value:o,children:C("div",{...Object.assign({},a,{className:u})})})},EN=$N,By=/^[\u4e00-\u9fa5]{2}$/,ag=By.test.bind(By);function jy(e){return typeof e=="string"}function cv(e){return e==="text"||e==="link"}function MN(e,t){if(e==null)return;const n=t?" ":"";return typeof e!="string"&&typeof e!="number"&&jy(e.type)&&ag(e.props.children)?ti(e,{children:e.props.children.split("").join(n)}):jy(e)?ag(e)?C("span",{children:e.split("").join(n)}):C("span",{children:e}):hw(e)?C("span",{children:e}):e}function ON(e,t){let n=!1;const r=[];return lt.Children.forEach(e,o=>{const i=typeof o,a=i==="string"||i==="number";if(n&&a){const l=r.length-1,s=r[l];r[l]=`${s}${o}`}else r.push(o);n=a}),lt.Children.map(r,o=>MN(o,t))}const RN=f.exports.forwardRef((e,t)=>{const{className:n,style:r,children:o,prefixCls:i}=e,a=te(`${i}-icon`,n);return C("span",{ref:t,className:a,style:r,children:o})}),Cw=RN,Hy=f.exports.forwardRef((e,t)=>{let{prefixCls:n,className:r,style:o,iconClassName:i}=e;const a=te(`${n}-loading-icon`,r);return C(Cw,{prefixCls:n,className:a,style:o,ref:t,children:C(ux,{className:i})})}),uv=()=>({width:0,opacity:0,transform:"scale(0)"}),dv=e=>({width:e.scrollWidth,opacity:1,transform:"scale(1)"}),IN=e=>{const{prefixCls:t,loading:n,existIcon:r,className:o,style:i}=e,a=!!n;return r?C(Hy,{prefixCls:t,className:o,style:i}):C(to,{visible:a,motionName:`${t}-loading-icon-motion`,motionLeave:a,removeOnLeave:!0,onAppearStart:uv,onAppearActive:dv,onEnterStart:uv,onEnterActive:dv,onLeaveStart:dv,onLeaveActive:uv,children:(l,s)=>{let{className:c,style:u}=l;return C(Hy,{prefixCls:t,className:o,style:Object.assign(Object.assign({},i),u),ref:s,iconClassName:c})}})},PN=IN,Wy=(e,t)=>({[`> span, > ${e}`]:{"&:not(:last-child)":{[`&, & > ${e}`]:{"&:not(:disabled)":{borderInlineEndColor:t}}},"&:not(:first-child)":{[`&, & > ${e}`]:{"&:not(:disabled)":{borderInlineStartColor:t}}}}}),TN=e=>{const{componentCls:t,fontSize:n,lineWidth:r,groupBorderColor:o,colorErrorHover:i}=e;return{[`${t}-group`]:[{position:"relative",display:"inline-flex",[`> span, > ${t}`]:{"&:not(:last-child)":{[`&, & > ${t}`]:{borderStartEndRadius:0,borderEndEndRadius:0}},"&:not(:first-child)":{marginInlineStart:e.calc(r).mul(-1).equal(),[`&, & > ${t}`]:{borderStartStartRadius:0,borderEndStartRadius:0}}},[t]:{position:"relative",zIndex:1,[`&:hover, + &:focus, + &:active`]:{zIndex:2},"&[disabled]":{zIndex:0}},[`${t}-icon-only`]:{fontSize:n}},Wy(`${t}-primary`,o),Wy(`${t}-danger`,i)]}},NN=TN,xw=e=>{const{paddingInline:t,onlyIconSize:n,paddingBlock:r}=e;return $t(e,{buttonPaddingHorizontal:t,buttonPaddingVertical:r,buttonIconOnlyFontSize:n})},ww=e=>{var t,n,r,o,i,a;const l=(t=e.contentFontSize)!==null&&t!==void 0?t:e.fontSize,s=(n=e.contentFontSizeSM)!==null&&n!==void 0?n:e.fontSize,c=(r=e.contentFontSizeLG)!==null&&r!==void 0?r:e.fontSizeLG,u=(o=e.contentLineHeight)!==null&&o!==void 0?o:ou(l),d=(i=e.contentLineHeightSM)!==null&&i!==void 0?i:ou(s),v=(a=e.contentLineHeightLG)!==null&&a!==void 0?a:ou(c);return{fontWeight:400,defaultShadow:`0 ${e.controlOutlineWidth}px 0 ${e.controlTmpOutline}`,primaryShadow:`0 ${e.controlOutlineWidth}px 0 ${e.controlOutline}`,dangerShadow:`0 ${e.controlOutlineWidth}px 0 ${e.colorErrorOutline}`,primaryColor:e.colorTextLightSolid,dangerColor:e.colorTextLightSolid,borderColorDisabled:e.colorBorder,defaultGhostColor:e.colorBgContainer,ghostBg:"transparent",defaultGhostBorderColor:e.colorBgContainer,paddingInline:e.paddingContentHorizontal-e.lineWidth,paddingInlineLG:e.paddingContentHorizontal-e.lineWidth,paddingInlineSM:8-e.lineWidth,onlyIconSize:e.fontSizeLG,onlyIconSizeSM:e.fontSizeLG-2,onlyIconSizeLG:e.fontSizeLG+2,groupBorderColor:e.colorPrimaryHover,linkHoverBg:"transparent",textHoverBg:e.colorBgTextHover,defaultColor:e.colorText,defaultBg:e.colorBgContainer,defaultBorderColor:e.colorBorder,defaultBorderColorDisabled:e.colorBorder,defaultHoverBg:e.colorBgContainer,defaultHoverColor:e.colorPrimaryHover,defaultHoverBorderColor:e.colorPrimaryHover,defaultActiveBg:e.colorBgContainer,defaultActiveColor:e.colorPrimaryActive,defaultActiveBorderColor:e.colorPrimaryActive,contentFontSize:l,contentFontSizeSM:s,contentFontSizeLG:c,contentLineHeight:u,contentLineHeightSM:d,contentLineHeightLG:v,paddingBlock:Math.max((e.controlHeight-l*u)/2-e.lineWidth,0),paddingBlockSM:Math.max((e.controlHeightSM-s*d)/2-e.lineWidth,0),paddingBlockLG:Math.max((e.controlHeightLG-c*v)/2-e.lineWidth,0)}},_N=e=>{const{componentCls:t,iconCls:n,fontWeight:r}=e;return{[t]:{outline:"none",position:"relative",display:"inline-block",fontWeight:r,whiteSpace:"nowrap",textAlign:"center",backgroundImage:"none",background:"transparent",border:`${X(e.lineWidth)} ${e.lineType} transparent`,cursor:"pointer",transition:`all ${e.motionDurationMid} ${e.motionEaseInOut}`,userSelect:"none",touchAction:"manipulation",color:e.colorText,"&:disabled > *":{pointerEvents:"none"},"> span":{display:"inline-block"},[`${t}-icon`]:{lineHeight:0},[`> ${n} + span, > span + ${n}`]:{marginInlineStart:e.marginXS},[`&:not(${t}-icon-only) > ${t}-icon`]:{[`&${t}-loading-icon, &:not(:last-child)`]:{marginInlineEnd:e.marginXS}},"> a":{color:"currentColor"},"&:not(:disabled)":Object.assign({},Xd(e)),[`&${t}-two-chinese-chars::first-letter`]:{letterSpacing:"0.34em"},[`&${t}-two-chinese-chars > *:not(${n})`]:{marginInlineEnd:"-0.34em",letterSpacing:"0.34em"},[`&-icon-only${t}-compact-item`]:{flex:"none"}}}},yo=(e,t,n)=>({[`&:not(:disabled):not(${e}-disabled)`]:{"&:hover":t,"&:active":n}}),AN=e=>({minWidth:e.controlHeight,paddingInlineStart:0,paddingInlineEnd:0,borderRadius:"50%"}),DN=e=>({borderRadius:e.controlHeight,paddingInlineStart:e.calc(e.controlHeight).div(2).equal(),paddingInlineEnd:e.calc(e.controlHeight).div(2).equal()}),LN=e=>({cursor:"not-allowed",borderColor:e.borderColorDisabled,color:e.colorTextDisabled,background:e.colorBgContainerDisabled,boxShadow:"none"}),Ms=(e,t,n,r,o,i,a,l)=>({[`&${e}-background-ghost`]:Object.assign(Object.assign({color:n||void 0,background:t,borderColor:r||void 0,boxShadow:"none"},yo(e,Object.assign({background:t},a),Object.assign({background:t},l))),{"&:disabled":{cursor:"not-allowed",color:o||void 0,borderColor:i||void 0}})}),Zh=e=>({[`&:disabled, &${e.componentCls}-disabled`]:Object.assign({},LN(e))}),$w=e=>Object.assign({},Zh(e)),qu=e=>({[`&:disabled, &${e.componentCls}-disabled`]:{cursor:"not-allowed",color:e.colorTextDisabled}}),Ew=e=>Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({},$w(e)),{background:e.defaultBg,borderColor:e.defaultBorderColor,color:e.defaultColor,boxShadow:e.defaultShadow}),yo(e.componentCls,{color:e.defaultHoverColor,borderColor:e.defaultHoverBorderColor,background:e.defaultHoverBg},{color:e.defaultActiveColor,borderColor:e.defaultActiveBorderColor,background:e.defaultActiveBg})),Ms(e.componentCls,e.ghostBg,e.defaultGhostColor,e.defaultGhostBorderColor,e.colorTextDisabled,e.colorBorder)),{[`&${e.componentCls}-dangerous`]:Object.assign(Object.assign(Object.assign({color:e.colorError,borderColor:e.colorError},yo(e.componentCls,{color:e.colorErrorHover,borderColor:e.colorErrorBorderHover},{color:e.colorErrorActive,borderColor:e.colorErrorActive})),Ms(e.componentCls,e.ghostBg,e.colorError,e.colorError,e.colorTextDisabled,e.colorBorder)),Zh(e))}),zN=e=>Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({},$w(e)),{color:e.primaryColor,background:e.colorPrimary,boxShadow:e.primaryShadow}),yo(e.componentCls,{color:e.colorTextLightSolid,background:e.colorPrimaryHover},{color:e.colorTextLightSolid,background:e.colorPrimaryActive})),Ms(e.componentCls,e.ghostBg,e.colorPrimary,e.colorPrimary,e.colorTextDisabled,e.colorBorder,{color:e.colorPrimaryHover,borderColor:e.colorPrimaryHover},{color:e.colorPrimaryActive,borderColor:e.colorPrimaryActive})),{[`&${e.componentCls}-dangerous`]:Object.assign(Object.assign(Object.assign({background:e.colorError,boxShadow:e.dangerShadow,color:e.dangerColor},yo(e.componentCls,{background:e.colorErrorHover},{background:e.colorErrorActive})),Ms(e.componentCls,e.ghostBg,e.colorError,e.colorError,e.colorTextDisabled,e.colorBorder,{color:e.colorErrorHover,borderColor:e.colorErrorHover},{color:e.colorErrorActive,borderColor:e.colorErrorActive})),Zh(e))}),FN=e=>Object.assign(Object.assign({},Ew(e)),{borderStyle:"dashed"}),kN=e=>Object.assign(Object.assign(Object.assign({color:e.colorLink},yo(e.componentCls,{color:e.colorLinkHover,background:e.linkHoverBg},{color:e.colorLinkActive})),qu(e)),{[`&${e.componentCls}-dangerous`]:Object.assign(Object.assign({color:e.colorError},yo(e.componentCls,{color:e.colorErrorHover},{color:e.colorErrorActive})),qu(e))}),BN=e=>Object.assign(Object.assign(Object.assign({},yo(e.componentCls,{color:e.colorText,background:e.textHoverBg},{color:e.colorText,background:e.colorBgTextActive})),qu(e)),{[`&${e.componentCls}-dangerous`]:Object.assign(Object.assign({color:e.colorError},qu(e)),yo(e.componentCls,{color:e.colorErrorHover,background:e.colorErrorBg},{color:e.colorErrorHover,background:e.colorErrorBg}))}),jN=e=>{const{componentCls:t}=e;return{[`${t}-default`]:Ew(e),[`${t}-primary`]:zN(e),[`${t}-dashed`]:FN(e),[`${t}-link`]:kN(e),[`${t}-text`]:BN(e),[`${t}-ghost`]:Ms(e.componentCls,e.ghostBg,e.colorBgContainer,e.colorBgContainer,e.colorTextDisabled,e.colorBorder)}},Jh=function(e){let t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:"";const{componentCls:n,controlHeight:r,fontSize:o,lineHeight:i,borderRadius:a,buttonPaddingHorizontal:l,iconCls:s,buttonPaddingVertical:c}=e,u=`${n}-icon-only`;return[{[`${t}`]:{fontSize:o,lineHeight:i,height:r,padding:`${X(c)} ${X(l)}`,borderRadius:a,[`&${u}`]:{width:r,paddingInlineStart:0,paddingInlineEnd:0,[`&${n}-round`]:{width:"auto"},[s]:{fontSize:e.buttonIconOnlyFontSize}},[`&${n}-loading`]:{opacity:e.opacityLoading,cursor:"default"},[`${n}-loading-icon`]:{transition:`width ${e.motionDurationSlow} ${e.motionEaseInOut}, opacity ${e.motionDurationSlow} ${e.motionEaseInOut}`}}},{[`${n}${n}-circle${t}`]:AN(e)},{[`${n}${n}-round${t}`]:DN(e)}]},HN=e=>{const t=$t(e,{fontSize:e.contentFontSize,lineHeight:e.contentLineHeight});return Jh(t,e.componentCls)},WN=e=>{const t=$t(e,{controlHeight:e.controlHeightSM,fontSize:e.contentFontSizeSM,lineHeight:e.contentLineHeightSM,padding:e.paddingXS,buttonPaddingHorizontal:e.paddingInlineSM,buttonPaddingVertical:e.paddingBlockSM,borderRadius:e.borderRadiusSM,buttonIconOnlyFontSize:e.onlyIconSizeSM});return Jh(t,`${e.componentCls}-sm`)},VN=e=>{const t=$t(e,{controlHeight:e.controlHeightLG,fontSize:e.contentFontSizeLG,lineHeight:e.contentLineHeightLG,buttonPaddingHorizontal:e.paddingInlineLG,buttonPaddingVertical:e.paddingBlockLG,borderRadius:e.borderRadiusLG,buttonIconOnlyFontSize:e.onlyIconSizeLG});return Jh(t,`${e.componentCls}-lg`)},UN=e=>{const{componentCls:t}=e;return{[t]:{[`&${t}-block`]:{width:"100%"}}}},YN=vn("Button",e=>{const t=xw(e);return[_N(t),HN(t),WN(t),VN(t),UN(t),jN(t),NN(t)]},ww,{unitless:{fontWeight:!0,contentLineHeight:!0,contentLineHeightSM:!0,contentLineHeightLG:!0}});function GN(e,t,n){const{focusElCls:r,focus:o,borderElCls:i}=n,a=i?"> *":"",l=["hover",o?"focus":null,"active"].filter(Boolean).map(s=>`&:${s} ${a}`).join(",");return{[`&-item:not(${t}-last-item)`]:{marginInlineEnd:e.calc(e.lineWidth).mul(-1).equal()},"&-item":Object.assign(Object.assign({[l]:{zIndex:2}},r?{[`&${r}`]:{zIndex:2}}:{}),{[`&[disabled] ${a}`]:{zIndex:0}})}}function KN(e,t,n){const{borderElCls:r}=n,o=r?`> ${r}`:"";return{[`&-item:not(${t}-first-item):not(${t}-last-item) ${o}`]:{borderRadius:0},[`&-item:not(${t}-last-item)${t}-first-item`]:{[`& ${o}, &${e}-sm ${o}, &${e}-lg ${o}`]:{borderStartEndRadius:0,borderEndEndRadius:0}},[`&-item:not(${t}-first-item)${t}-last-item`]:{[`& ${o}, &${e}-sm ${o}, &${e}-lg ${o}`]:{borderStartStartRadius:0,borderEndStartRadius:0}}}}function tf(e){let t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{focus:!0};const{componentCls:n}=e,r=`${n}-compact`;return{[r]:Object.assign(Object.assign({},GN(e,r,t)),KN(n,r,t))}}function qN(e,t){return{[`&-item:not(${t}-last-item)`]:{marginBottom:e.calc(e.lineWidth).mul(-1).equal()},"&-item":{"&:hover,&:focus,&:active":{zIndex:2},"&[disabled]":{zIndex:0}}}}function XN(e,t){return{[`&-item:not(${t}-first-item):not(${t}-last-item)`]:{borderRadius:0},[`&-item${t}-first-item:not(${t}-last-item)`]:{[`&, &${e}-sm, &${e}-lg`]:{borderEndEndRadius:0,borderEndStartRadius:0}},[`&-item${t}-last-item:not(${t}-first-item)`]:{[`&, &${e}-sm, &${e}-lg`]:{borderStartStartRadius:0,borderStartEndRadius:0}}}}function QN(e){const t=`${e.componentCls}-compact-vertical`;return{[t]:Object.assign(Object.assign({},qN(e,t)),XN(e.componentCls,t))}}const ZN=e=>{const{componentCls:t,calc:n}=e;return{[t]:{[`&-compact-item${t}-primary`]:{[`&:not([disabled]) + ${t}-compact-item${t}-primary:not([disabled])`]:{position:"relative","&:before":{position:"absolute",top:n(e.lineWidth).mul(-1).equal(),insetInlineStart:n(e.lineWidth).mul(-1).equal(),display:"inline-block",width:e.lineWidth,height:`calc(100% + ${X(e.lineWidth)} * 2)`,backgroundColor:e.colorPrimaryHover,content:'""'}}},"&-compact-vertical-item":{[`&${t}-primary`]:{[`&:not([disabled]) + ${t}-compact-vertical-item${t}-primary:not([disabled])`]:{position:"relative","&:before":{position:"absolute",top:n(e.lineWidth).mul(-1).equal(),insetInlineStart:n(e.lineWidth).mul(-1).equal(),display:"inline-block",width:`calc(100% + ${X(e.lineWidth)} * 2)`,height:e.lineWidth,backgroundColor:e.colorPrimaryHover,content:'""'}}}}}}},JN=Kh(["Button","compact"],e=>{const t=xw(e);return[tf(t),QN(t),ZN(t)]},ww);var e6=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{var n,r;const{loading:o=!1,prefixCls:i,type:a="default",danger:l,shape:s="default",size:c,styles:u,disabled:d,className:v,rootClassName:h,children:g,icon:p,ghost:b=!1,block:m=!1,htmlType:y="button",classNames:S,style:x={}}=e,$=e6(e,["loading","prefixCls","type","danger","shape","size","styles","disabled","className","rootClassName","children","icon","ghost","block","htmlType","classNames","style"]),{getPrefixCls:E,autoInsertSpaceInButton:w,direction:R,button:P}=f.exports.useContext(ot),N=E("btn",i),[I,z,F]=YN(N),T=f.exports.useContext(rl),D=d!=null?d:T,_=f.exports.useContext(Sw),O=f.exports.useMemo(()=>t6(o),[o]),[M,L]=f.exports.useState(O.loading),[A,B]=f.exports.useState(!1),j=xr(t,f.exports.createRef()),H=f.exports.Children.count(g)===1&&!p&&!cv(a);f.exports.useEffect(()=>{let le=null;O.delay>0?le=setTimeout(()=>{le=null,L(!0)},O.delay):L(O.loading);function Ce(){le&&(clearTimeout(le),le=null)}return Ce},[O]),f.exports.useEffect(()=>{if(!j||!j.current||w===!1)return;const le=j.current.textContent;H&&ag(le)?A||B(!0):A&&B(!1)},[j]);const W=le=>{const{onClick:Ce}=e;if(M||D){le.preventDefault();return}Ce==null||Ce(le)},Y=w!==!1,{compactSize:K,compactItemClassnames:q}=ef(N,R),ee={large:"lg",small:"sm",middle:void 0},Z=So(le=>{var Ce,ce;return(ce=(Ce=c!=null?c:K)!==null&&Ce!==void 0?Ce:_)!==null&&ce!==void 0?ce:le}),Q=Z&&ee[Z]||"",ne=M?"loading":p,ae=lr($,["navigate"]),J=te(N,z,F,{[`${N}-${s}`]:s!=="default"&&s,[`${N}-${a}`]:a,[`${N}-${Q}`]:Q,[`${N}-icon-only`]:!g&&g!==0&&!!ne,[`${N}-background-ghost`]:b&&!cv(a),[`${N}-loading`]:M,[`${N}-two-chinese-chars`]:A&&Y&&!M,[`${N}-block`]:m,[`${N}-dangerous`]:!!l,[`${N}-rtl`]:R==="rtl"},q,v,h,P==null?void 0:P.className),re=Object.assign(Object.assign({},P==null?void 0:P.style),x),fe=te(S==null?void 0:S.icon,(n=P==null?void 0:P.classNames)===null||n===void 0?void 0:n.icon),ve=Object.assign(Object.assign({},(u==null?void 0:u.icon)||{}),((r=P==null?void 0:P.styles)===null||r===void 0?void 0:r.icon)||{}),pe=p&&!M?C(Cw,{prefixCls:N,className:fe,style:ve,children:p}):C(PN,{existIcon:!!p,prefixCls:N,loading:!!M}),oe=g||g===0?ON(g,H&&Y):null;if(ae.href!==void 0)return I(ie("a",{...Object.assign({},ae,{className:te(J,{[`${N}-disabled`]:D}),href:D?void 0:ae.href,style:re,onClick:W,ref:j,tabIndex:D?-1:0}),children:[pe,oe]}));let se=ie("button",{...Object.assign({},$,{type:y,className:J,style:re,onClick:W,disabled:D,ref:j}),children:[pe,oe,!!q&&C(JN,{prefixCls:N},"compact")]});return cv(a)||(se=C(Qh,{component:"Button",disabled:!!M,children:se})),I(se)},em=f.exports.forwardRef(n6);em.Group=EN;em.__ANT_BUTTON=!0;const Xu=em;var Mw=f.exports.createContext(null),Vy=[];function r6(e,t){var n=f.exports.useState(function(){if(!Rn())return null;var g=document.createElement("div");return g}),r=G(n,1),o=r[0],i=f.exports.useRef(!1),a=f.exports.useContext(Mw),l=f.exports.useState(Vy),s=G(l,2),c=s[0],u=s[1],d=a||(i.current?void 0:function(g){u(function(p){var b=[g].concat(Oe(p));return b})});function v(){o.parentElement||document.body.appendChild(o),i.current=!0}function h(){var g;(g=o.parentElement)===null||g===void 0||g.removeChild(o),i.current=!1}return Nt(function(){return e?a?a(v):v():h(),h},[e]),Nt(function(){c.length&&(c.forEach(function(g){return g()}),u(Vy))},[c]),[o,d]}var fv;function o6(e){if(typeof document>"u")return 0;if(e||fv===void 0){var t=document.createElement("div");t.style.width="100%",t.style.height="200px";var n=document.createElement("div"),r=n.style;r.position="absolute",r.top="0",r.left="0",r.pointerEvents="none",r.visibility="hidden",r.width="200px",r.height="150px",r.overflow="hidden",n.appendChild(t),document.body.appendChild(n);var o=t.offsetWidth;n.style.overflow="scroll";var i=t.offsetWidth;o===i&&(i=n.clientWidth),document.body.removeChild(n),fv=o-i}return fv}function Uy(e){var t=e.match(/^(.*)px$/),n=Number(t==null?void 0:t[1]);return Number.isNaN(n)?o6():n}function i6(e){if(typeof document>"u"||!e||!(e instanceof Element))return{width:0,height:0};var t=getComputedStyle(e,"::-webkit-scrollbar"),n=t.width,r=t.height;return{width:Uy(n),height:Uy(r)}}function a6(){return document.body.scrollHeight>(window.innerHeight||document.documentElement.clientHeight)&&window.innerWidth>document.body.offsetWidth}var l6="rc-util-locker-".concat(Date.now()),Yy=0;function s6(e){var t=!!e,n=f.exports.useState(function(){return Yy+=1,"".concat(l6,"_").concat(Yy)}),r=G(n,1),o=r[0];Nt(function(){if(t){var i=i6(document.body).width,a=a6();Xo(` +html body { + overflow-y: hidden; + `.concat(a?"width: calc(100% - ".concat(i,"px);"):"",` +}`),o)}else Ss(o);return function(){Ss(o)}},[t,o])}var Gy=!1;function c6(e){return typeof e=="boolean"&&(Gy=e),Gy}var Ky=function(t){return t===!1?!1:!Rn()||!t?null:typeof t=="string"?document.querySelector(t):typeof t=="function"?t():t},nf=f.exports.forwardRef(function(e,t){var n=e.open,r=e.autoLock,o=e.getContainer;e.debug;var i=e.autoDestroy,a=i===void 0?!0:i,l=e.children,s=f.exports.useState(n),c=G(s,2),u=c[0],d=c[1],v=u||n;f.exports.useEffect(function(){(a||n)&&d(n)},[n,a]);var h=f.exports.useState(function(){return Ky(o)}),g=G(h,2),p=g[0],b=g[1];f.exports.useEffect(function(){var I=Ky(o);b(I!=null?I:null)});var m=r6(v&&!p),y=G(m,2),S=y[0],x=y[1],$=p!=null?p:S;s6(r&&n&&Rn()&&($===S||$===document.body));var E=null;if(l&&ki(l)&&t){var w=l;E=w.ref}var R=Fi(E,t);if(!v||!Rn()||p===void 0)return null;var P=$===!1||c6(),N=l;return t&&(N=f.exports.cloneElement(l,{ref:R})),C(Mw.Provider,{value:x,children:P?N:Gn.exports.createPortal(N,$)})}),Ow=f.exports.createContext({});function u6(){var e=U({},As);return e.useId}var qy=0,Xy=u6();const Rw=Xy?function(t){var n=Xy();return t||n}:function(t){var n=f.exports.useState("ssr-id"),r=G(n,2),o=r[0],i=r[1];return f.exports.useEffect(function(){var a=qy;qy+=1,i("rc_unique_".concat(a))},[]),t||o};function Qy(e,t,n){var r=t;return!r&&n&&(r="".concat(e,"-").concat(n)),r}function Zy(e,t){var n=e["page".concat(t?"Y":"X","Offset")],r="scroll".concat(t?"Top":"Left");if(typeof n!="number"){var o=e.document;n=o.documentElement[r],typeof n!="number"&&(n=o.body[r])}return n}function d6(e){var t=e.getBoundingClientRect(),n={left:t.left,top:t.top},r=e.ownerDocument,o=r.defaultView||r.parentWindow;return n.left+=Zy(o),n.top+=Zy(o,!0),n}const f6=f.exports.memo(function(e){var t=e.children;return t},function(e,t){var n=t.shouldUpdate;return!n});var Jy={width:0,height:0,overflow:"hidden",outline:"none"},v6=lt.forwardRef(function(e,t){var n=e.prefixCls,r=e.className,o=e.style,i=e.title,a=e.ariaId,l=e.footer,s=e.closable,c=e.closeIcon,u=e.onClose,d=e.children,v=e.bodyStyle,h=e.bodyProps,g=e.modalRender,p=e.onMouseDown,b=e.onMouseUp,m=e.holderRef,y=e.visible,S=e.forceRender,x=e.width,$=e.height,E=e.classNames,w=e.styles,R=lt.useContext(Ow),P=R.panel,N=Fi(m,P),I=f.exports.useRef(),z=f.exports.useRef();lt.useImperativeHandle(t,function(){return{focus:function(){var L;(L=I.current)===null||L===void 0||L.focus()},changeActive:function(L){var A=document,B=A.activeElement;L&&B===z.current?I.current.focus():!L&&B===I.current&&z.current.focus()}}});var F={};x!==void 0&&(F.width=x),$!==void 0&&(F.height=$);var T;l&&(T=C("div",{className:te("".concat(n,"-footer"),E==null?void 0:E.footer),style:U({},w==null?void 0:w.footer),children:l}));var D;i&&(D=C("div",{className:te("".concat(n,"-header"),E==null?void 0:E.header),style:U({},w==null?void 0:w.header),children:C("div",{className:"".concat(n,"-title"),id:a,children:i})}));var _;s&&(_=C("button",{type:"button",onClick:u,"aria-label":"Close",className:"".concat(n,"-close"),children:c||C("span",{className:"".concat(n,"-close-x")})}));var O=ie("div",{className:te("".concat(n,"-content"),E==null?void 0:E.content),style:w==null?void 0:w.content,children:[_,D,C("div",{className:te("".concat(n,"-body"),E==null?void 0:E.body),style:U(U({},v),w==null?void 0:w.body),...h,children:d}),T]});return ie("div",{role:"dialog","aria-labelledby":i?a:null,"aria-modal":"true",ref:N,style:U(U({},o),F),className:te(n,r),onMouseDown:p,onMouseUp:b,children:[C("div",{tabIndex:0,ref:I,style:Jy,"aria-hidden":"true"}),C(f6,{shouldUpdate:y||S,children:g?g(O):O}),C("div",{tabIndex:0,ref:z,style:Jy,"aria-hidden":"true"})]},"dialog-element")}),Iw=f.exports.forwardRef(function(e,t){var n=e.prefixCls,r=e.title,o=e.style,i=e.className,a=e.visible,l=e.forceRender,s=e.destroyOnClose,c=e.motionName,u=e.ariaId,d=e.onVisibleChanged,v=e.mousePosition,h=f.exports.useRef(),g=f.exports.useState(),p=G(g,2),b=p[0],m=p[1],y={};b&&(y.transformOrigin=b);function S(){var x=d6(h.current);m(v?"".concat(v.x-x.left,"px ").concat(v.y-x.top,"px"):"")}return C(to,{visible:a,onVisibleChanged:d,onAppearPrepare:S,onEnterPrepare:S,forceRender:l,motionName:c,removeOnLeave:s,ref:h,children:function(x,$){var E=x.className,w=x.style;return C(v6,{...e,ref:t,title:r,ariaId:u,prefixCls:n,holderRef:$,style:U(U(U({},w),o),y),className:te(i,E)})}})});Iw.displayName="Content";function p6(e){var t=e.prefixCls,n=e.style,r=e.visible,o=e.maskProps,i=e.motionName,a=e.className;return C(to,{visible:r,motionName:i,leavedClassName:"".concat(t,"-mask-hidden"),children:function(l,s){var c=l.className,u=l.style;return C("div",{ref:s,style:U(U({},u),n),className:te("".concat(t,"-mask"),c,a),...o})}},"mask")}function g6(e){var t=e.prefixCls,n=t===void 0?"rc-dialog":t,r=e.zIndex,o=e.visible,i=o===void 0?!1:o,a=e.keyboard,l=a===void 0?!0:a,s=e.focusTriggerAfterClose,c=s===void 0?!0:s,u=e.wrapStyle,d=e.wrapClassName,v=e.wrapProps,h=e.onClose,g=e.afterOpenChange,p=e.afterClose,b=e.transitionName,m=e.animation,y=e.closable,S=y===void 0?!0:y,x=e.mask,$=x===void 0?!0:x,E=e.maskTransitionName,w=e.maskAnimation,R=e.maskClosable,P=R===void 0?!0:R,N=e.maskStyle,I=e.maskProps,z=e.rootClassName,F=e.classNames,T=e.styles,D=f.exports.useRef(),_=f.exports.useRef(),O=f.exports.useRef(),M=f.exports.useState(i),L=G(M,2),A=L[0],B=L[1],k=Rw();function j(){Np(_.current,document.activeElement)||(D.current=document.activeElement)}function H(){if(!Np(_.current,document.activeElement)){var ae;(ae=O.current)===null||ae===void 0||ae.focus()}}function W(ae){if(ae)H();else{if(B(!1),$&&D.current&&c){try{D.current.focus({preventScroll:!0})}catch{}D.current=null}A&&(p==null||p())}g==null||g(ae)}function Y(ae){h==null||h(ae)}var K=f.exports.useRef(!1),q=f.exports.useRef(),ee=function(){clearTimeout(q.current),K.current=!0},Z=function(){q.current=setTimeout(function(){K.current=!1})},Q=null;P&&(Q=function(J){K.current?K.current=!1:_.current===J.target&&Y(J)});function ne(ae){if(l&&ae.keyCode===ue.ESC){ae.stopPropagation(),Y(ae);return}i&&ae.keyCode===ue.TAB&&O.current.changeActive(!ae.shiftKey)}return f.exports.useEffect(function(){i&&(B(!0),j())},[i]),f.exports.useEffect(function(){return function(){clearTimeout(q.current)}},[]),ie("div",{className:te("".concat(n,"-root"),z),...Ka(e,{data:!0}),children:[C(p6,{prefixCls:n,visible:$&&i,motionName:Qy(n,E,w),style:U(U({zIndex:r},N),T==null?void 0:T.mask),maskProps:I,className:F==null?void 0:F.mask}),C("div",{tabIndex:-1,onKeyDown:ne,className:te("".concat(n,"-wrap"),d,F==null?void 0:F.wrapper),ref:_,onClick:Q,style:U(U(U({zIndex:r},u),T==null?void 0:T.wrapper),{},{display:A?null:"none"}),...v,children:C(Iw,{...e,onMouseDown:ee,onMouseUp:Z,ref:O,closable:S,ariaId:k,prefixCls:n,visible:i&&A,onClose:Y,onVisibleChanged:W,motionName:Qy(n,b,m)})})]})}var Pw=function(t){var n=t.visible,r=t.getContainer,o=t.forceRender,i=t.destroyOnClose,a=i===void 0?!1:i,l=t.afterClose,s=t.panelRef,c=f.exports.useState(n),u=G(c,2),d=u[0],v=u[1],h=f.exports.useMemo(function(){return{panel:s}},[s]);return f.exports.useEffect(function(){n&&v(!0)},[n]),!o&&a&&!d?null:C(Ow.Provider,{value:h,children:C(nf,{open:n||o||d,autoDestroy:!1,getContainer:r,autoLock:n||d,children:C(g6,{...t,destroyOnClose:a,afterClose:function(){l==null||l(),v(!1)}})})})};Pw.displayName="Dialog";function h6(e,t,n){return typeof e=="boolean"?e:t===void 0?!!n:t!==!1&&t!==null}function m6(e,t,n){let r=arguments.length>3&&arguments[3]!==void 0?arguments[3]:C(eo,{}),o=arguments.length>4&&arguments[4]!==void 0?arguments[4]:!1;if(!h6(e,t,o))return[!1,null];const a=typeof t=="boolean"||t===void 0||t===null?r:t;return[!0,n?n(a):a]}var Si="RC_FORM_INTERNAL_HOOKS",Pt=function(){Mn(!1,"Can not find FormContext. Please make sure you wrap Field under Form.")},qa=f.exports.createContext({getFieldValue:Pt,getFieldsValue:Pt,getFieldError:Pt,getFieldWarning:Pt,getFieldsError:Pt,isFieldsTouched:Pt,isFieldTouched:Pt,isFieldValidating:Pt,isFieldsValidating:Pt,resetFields:Pt,setFields:Pt,setFieldValue:Pt,setFieldsValue:Pt,validateFields:Pt,submit:Pt,getInternalHooks:function(){return Pt(),{dispatch:Pt,initEntityValue:Pt,registerField:Pt,useSubscribe:Pt,setInitialValues:Pt,destroyForm:Pt,setCallbacks:Pt,registerWatch:Pt,getFields:Pt,setValidateMessages:Pt,setPreserve:Pt,getInitialValue:Pt}}}),Qu=f.exports.createContext(null);function lg(e){return e==null?[]:Array.isArray(e)?e:[e]}function y6(e){return e&&!!e._init}function Ci(){return Ci=Object.assign?Object.assign.bind():function(e){for(var t=1;t"u"||!Reflect.construct||Reflect.construct.sham)return!1;if(typeof Proxy=="function")return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch{return!1}}function iu(e,t,n){return S6()?iu=Reflect.construct.bind():iu=function(o,i,a){var l=[null];l.push.apply(l,i);var s=Function.bind.apply(o,l),c=new s;return a&&Os(c,a.prototype),c},iu.apply(null,arguments)}function C6(e){return Function.toString.call(e).indexOf("[native code]")!==-1}function cg(e){var t=typeof Map=="function"?new Map:void 0;return cg=function(r){if(r===null||!C6(r))return r;if(typeof r!="function")throw new TypeError("Super expression must either be null or a function");if(typeof t<"u"){if(t.has(r))return t.get(r);t.set(r,o)}function o(){return iu(r,arguments,sg(this).constructor)}return o.prototype=Object.create(r.prototype,{constructor:{value:o,enumerable:!1,writable:!0,configurable:!0}}),Os(o,r)},cg(e)}var x6=/%[sdj%]/g,w6=function(){};typeof process<"u"&&process.env;function ug(e){if(!e||!e.length)return null;var t={};return e.forEach(function(n){var r=n.field;t[r]=t[r]||[],t[r].push(n)}),t}function nr(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),r=1;r=i)return l;switch(l){case"%s":return String(n[o++]);case"%d":return Number(n[o++]);case"%j":try{return JSON.stringify(n[o++])}catch{return"[Circular]"}break;default:return l}});return a}return e}function $6(e){return e==="string"||e==="url"||e==="hex"||e==="email"||e==="date"||e==="pattern"}function ln(e,t){return!!(e==null||t==="array"&&Array.isArray(e)&&!e.length||$6(t)&&typeof e=="string"&&!e)}function E6(e,t,n){var r=[],o=0,i=e.length;function a(l){r.push.apply(r,l||[]),o++,o===i&&n(r)}e.forEach(function(l){t(l,a)})}function eb(e,t,n){var r=0,o=e.length;function i(a){if(a&&a.length){n(a);return}var l=r;r=r+1,l()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+\.)+[a-zA-Z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]{2,}))$/,hex:/^#?([a-f0-9]{6}|[a-f0-9]{3})$/i},Nl={integer:function(t){return Nl.number(t)&&parseInt(t,10)===t},float:function(t){return Nl.number(t)&&!Nl.integer(t)},array:function(t){return Array.isArray(t)},regexp:function(t){if(t instanceof RegExp)return!0;try{return!!new RegExp(t)}catch{return!1}},date:function(t){return typeof t.getTime=="function"&&typeof t.getMonth=="function"&&typeof t.getYear=="function"&&!isNaN(t.getTime())},number:function(t){return isNaN(t)?!1:typeof t=="number"},object:function(t){return typeof t=="object"&&!Nl.array(t)},method:function(t){return typeof t=="function"},email:function(t){return typeof t=="string"&&t.length<=320&&!!t.match(ob.email)},url:function(t){return typeof t=="string"&&t.length<=2048&&!!t.match(T6())},hex:function(t){return typeof t=="string"&&!!t.match(ob.hex)}},N6=function(t,n,r,o,i){if(t.required&&n===void 0){Tw(t,n,r,o,i);return}var a=["integer","float","array","regexp","object","method","email","number","date","url","hex"],l=t.type;a.indexOf(l)>-1?Nl[l](n)||o.push(nr(i.messages.types[l],t.fullField,t.type)):l&&typeof n!==t.type&&o.push(nr(i.messages.types[l],t.fullField,t.type))},_6=function(t,n,r,o,i){var a=typeof t.len=="number",l=typeof t.min=="number",s=typeof t.max=="number",c=/[\uD800-\uDBFF][\uDC00-\uDFFF]/g,u=n,d=null,v=typeof n=="number",h=typeof n=="string",g=Array.isArray(n);if(v?d="number":h?d="string":g&&(d="array"),!d)return!1;g&&(u=n.length),h&&(u=n.replace(c,"_").length),a?u!==t.len&&o.push(nr(i.messages[d].len,t.fullField,t.len)):l&&!s&&ut.max?o.push(nr(i.messages[d].max,t.fullField,t.max)):l&&s&&(ut.max)&&o.push(nr(i.messages[d].range,t.fullField,t.min,t.max))},Gi="enum",A6=function(t,n,r,o,i){t[Gi]=Array.isArray(t[Gi])?t[Gi]:[],t[Gi].indexOf(n)===-1&&o.push(nr(i.messages[Gi],t.fullField,t[Gi].join(", ")))},D6=function(t,n,r,o,i){if(t.pattern){if(t.pattern instanceof RegExp)t.pattern.lastIndex=0,t.pattern.test(n)||o.push(nr(i.messages.pattern.mismatch,t.fullField,n,t.pattern));else if(typeof t.pattern=="string"){var a=new RegExp(t.pattern);a.test(n)||o.push(nr(i.messages.pattern.mismatch,t.fullField,n,t.pattern))}}},pt={required:Tw,whitespace:P6,type:N6,range:_6,enum:A6,pattern:D6},L6=function(t,n,r,o,i){var a=[],l=t.required||!t.required&&o.hasOwnProperty(t.field);if(l){if(ln(n,"string")&&!t.required)return r();pt.required(t,n,o,a,i,"string"),ln(n,"string")||(pt.type(t,n,o,a,i),pt.range(t,n,o,a,i),pt.pattern(t,n,o,a,i),t.whitespace===!0&&pt.whitespace(t,n,o,a,i))}r(a)},z6=function(t,n,r,o,i){var a=[],l=t.required||!t.required&&o.hasOwnProperty(t.field);if(l){if(ln(n)&&!t.required)return r();pt.required(t,n,o,a,i),n!==void 0&&pt.type(t,n,o,a,i)}r(a)},F6=function(t,n,r,o,i){var a=[],l=t.required||!t.required&&o.hasOwnProperty(t.field);if(l){if(n===""&&(n=void 0),ln(n)&&!t.required)return r();pt.required(t,n,o,a,i),n!==void 0&&(pt.type(t,n,o,a,i),pt.range(t,n,o,a,i))}r(a)},k6=function(t,n,r,o,i){var a=[],l=t.required||!t.required&&o.hasOwnProperty(t.field);if(l){if(ln(n)&&!t.required)return r();pt.required(t,n,o,a,i),n!==void 0&&pt.type(t,n,o,a,i)}r(a)},B6=function(t,n,r,o,i){var a=[],l=t.required||!t.required&&o.hasOwnProperty(t.field);if(l){if(ln(n)&&!t.required)return r();pt.required(t,n,o,a,i),ln(n)||pt.type(t,n,o,a,i)}r(a)},j6=function(t,n,r,o,i){var a=[],l=t.required||!t.required&&o.hasOwnProperty(t.field);if(l){if(ln(n)&&!t.required)return r();pt.required(t,n,o,a,i),n!==void 0&&(pt.type(t,n,o,a,i),pt.range(t,n,o,a,i))}r(a)},H6=function(t,n,r,o,i){var a=[],l=t.required||!t.required&&o.hasOwnProperty(t.field);if(l){if(ln(n)&&!t.required)return r();pt.required(t,n,o,a,i),n!==void 0&&(pt.type(t,n,o,a,i),pt.range(t,n,o,a,i))}r(a)},W6=function(t,n,r,o,i){var a=[],l=t.required||!t.required&&o.hasOwnProperty(t.field);if(l){if(n==null&&!t.required)return r();pt.required(t,n,o,a,i,"array"),n!=null&&(pt.type(t,n,o,a,i),pt.range(t,n,o,a,i))}r(a)},V6=function(t,n,r,o,i){var a=[],l=t.required||!t.required&&o.hasOwnProperty(t.field);if(l){if(ln(n)&&!t.required)return r();pt.required(t,n,o,a,i),n!==void 0&&pt.type(t,n,o,a,i)}r(a)},U6="enum",Y6=function(t,n,r,o,i){var a=[],l=t.required||!t.required&&o.hasOwnProperty(t.field);if(l){if(ln(n)&&!t.required)return r();pt.required(t,n,o,a,i),n!==void 0&&pt[U6](t,n,o,a,i)}r(a)},G6=function(t,n,r,o,i){var a=[],l=t.required||!t.required&&o.hasOwnProperty(t.field);if(l){if(ln(n,"string")&&!t.required)return r();pt.required(t,n,o,a,i),ln(n,"string")||pt.pattern(t,n,o,a,i)}r(a)},K6=function(t,n,r,o,i){var a=[],l=t.required||!t.required&&o.hasOwnProperty(t.field);if(l){if(ln(n,"date")&&!t.required)return r();if(pt.required(t,n,o,a,i),!ln(n,"date")){var s;n instanceof Date?s=n:s=new Date(n),pt.type(t,s,o,a,i),s&&pt.range(t,s.getTime(),o,a,i)}}r(a)},q6=function(t,n,r,o,i){var a=[],l=Array.isArray(n)?"array":typeof n;pt.required(t,n,o,a,i,l),r(a)},vv=function(t,n,r,o,i){var a=t.type,l=[],s=t.required||!t.required&&o.hasOwnProperty(t.field);if(s){if(ln(n,a)&&!t.required)return r();pt.required(t,n,o,l,i,a),ln(n,a)||pt.type(t,n,o,l,i)}r(l)},X6=function(t,n,r,o,i){var a=[],l=t.required||!t.required&&o.hasOwnProperty(t.field);if(l){if(ln(n)&&!t.required)return r();pt.required(t,n,o,a,i)}r(a)},Zl={string:L6,method:z6,number:F6,boolean:k6,regexp:B6,integer:j6,float:H6,array:W6,object:V6,enum:Y6,pattern:G6,date:K6,url:vv,hex:vv,email:vv,required:q6,any:X6};function dg(){return{default:"Validation error on field %s",required:"%s is required",enum:"%s must be one of %s",whitespace:"%s cannot be empty",date:{format:"%s date %s is invalid for format %s",parse:"%s date could not be parsed, %s is invalid ",invalid:"%s date %s is invalid"},types:{string:"%s is not a %s",method:"%s is not a %s (function)",array:"%s is not an %s",object:"%s is not an %s",number:"%s is not a %s",date:"%s is not a %s",boolean:"%s is not a %s",integer:"%s is not an %s",float:"%s is not a %s",regexp:"%s is not a valid %s",email:"%s is not a valid %s",url:"%s is not a valid %s",hex:"%s is not a valid %s"},string:{len:"%s must be exactly %s characters",min:"%s must be at least %s characters",max:"%s cannot be longer than %s characters",range:"%s must be between %s and %s characters"},number:{len:"%s must equal %s",min:"%s cannot be less than %s",max:"%s cannot be greater than %s",range:"%s must be between %s and %s"},array:{len:"%s must be exactly %s in length",min:"%s cannot be less than %s in length",max:"%s cannot be greater than %s in length",range:"%s must be between %s and %s in length"},pattern:{mismatch:"%s value %s does not match pattern %s"},clone:function(){var t=JSON.parse(JSON.stringify(this));return t.clone=this.clone,t}}}var fg=dg(),Gs=function(){function e(n){this.rules=null,this._messages=fg,this.define(n)}var t=e.prototype;return t.define=function(r){var o=this;if(!r)throw new Error("Cannot configure a schema with no rules");if(typeof r!="object"||Array.isArray(r))throw new Error("Rules must be an object");this.rules={},Object.keys(r).forEach(function(i){var a=r[i];o.rules[i]=Array.isArray(a)?a:[a]})},t.messages=function(r){return r&&(this._messages=rb(dg(),r)),this._messages},t.validate=function(r,o,i){var a=this;o===void 0&&(o={}),i===void 0&&(i=function(){});var l=r,s=o,c=i;if(typeof s=="function"&&(c=s,s={}),!this.rules||Object.keys(this.rules).length===0)return c&&c(null,l),Promise.resolve(l);function u(p){var b=[],m={};function y(x){if(Array.isArray(x)){var $;b=($=b).concat.apply($,x)}else b.push(x)}for(var S=0;S2&&arguments[2]!==void 0?arguments[2]:!1;return e&&e.some(function(r){return _w(t,r,n)})}function _w(e,t){var n=arguments.length>2&&arguments[2]!==void 0?arguments[2]:!1;return!e||!t||!n&&e.length!==t.length?!1:t.every(function(r,o){return e[o]===r})}function t_(e,t){if(e===t)return!0;if(!e&&t||e&&!t||!e||!t||Qe(e)!=="object"||Qe(t)!=="object")return!1;var n=Object.keys(e),r=Object.keys(t),o=new Set([].concat(n,r));return Oe(o).every(function(i){var a=e[i],l=t[i];return typeof a=="function"&&typeof l=="function"?!0:a===l})}function n_(e){var t=arguments.length<=1?void 0:arguments[1];return t&&t.target&&Qe(t.target)==="object"&&e in t.target?t.target[e]:t}function sb(e,t,n){var r=e.length;if(t<0||t>=r||n<0||n>=r)return e;var o=e[t],i=t-n;return i>0?[].concat(Oe(e.slice(0,n)),[o],Oe(e.slice(n,t)),Oe(e.slice(t+1,r))):i<0?[].concat(Oe(e.slice(0,t)),Oe(e.slice(t+1,n+1)),[o],Oe(e.slice(n+1,r))):e}var r_=["name"],cr=[];function cb(e,t,n,r,o,i){return typeof e=="function"?e(t,n,"source"in i?{source:i.source}:{}):r!==o}var tm=function(e){Bi(n,e);var t=Ws(n);function n(r){var o;if(zn(this,n),o=t.call(this,r),V(xt(o),"state",{resetCount:0}),V(xt(o),"cancelRegisterFunc",null),V(xt(o),"mounted",!1),V(xt(o),"touched",!1),V(xt(o),"dirty",!1),V(xt(o),"validatePromise",void 0),V(xt(o),"prevValidating",void 0),V(xt(o),"errors",cr),V(xt(o),"warnings",cr),V(xt(o),"cancelRegister",function(){var s=o.props,c=s.preserve,u=s.isListField,d=s.name;o.cancelRegisterFunc&&o.cancelRegisterFunc(u,c,qt(d)),o.cancelRegisterFunc=null}),V(xt(o),"getNamePath",function(){var s=o.props,c=s.name,u=s.fieldContext,d=u.prefixName,v=d===void 0?[]:d;return c!==void 0?[].concat(Oe(v),Oe(c)):[]}),V(xt(o),"getRules",function(){var s=o.props,c=s.rules,u=c===void 0?[]:c,d=s.fieldContext;return u.map(function(v){return typeof v=="function"?v(d):v})}),V(xt(o),"refresh",function(){!o.mounted||o.setState(function(s){var c=s.resetCount;return{resetCount:c+1}})}),V(xt(o),"metaCache",null),V(xt(o),"triggerMetaEvent",function(s){var c=o.props.onMetaChange;if(c){var u=U(U({},o.getMeta()),{},{destroy:s});Vs(o.metaCache,u)||c(u),o.metaCache=u}else o.metaCache=null}),V(xt(o),"onStoreChange",function(s,c,u){var d=o.props,v=d.shouldUpdate,h=d.dependencies,g=h===void 0?[]:h,p=d.onReset,b=u.store,m=o.getNamePath(),y=o.getValue(s),S=o.getValue(b),x=c&&Aa(c,m);switch(u.type==="valueUpdate"&&u.source==="external"&&y!==S&&(o.touched=!0,o.dirty=!0,o.validatePromise=null,o.errors=cr,o.warnings=cr,o.triggerMetaEvent()),u.type){case"reset":if(!c||x){o.touched=!1,o.dirty=!1,o.validatePromise=void 0,o.errors=cr,o.warnings=cr,o.triggerMetaEvent(),p==null||p(),o.refresh();return}break;case"remove":{if(v){o.reRender();return}break}case"setField":{var $=u.data;if(x){"touched"in $&&(o.touched=$.touched),"validating"in $&&!("originRCField"in $)&&(o.validatePromise=$.validating?Promise.resolve([]):null),"errors"in $&&(o.errors=$.errors||cr),"warnings"in $&&(o.warnings=$.warnings||cr),o.dirty=!0,o.triggerMetaEvent(),o.reRender();return}else if("value"in $&&Aa(c,m,!0)){o.reRender();return}if(v&&!m.length&&cb(v,s,b,y,S,u)){o.reRender();return}break}case"dependenciesUpdate":{var E=g.map(qt);if(E.some(function(w){return Aa(u.relatedFields,w)})){o.reRender();return}break}default:if(x||(!g.length||m.length||v)&&cb(v,s,b,y,S,u)){o.reRender();return}break}v===!0&&o.reRender()}),V(xt(o),"validateRules",function(s){var c=o.getNamePath(),u=o.getValue(),d=s||{},v=d.triggerName,h=d.validateOnly,g=h===void 0?!1:h,p=Promise.resolve().then(ji(An().mark(function b(){var m,y,S,x,$,E,w;return An().wrap(function(P){for(;;)switch(P.prev=P.next){case 0:if(o.mounted){P.next=2;break}return P.abrupt("return",[]);case 2:if(m=o.props,y=m.validateFirst,S=y===void 0?!1:y,x=m.messageVariables,$=m.validateDebounce,E=o.getRules(),v&&(E=E.filter(function(N){return N}).filter(function(N){var I=N.validateTrigger;if(!I)return!0;var z=lg(I);return z.includes(v)})),!($&&v)){P.next=10;break}return P.next=8,new Promise(function(N){setTimeout(N,$)});case 8:if(o.validatePromise===p){P.next=10;break}return P.abrupt("return",[]);case 10:return w=Z6(c,u,E,s,S,x),w.catch(function(N){return N}).then(function(){var N=arguments.length>0&&arguments[0]!==void 0?arguments[0]:cr;if(o.validatePromise===p){var I;o.validatePromise=null;var z=[],F=[];(I=N.forEach)===null||I===void 0||I.call(N,function(T){var D=T.rule.warningOnly,_=T.errors,O=_===void 0?cr:_;D?F.push.apply(F,Oe(O)):z.push.apply(z,Oe(O))}),o.errors=z,o.warnings=F,o.triggerMetaEvent(),o.reRender()}}),P.abrupt("return",w);case 13:case"end":return P.stop()}},b)})));return g||(o.validatePromise=p,o.dirty=!0,o.errors=cr,o.warnings=cr,o.triggerMetaEvent(),o.reRender()),p}),V(xt(o),"isFieldValidating",function(){return!!o.validatePromise}),V(xt(o),"isFieldTouched",function(){return o.touched}),V(xt(o),"isFieldDirty",function(){if(o.dirty||o.props.initialValue!==void 0)return!0;var s=o.props.fieldContext,c=s.getInternalHooks(Si),u=c.getInitialValue;return u(o.getNamePath())!==void 0}),V(xt(o),"getErrors",function(){return o.errors}),V(xt(o),"getWarnings",function(){return o.warnings}),V(xt(o),"isListField",function(){return o.props.isListField}),V(xt(o),"isList",function(){return o.props.isList}),V(xt(o),"isPreserve",function(){return o.props.preserve}),V(xt(o),"getMeta",function(){o.prevValidating=o.isFieldValidating();var s={touched:o.isFieldTouched(),validating:o.prevValidating,errors:o.errors,warnings:o.warnings,name:o.getNamePath(),validated:o.validatePromise===null};return s}),V(xt(o),"getOnlyChild",function(s){if(typeof s=="function"){var c=o.getMeta();return U(U({},o.getOnlyChild(s(o.getControlled(),c,o.props.fieldContext))),{},{isFunction:!0})}var u=Qo(s);return u.length!==1||!f.exports.isValidElement(u[0])?{child:u,isFunction:!1}:{child:u[0],isFunction:!1}}),V(xt(o),"getValue",function(s){var c=o.props.fieldContext.getFieldsValue,u=o.getNamePath();return qr(s||c(!0),u)}),V(xt(o),"getControlled",function(){var s=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},c=o.props,u=c.trigger,d=c.validateTrigger,v=c.getValueFromEvent,h=c.normalize,g=c.valuePropName,p=c.getValueProps,b=c.fieldContext,m=d!==void 0?d:b.validateTrigger,y=o.getNamePath(),S=b.getInternalHooks,x=b.getFieldsValue,$=S(Si),E=$.dispatch,w=o.getValue(),R=p||function(z){return V({},g,z)},P=s[u],N=U(U({},s),R(w));N[u]=function(){o.touched=!0,o.dirty=!0,o.triggerMetaEvent();for(var z,F=arguments.length,T=new Array(F),D=0;D=0&&N<=I.length?(u.keys=[].concat(Oe(u.keys.slice(0,N)),[u.id],Oe(u.keys.slice(N))),S([].concat(Oe(I.slice(0,N)),[P],Oe(I.slice(N))))):(u.keys=[].concat(Oe(u.keys),[u.id]),S([].concat(Oe(I),[P]))),u.id+=1},remove:function(P){var N=$(),I=new Set(Array.isArray(P)?P:[P]);I.size<=0||(u.keys=u.keys.filter(function(z,F){return!I.has(F)}),S(N.filter(function(z,F){return!I.has(F)})))},move:function(P,N){if(P!==N){var I=$();P<0||P>=I.length||N<0||N>=I.length||(u.keys=sb(u.keys,P,N),S(sb(I,P,N)))}}},w=y||[];return Array.isArray(w)||(w=[]),r(w.map(function(R,P){var N=u.keys[P];return N===void 0&&(u.keys[P]=u.id,N=u.keys[P],u.id+=1),{name:P,key:N,isListField:!0}}),E,b)}})})})}function i_(e){var t=!1,n=e.length,r=[];return e.length?new Promise(function(o,i){e.forEach(function(a,l){a.catch(function(s){return t=!0,s}).then(function(s){n-=1,r[l]=s,!(n>0)&&(t&&i(r),o(r))})})}):Promise.resolve([])}var Dw="__@field_split__";function pv(e){return e.map(function(t){return"".concat(Qe(t),":").concat(t)}).join(Dw)}var Ki=function(){function e(){zn(this,e),V(this,"kvs",new Map)}return Fn(e,[{key:"set",value:function(n,r){this.kvs.set(pv(n),r)}},{key:"get",value:function(n){return this.kvs.get(pv(n))}},{key:"update",value:function(n,r){var o=this.get(n),i=r(o);i?this.set(n,i):this.delete(n)}},{key:"delete",value:function(n){this.kvs.delete(pv(n))}},{key:"map",value:function(n){return Oe(this.kvs.entries()).map(function(r){var o=G(r,2),i=o[0],a=o[1],l=i.split(Dw);return n({key:l.map(function(s){var c=s.match(/^([^:]*):(.*)$/),u=G(c,3),d=u[1],v=u[2];return d==="number"?Number(v):v}),value:a})})}},{key:"toJSON",value:function(){var n={};return this.map(function(r){var o=r.key,i=r.value;return n[o.join(".")]=i,null}),n}}]),e}(),a_=["name"],l_=Fn(function e(t){var n=this;zn(this,e),V(this,"formHooked",!1),V(this,"forceRootUpdate",void 0),V(this,"subscribable",!0),V(this,"store",{}),V(this,"fieldEntities",[]),V(this,"initialValues",{}),V(this,"callbacks",{}),V(this,"validateMessages",null),V(this,"preserve",null),V(this,"lastValidatePromise",null),V(this,"getForm",function(){return{getFieldValue:n.getFieldValue,getFieldsValue:n.getFieldsValue,getFieldError:n.getFieldError,getFieldWarning:n.getFieldWarning,getFieldsError:n.getFieldsError,isFieldsTouched:n.isFieldsTouched,isFieldTouched:n.isFieldTouched,isFieldValidating:n.isFieldValidating,isFieldsValidating:n.isFieldsValidating,resetFields:n.resetFields,setFields:n.setFields,setFieldValue:n.setFieldValue,setFieldsValue:n.setFieldsValue,validateFields:n.validateFields,submit:n.submit,_init:!0,getInternalHooks:n.getInternalHooks}}),V(this,"getInternalHooks",function(r){return r===Si?(n.formHooked=!0,{dispatch:n.dispatch,initEntityValue:n.initEntityValue,registerField:n.registerField,useSubscribe:n.useSubscribe,setInitialValues:n.setInitialValues,destroyForm:n.destroyForm,setCallbacks:n.setCallbacks,setValidateMessages:n.setValidateMessages,getFields:n.getFields,setPreserve:n.setPreserve,getInitialValue:n.getInitialValue,registerWatch:n.registerWatch}):(Mn(!1,"`getInternalHooks` is internal usage. Should not call directly."),null)}),V(this,"useSubscribe",function(r){n.subscribable=r}),V(this,"prevWithoutPreserves",null),V(this,"setInitialValues",function(r,o){if(n.initialValues=r||{},o){var i,a=Ca(r,n.store);(i=n.prevWithoutPreserves)===null||i===void 0||i.map(function(l){var s=l.key;a=Tr(a,s,qr(r,s))}),n.prevWithoutPreserves=null,n.updateStore(a)}}),V(this,"destroyForm",function(){var r=new Ki;n.getFieldEntities(!0).forEach(function(o){n.isMergedPreserve(o.isPreserve())||r.set(o.getNamePath(),!0)}),n.prevWithoutPreserves=r}),V(this,"getInitialValue",function(r){var o=qr(n.initialValues,r);return r.length?Ca(o):o}),V(this,"setCallbacks",function(r){n.callbacks=r}),V(this,"setValidateMessages",function(r){n.validateMessages=r}),V(this,"setPreserve",function(r){n.preserve=r}),V(this,"watchList",[]),V(this,"registerWatch",function(r){return n.watchList.push(r),function(){n.watchList=n.watchList.filter(function(o){return o!==r})}}),V(this,"notifyWatch",function(){var r=arguments.length>0&&arguments[0]!==void 0?arguments[0]:[];if(n.watchList.length){var o=n.getFieldsValue(),i=n.getFieldsValue(!0);n.watchList.forEach(function(a){a(o,i,r)})}}),V(this,"timeoutId",null),V(this,"warningUnhooked",function(){}),V(this,"updateStore",function(r){n.store=r}),V(this,"getFieldEntities",function(){var r=arguments.length>0&&arguments[0]!==void 0?arguments[0]:!1;return r?n.fieldEntities.filter(function(o){return o.getNamePath().length}):n.fieldEntities}),V(this,"getFieldsMap",function(){var r=arguments.length>0&&arguments[0]!==void 0?arguments[0]:!1,o=new Ki;return n.getFieldEntities(r).forEach(function(i){var a=i.getNamePath();o.set(a,i)}),o}),V(this,"getFieldEntitiesForNamePathList",function(r){if(!r)return n.getFieldEntities(!0);var o=n.getFieldsMap(!0);return r.map(function(i){var a=qt(i);return o.get(a)||{INVALIDATE_NAME_PATH:qt(i)}})}),V(this,"getFieldsValue",function(r,o){n.warningUnhooked();var i,a,l;if(r===!0||Array.isArray(r)?(i=r,a=o):r&&Qe(r)==="object"&&(l=r.strict,a=r.filter),i===!0&&!a)return n.store;var s=n.getFieldEntitiesForNamePathList(Array.isArray(i)?i:null),c=[];return s.forEach(function(u){var d,v,h="INVALIDATE_NAME_PATH"in u?u.INVALIDATE_NAME_PATH:u.getNamePath();if(l){var g,p;if((g=(p=u).isList)!==null&&g!==void 0&&g.call(p))return}else if(!i&&(d=(v=u).isListField)!==null&&d!==void 0&&d.call(v))return;if(!a)c.push(h);else{var b="getMeta"in u?u.getMeta():null;a(b)&&c.push(h)}}),lb(n.store,c.map(qt))}),V(this,"getFieldValue",function(r){n.warningUnhooked();var o=qt(r);return qr(n.store,o)}),V(this,"getFieldsError",function(r){n.warningUnhooked();var o=n.getFieldEntitiesForNamePathList(r);return o.map(function(i,a){return i&&!("INVALIDATE_NAME_PATH"in i)?{name:i.getNamePath(),errors:i.getErrors(),warnings:i.getWarnings()}:{name:qt(r[a]),errors:[],warnings:[]}})}),V(this,"getFieldError",function(r){n.warningUnhooked();var o=qt(r),i=n.getFieldsError([o])[0];return i.errors}),V(this,"getFieldWarning",function(r){n.warningUnhooked();var o=qt(r),i=n.getFieldsError([o])[0];return i.warnings}),V(this,"isFieldsTouched",function(){n.warningUnhooked();for(var r=arguments.length,o=new Array(r),i=0;i0&&arguments[0]!==void 0?arguments[0]:{},o=new Ki,i=n.getFieldEntities(!0);i.forEach(function(s){var c=s.props.initialValue,u=s.getNamePath();if(c!==void 0){var d=o.get(u)||new Set;d.add({entity:s,value:c}),o.set(u,d)}});var a=function(c){c.forEach(function(u){var d=u.props.initialValue;if(d!==void 0){var v=u.getNamePath(),h=n.getInitialValue(v);if(h!==void 0)Mn(!1,"Form already set 'initialValues' with path '".concat(v.join("."),"'. Field can not overwrite it."));else{var g=o.get(v);if(g&&g.size>1)Mn(!1,"Multiple Field with path '".concat(v.join("."),"' set 'initialValue'. Can not decide which one to pick."));else if(g){var p=n.getFieldValue(v),b=u.isListField();!b&&(!r.skipExist||p===void 0)&&n.updateStore(Tr(n.store,v,Oe(g)[0].value))}}}})},l;r.entities?l=r.entities:r.namePathList?(l=[],r.namePathList.forEach(function(s){var c=o.get(s);if(c){var u;(u=l).push.apply(u,Oe(Oe(c).map(function(d){return d.entity})))}})):l=i,a(l)}),V(this,"resetFields",function(r){n.warningUnhooked();var o=n.store;if(!r){n.updateStore(Ca(n.initialValues)),n.resetWithFieldInitialValue(),n.notifyObservers(o,null,{type:"reset"}),n.notifyWatch();return}var i=r.map(qt);i.forEach(function(a){var l=n.getInitialValue(a);n.updateStore(Tr(n.store,a,l))}),n.resetWithFieldInitialValue({namePathList:i}),n.notifyObservers(o,i,{type:"reset"}),n.notifyWatch(i)}),V(this,"setFields",function(r){n.warningUnhooked();var o=n.store,i=[];r.forEach(function(a){var l=a.name,s=Je(a,a_),c=qt(l);i.push(c),"value"in s&&n.updateStore(Tr(n.store,c,s.value)),n.notifyObservers(o,[c],{type:"setField",data:a})}),n.notifyWatch(i)}),V(this,"getFields",function(){var r=n.getFieldEntities(!0),o=r.map(function(i){var a=i.getNamePath(),l=i.getMeta(),s=U(U({},l),{},{name:a,value:n.getFieldValue(a)});return Object.defineProperty(s,"originRCField",{value:!0}),s});return o}),V(this,"initEntityValue",function(r){var o=r.props.initialValue;if(o!==void 0){var i=r.getNamePath(),a=qr(n.store,i);a===void 0&&n.updateStore(Tr(n.store,i,o))}}),V(this,"isMergedPreserve",function(r){var o=r!==void 0?r:n.preserve;return o!=null?o:!0}),V(this,"registerField",function(r){n.fieldEntities.push(r);var o=r.getNamePath();if(n.notifyWatch([o]),r.props.initialValue!==void 0){var i=n.store;n.resetWithFieldInitialValue({entities:[r],skipExist:!0}),n.notifyObservers(i,[r.getNamePath()],{type:"valueUpdate",source:"internal"})}return function(a,l){var s=arguments.length>2&&arguments[2]!==void 0?arguments[2]:[];if(n.fieldEntities=n.fieldEntities.filter(function(d){return d!==r}),!n.isMergedPreserve(l)&&(!a||s.length>1)){var c=a?void 0:n.getInitialValue(o);if(o.length&&n.getFieldValue(o)!==c&&n.fieldEntities.every(function(d){return!_w(d.getNamePath(),o)})){var u=n.store;n.updateStore(Tr(u,o,c,!0)),n.notifyObservers(u,[o],{type:"remove"}),n.triggerDependenciesUpdate(u,o)}}n.notifyWatch([o])}}),V(this,"dispatch",function(r){switch(r.type){case"updateValue":{var o=r.namePath,i=r.value;n.updateValue(o,i);break}case"validateField":{var a=r.namePath,l=r.triggerName;n.validateFields([a],{triggerName:l});break}}}),V(this,"notifyObservers",function(r,o,i){if(n.subscribable){var a=U(U({},i),{},{store:n.getFieldsValue(!0)});n.getFieldEntities().forEach(function(l){var s=l.onStoreChange;s(r,o,a)})}else n.forceRootUpdate()}),V(this,"triggerDependenciesUpdate",function(r,o){var i=n.getDependencyChildrenFields(o);return i.length&&n.validateFields(i),n.notifyObservers(r,i,{type:"dependenciesUpdate",relatedFields:[o].concat(Oe(i))}),i}),V(this,"updateValue",function(r,o){var i=qt(r),a=n.store;n.updateStore(Tr(n.store,i,o)),n.notifyObservers(a,[i],{type:"valueUpdate",source:"internal"}),n.notifyWatch([i]);var l=n.triggerDependenciesUpdate(a,i),s=n.callbacks.onValuesChange;if(s){var c=lb(n.store,[i]);s(c,n.getFieldsValue())}n.triggerOnFieldsChange([i].concat(Oe(l)))}),V(this,"setFieldsValue",function(r){n.warningUnhooked();var o=n.store;if(r){var i=Ca(n.store,r);n.updateStore(i)}n.notifyObservers(o,null,{type:"valueUpdate",source:"external"}),n.notifyWatch()}),V(this,"setFieldValue",function(r,o){n.setFields([{name:r,value:o}])}),V(this,"getDependencyChildrenFields",function(r){var o=new Set,i=[],a=new Ki;n.getFieldEntities().forEach(function(s){var c=s.props.dependencies;(c||[]).forEach(function(u){var d=qt(u);a.update(d,function(){var v=arguments.length>0&&arguments[0]!==void 0?arguments[0]:new Set;return v.add(s),v})})});var l=function s(c){var u=a.get(c)||new Set;u.forEach(function(d){if(!o.has(d)){o.add(d);var v=d.getNamePath();d.isFieldDirty()&&v.length&&(i.push(v),s(v))}})};return l(r),i}),V(this,"triggerOnFieldsChange",function(r,o){var i=n.callbacks.onFieldsChange;if(i){var a=n.getFields();if(o){var l=new Ki;o.forEach(function(c){var u=c.name,d=c.errors;l.set(u,d)}),a.forEach(function(c){c.errors=l.get(c.name)||c.errors})}var s=a.filter(function(c){var u=c.name;return Aa(r,u)});s.length&&i(s,a)}}),V(this,"validateFields",function(r,o){n.warningUnhooked();var i,a;Array.isArray(r)||typeof r=="string"||typeof o=="string"?(i=r,a=o):a=r;var l=!!i,s=l?i.map(qt):[],c=[],u=String(Date.now()),d=new Set,v=a||{},h=v.recursive,g=v.dirty;n.getFieldEntities(!0).forEach(function(y){if(l||s.push(y.getNamePath()),!(!y.props.rules||!y.props.rules.length)&&!(g&&!y.isFieldDirty())){var S=y.getNamePath();if(d.add(S.join(u)),!l||Aa(s,S,h)){var x=y.validateRules(U({validateMessages:U(U({},Nw),n.validateMessages)},a));c.push(x.then(function(){return{name:S,errors:[],warnings:[]}}).catch(function($){var E,w=[],R=[];return(E=$.forEach)===null||E===void 0||E.call($,function(P){var N=P.rule.warningOnly,I=P.errors;N?R.push.apply(R,Oe(I)):w.push.apply(w,Oe(I))}),w.length?Promise.reject({name:S,errors:w,warnings:R}):{name:S,errors:w,warnings:R}}))}}});var p=i_(c);n.lastValidatePromise=p,p.catch(function(y){return y}).then(function(y){var S=y.map(function(x){var $=x.name;return $});n.notifyObservers(n.store,S,{type:"validateFinish"}),n.triggerOnFieldsChange(S,y)});var b=p.then(function(){return n.lastValidatePromise===p?Promise.resolve(n.getFieldsValue(s)):Promise.reject([])}).catch(function(y){var S=y.filter(function(x){return x&&x.errors.length});return Promise.reject({values:n.getFieldsValue(s),errorFields:S,outOfDate:n.lastValidatePromise!==p})});b.catch(function(y){return y});var m=s.filter(function(y){return d.has(y.join(u))});return n.triggerOnFieldsChange(m),b}),V(this,"submit",function(){n.warningUnhooked(),n.validateFields().then(function(r){var o=n.callbacks.onFinish;if(o)try{o(r)}catch(i){console.error(i)}}).catch(function(r){var o=n.callbacks.onFinishFailed;o&&o(r)})}),this.forceRootUpdate=t});function Lw(e){var t=f.exports.useRef(),n=f.exports.useState({}),r=G(n,2),o=r[1];if(!t.current)if(e)t.current=e;else{var i=function(){o({})},a=new l_(i);t.current=a.getForm()}return[t.current]}var mg=f.exports.createContext({triggerFormChange:function(){},triggerFormFinish:function(){},registerForm:function(){},unregisterForm:function(){}}),s_=function(t){var n=t.validateMessages,r=t.onFormChange,o=t.onFormFinish,i=t.children,a=f.exports.useContext(mg),l=f.exports.useRef({});return C(mg.Provider,{value:U(U({},a),{},{validateMessages:U(U({},a.validateMessages),n),triggerFormChange:function(c,u){r&&r(c,{changedFields:u,forms:l.current}),a.triggerFormChange(c,u)},triggerFormFinish:function(c,u){o&&o(c,{values:u,forms:l.current}),a.triggerFormFinish(c,u)},registerForm:function(c,u){c&&(l.current=U(U({},l.current),{},V({},c,u))),a.registerForm(c,u)},unregisterForm:function(c){var u=U({},l.current);delete u[c],l.current=u,a.unregisterForm(c)}}),children:i})},c_=["name","initialValues","fields","form","preserve","children","component","validateMessages","validateTrigger","onValuesChange","onFieldsChange","onFinish","onFinishFailed"],u_=function(t,n){var r=t.name,o=t.initialValues,i=t.fields,a=t.form,l=t.preserve,s=t.children,c=t.component,u=c===void 0?"form":c,d=t.validateMessages,v=t.validateTrigger,h=v===void 0?"onChange":v,g=t.onValuesChange,p=t.onFieldsChange,b=t.onFinish,m=t.onFinishFailed,y=Je(t,c_),S=f.exports.useContext(mg),x=Lw(a),$=G(x,1),E=$[0],w=E.getInternalHooks(Si),R=w.useSubscribe,P=w.setInitialValues,N=w.setCallbacks,I=w.setValidateMessages,z=w.setPreserve,F=w.destroyForm;f.exports.useImperativeHandle(n,function(){return E}),f.exports.useEffect(function(){return S.registerForm(r,E),function(){S.unregisterForm(r)}},[S,E,r]),I(U(U({},S.validateMessages),d)),N({onValuesChange:g,onFieldsChange:function(k){if(S.triggerFormChange(r,k),p){for(var j=arguments.length,H=new Array(j>1?j-1:0),W=1;W{let{children:t,status:n,override:r}=e;const o=f.exports.useContext(Jr),i=f.exports.useMemo(()=>{const a=Object.assign({},o);return r&&delete a.isFormItemInput,n&&(delete a.status,delete a.hasFeedback,delete a.feedbackIcon),a},[n,r,o]);return C(Jr.Provider,{value:i,children:t})},v_=f.exports.createContext(void 0),p_=e=>({animationDuration:e,animationFillMode:"both"}),g_=e=>({animationDuration:e,animationFillMode:"both"}),rf=function(e,t,n,r){const i=(arguments.length>4&&arguments[4]!==void 0?arguments[4]:!1)?"&":"";return{[` + ${i}${e}-enter, + ${i}${e}-appear + `]:Object.assign(Object.assign({},p_(r)),{animationPlayState:"paused"}),[`${i}${e}-leave`]:Object.assign(Object.assign({},g_(r)),{animationPlayState:"paused"}),[` + ${i}${e}-enter${e}-enter-active, + ${i}${e}-appear${e}-appear-active + `]:{animationName:t,animationPlayState:"running"},[`${i}${e}-leave${e}-leave-active`]:{animationName:n,animationPlayState:"running",pointerEvents:"none"}}},h_=new Ct("antFadeIn",{"0%":{opacity:0},"100%":{opacity:1}}),m_=new Ct("antFadeOut",{"0%":{opacity:1},"100%":{opacity:0}}),zw=function(e){let t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1;const{antCls:n}=e,r=`${n}-fade`,o=t?"&":"";return[rf(r,h_,m_,e.motionDurationMid,t),{[` + ${o}${r}-enter, + ${o}${r}-appear + `]:{opacity:0,animationTimingFunction:"linear"},[`${o}${r}-leave`]:{animationTimingFunction:"linear"}}]},y_=new Ct("antMoveDownIn",{"0%":{transform:"translate3d(0, 100%, 0)",transformOrigin:"0 0",opacity:0},"100%":{transform:"translate3d(0, 0, 0)",transformOrigin:"0 0",opacity:1}}),b_=new Ct("antMoveDownOut",{"0%":{transform:"translate3d(0, 0, 0)",transformOrigin:"0 0",opacity:1},"100%":{transform:"translate3d(0, 100%, 0)",transformOrigin:"0 0",opacity:0}}),S_=new Ct("antMoveLeftIn",{"0%":{transform:"translate3d(-100%, 0, 0)",transformOrigin:"0 0",opacity:0},"100%":{transform:"translate3d(0, 0, 0)",transformOrigin:"0 0",opacity:1}}),C_=new Ct("antMoveLeftOut",{"0%":{transform:"translate3d(0, 0, 0)",transformOrigin:"0 0",opacity:1},"100%":{transform:"translate3d(-100%, 0, 0)",transformOrigin:"0 0",opacity:0}}),x_=new Ct("antMoveRightIn",{"0%":{transform:"translate3d(100%, 0, 0)",transformOrigin:"0 0",opacity:0},"100%":{transform:"translate3d(0, 0, 0)",transformOrigin:"0 0",opacity:1}}),w_=new Ct("antMoveRightOut",{"0%":{transform:"translate3d(0, 0, 0)",transformOrigin:"0 0",opacity:1},"100%":{transform:"translate3d(100%, 0, 0)",transformOrigin:"0 0",opacity:0}}),$_=new Ct("antMoveUpIn",{"0%":{transform:"translate3d(0, -100%, 0)",transformOrigin:"0 0",opacity:0},"100%":{transform:"translate3d(0, 0, 0)",transformOrigin:"0 0",opacity:1}}),E_=new Ct("antMoveUpOut",{"0%":{transform:"translate3d(0, 0, 0)",transformOrigin:"0 0",opacity:1},"100%":{transform:"translate3d(0, -100%, 0)",transformOrigin:"0 0",opacity:0}}),M_={"move-up":{inKeyframes:$_,outKeyframes:E_},"move-down":{inKeyframes:y_,outKeyframes:b_},"move-left":{inKeyframes:S_,outKeyframes:C_},"move-right":{inKeyframes:x_,outKeyframes:w_}},Zu=(e,t)=>{const{antCls:n}=e,r=`${n}-${t}`,{inKeyframes:o,outKeyframes:i}=M_[t];return[rf(r,o,i,e.motionDurationMid),{[` + ${r}-enter, + ${r}-appear + `]:{opacity:0,animationTimingFunction:e.motionEaseOutCirc},[`${r}-leave`]:{animationTimingFunction:e.motionEaseInOutCirc}}]},nm=new Ct("antSlideUpIn",{"0%":{transform:"scaleY(0.8)",transformOrigin:"0% 0%",opacity:0},"100%":{transform:"scaleY(1)",transformOrigin:"0% 0%",opacity:1}}),rm=new Ct("antSlideUpOut",{"0%":{transform:"scaleY(1)",transformOrigin:"0% 0%",opacity:1},"100%":{transform:"scaleY(0.8)",transformOrigin:"0% 0%",opacity:0}}),om=new Ct("antSlideDownIn",{"0%":{transform:"scaleY(0.8)",transformOrigin:"100% 100%",opacity:0},"100%":{transform:"scaleY(1)",transformOrigin:"100% 100%",opacity:1}}),im=new Ct("antSlideDownOut",{"0%":{transform:"scaleY(1)",transformOrigin:"100% 100%",opacity:1},"100%":{transform:"scaleY(0.8)",transformOrigin:"100% 100%",opacity:0}}),O_=new Ct("antSlideLeftIn",{"0%":{transform:"scaleX(0.8)",transformOrigin:"0% 0%",opacity:0},"100%":{transform:"scaleX(1)",transformOrigin:"0% 0%",opacity:1}}),R_=new Ct("antSlideLeftOut",{"0%":{transform:"scaleX(1)",transformOrigin:"0% 0%",opacity:1},"100%":{transform:"scaleX(0.8)",transformOrigin:"0% 0%",opacity:0}}),I_=new Ct("antSlideRightIn",{"0%":{transform:"scaleX(0.8)",transformOrigin:"100% 0%",opacity:0},"100%":{transform:"scaleX(1)",transformOrigin:"100% 0%",opacity:1}}),P_=new Ct("antSlideRightOut",{"0%":{transform:"scaleX(1)",transformOrigin:"100% 0%",opacity:1},"100%":{transform:"scaleX(0.8)",transformOrigin:"100% 0%",opacity:0}}),T_={"slide-up":{inKeyframes:nm,outKeyframes:rm},"slide-down":{inKeyframes:om,outKeyframes:im},"slide-left":{inKeyframes:O_,outKeyframes:R_},"slide-right":{inKeyframes:I_,outKeyframes:P_}},Xa=(e,t)=>{const{antCls:n}=e,r=`${n}-${t}`,{inKeyframes:o,outKeyframes:i}=T_[t];return[rf(r,o,i,e.motionDurationMid),{[` + ${r}-enter, + ${r}-appear + `]:{transform:"scale(0)",transformOrigin:"0% 0%",opacity:0,animationTimingFunction:e.motionEaseOutQuint,["&-prepare"]:{transform:"scale(1)"}},[`${r}-leave`]:{animationTimingFunction:e.motionEaseInQuint}}]},N_=new Ct("antZoomIn",{"0%":{transform:"scale(0.2)",opacity:0},"100%":{transform:"scale(1)",opacity:1}}),__=new Ct("antZoomOut",{"0%":{transform:"scale(1)"},"100%":{transform:"scale(0.2)",opacity:0}}),fb=new Ct("antZoomBigIn",{"0%":{transform:"scale(0.8)",opacity:0},"100%":{transform:"scale(1)",opacity:1}}),vb=new Ct("antZoomBigOut",{"0%":{transform:"scale(1)"},"100%":{transform:"scale(0.8)",opacity:0}}),A_=new Ct("antZoomUpIn",{"0%":{transform:"scale(0.8)",transformOrigin:"50% 0%",opacity:0},"100%":{transform:"scale(1)",transformOrigin:"50% 0%"}}),D_=new Ct("antZoomUpOut",{"0%":{transform:"scale(1)",transformOrigin:"50% 0%"},"100%":{transform:"scale(0.8)",transformOrigin:"50% 0%",opacity:0}}),L_=new Ct("antZoomLeftIn",{"0%":{transform:"scale(0.8)",transformOrigin:"0% 50%",opacity:0},"100%":{transform:"scale(1)",transformOrigin:"0% 50%"}}),z_=new Ct("antZoomLeftOut",{"0%":{transform:"scale(1)",transformOrigin:"0% 50%"},"100%":{transform:"scale(0.8)",transformOrigin:"0% 50%",opacity:0}}),F_=new Ct("antZoomRightIn",{"0%":{transform:"scale(0.8)",transformOrigin:"100% 50%",opacity:0},"100%":{transform:"scale(1)",transformOrigin:"100% 50%"}}),k_=new Ct("antZoomRightOut",{"0%":{transform:"scale(1)",transformOrigin:"100% 50%"},"100%":{transform:"scale(0.8)",transformOrigin:"100% 50%",opacity:0}}),B_=new Ct("antZoomDownIn",{"0%":{transform:"scale(0.8)",transformOrigin:"50% 100%",opacity:0},"100%":{transform:"scale(1)",transformOrigin:"50% 100%"}}),j_=new Ct("antZoomDownOut",{"0%":{transform:"scale(1)",transformOrigin:"50% 100%"},"100%":{transform:"scale(0.8)",transformOrigin:"50% 100%",opacity:0}}),H_={zoom:{inKeyframes:N_,outKeyframes:__},"zoom-big":{inKeyframes:fb,outKeyframes:vb},"zoom-big-fast":{inKeyframes:fb,outKeyframes:vb},"zoom-left":{inKeyframes:L_,outKeyframes:z_},"zoom-right":{inKeyframes:F_,outKeyframes:k_},"zoom-up":{inKeyframes:A_,outKeyframes:D_},"zoom-down":{inKeyframes:B_,outKeyframes:j_}},of=(e,t)=>{const{antCls:n}=e,r=`${n}-${t}`,{inKeyframes:o,outKeyframes:i}=H_[t];return[rf(r,o,i,t==="zoom-big-fast"?e.motionDurationFast:e.motionDurationMid),{[` + ${r}-enter, + ${r}-appear + `]:{transform:"scale(0)",opacity:0,animationTimingFunction:e.motionEaseOutCirc,"&-prepare":{transform:"none"}},[`${r}-leave`]:{animationTimingFunction:e.motionEaseInOutCirc}}]};function pb(e){return{position:e,inset:0}}const Fw=e=>{const{componentCls:t,antCls:n}=e;return[{[`${t}-root`]:{[`${t}${n}-zoom-enter, ${t}${n}-zoom-appear`]:{transform:"none",opacity:0,animationDuration:e.motionDurationSlow,userSelect:"none"},[`${t}${n}-zoom-leave ${t}-content`]:{pointerEvents:"none"},[`${t}-mask`]:Object.assign(Object.assign({},pb("fixed")),{zIndex:e.zIndexPopupBase,height:"100%",backgroundColor:e.colorBgMask,pointerEvents:"none",[`${t}-hidden`]:{display:"none"}}),[`${t}-wrap`]:Object.assign(Object.assign({},pb("fixed")),{zIndex:e.zIndexPopupBase,overflow:"auto",outline:0,WebkitOverflowScrolling:"touch"})}},{[`${t}-root`]:zw(e)}]},W_=e=>{const{componentCls:t}=e;return[{[`${t}-root`]:{[`${t}-wrap-rtl`]:{direction:"rtl"},[`${t}-centered`]:{textAlign:"center","&::before":{display:"inline-block",width:0,height:"100%",verticalAlign:"middle",content:'""'},[t]:{top:0,display:"inline-block",paddingBottom:0,textAlign:"start",verticalAlign:"middle"}},[`@media (max-width: ${e.screenSMMax}px)`]:{[t]:{maxWidth:"calc(100vw - 16px)",margin:`${X(e.marginXS)} auto`},[`${t}-centered`]:{[t]:{flex:1}}}}},{[t]:Object.assign(Object.assign({},Qt(e)),{pointerEvents:"none",position:"relative",top:100,width:"auto",maxWidth:`calc(100vw - ${X(e.calc(e.margin).mul(2).equal())})`,margin:"0 auto",paddingBottom:e.paddingLG,[`${t}-title`]:{margin:0,color:e.titleColor,fontWeight:e.fontWeightStrong,fontSize:e.titleFontSize,lineHeight:e.titleLineHeight,wordWrap:"break-word"},[`${t}-content`]:{position:"relative",backgroundColor:e.contentBg,backgroundClip:"padding-box",border:0,borderRadius:e.borderRadiusLG,boxShadow:e.boxShadow,pointerEvents:"auto",padding:e.contentPadding},[`${t}-close`]:Object.assign({position:"absolute",top:e.calc(e.modalHeaderHeight).sub(e.modalCloseBtnSize).div(2).equal(),insetInlineEnd:e.calc(e.modalHeaderHeight).sub(e.modalCloseBtnSize).div(2).equal(),zIndex:e.calc(e.zIndexPopupBase).add(10).equal(),padding:0,color:e.modalCloseIconColor,fontWeight:e.fontWeightStrong,lineHeight:1,textDecoration:"none",background:"transparent",borderRadius:e.borderRadiusSM,width:e.modalCloseBtnSize,height:e.modalCloseBtnSize,border:0,outline:0,cursor:"pointer",transition:`color ${e.motionDurationMid}, background-color ${e.motionDurationMid}`,"&-x":{display:"flex",fontSize:e.fontSizeLG,fontStyle:"normal",lineHeight:`${X(e.modalCloseBtnSize)}`,justifyContent:"center",textTransform:"none",textRendering:"auto"},"&:hover":{color:e.modalIconHoverColor,backgroundColor:e.closeBtnHoverBg,textDecoration:"none"},"&:active":{backgroundColor:e.closeBtnActiveBg}},Xd(e)),[`${t}-header`]:{color:e.colorText,background:e.headerBg,borderRadius:`${X(e.borderRadiusLG)} ${X(e.borderRadiusLG)} 0 0`,marginBottom:e.headerMarginBottom,padding:e.headerPadding,borderBottom:e.headerBorderBottom},[`${t}-body`]:{fontSize:e.fontSize,lineHeight:e.lineHeight,wordWrap:"break-word",padding:e.bodyPadding},[`${t}-footer`]:{textAlign:"end",background:e.footerBg,marginTop:e.footerMarginTop,padding:e.footerPadding,borderTop:e.footerBorderTop,borderRadius:e.footerBorderRadius,[`> ${e.antCls}-btn + ${e.antCls}-btn`]:{marginInlineStart:e.marginXS}},[`${t}-open`]:{overflow:"hidden"}})},{[`${t}-pure-panel`]:{top:"auto",padding:0,display:"flex",flexDirection:"column",[`${t}-content, + ${t}-body, + ${t}-confirm-body-wrapper`]:{display:"flex",flexDirection:"column",flex:"auto"},[`${t}-confirm-body`]:{marginBottom:"auto"}}}]},V_=e=>{const{componentCls:t}=e;return{[`${t}-root`]:{[`${t}-wrap-rtl`]:{direction:"rtl",[`${t}-confirm-body`]:{direction:"rtl"}}}}},U_=e=>{const t=e.padding,n=e.fontSizeHeading5,r=e.lineHeightHeading5;return $t(e,{modalHeaderHeight:e.calc(e.calc(r).mul(n).equal()).add(e.calc(t).mul(2).equal()).equal(),modalFooterBorderColorSplit:e.colorSplit,modalFooterBorderStyle:e.lineType,modalFooterBorderWidth:e.lineWidth,modalIconHoverColor:e.colorIconHover,modalCloseIconColor:e.colorIcon,modalCloseBtnSize:e.fontHeight,modalConfirmIconSize:e.fontHeight,modalTitleHeight:e.calc(e.titleFontSize).mul(e.titleLineHeight).equal()})},Y_=e=>({footerBg:"transparent",headerBg:e.colorBgElevated,titleLineHeight:e.lineHeightHeading5,titleFontSize:e.fontSizeHeading5,contentBg:e.colorBgElevated,titleColor:e.colorTextHeading,closeBtnHoverBg:e.wireframe?"transparent":e.colorFillContent,closeBtnActiveBg:e.wireframe?"transparent":e.colorFillContentHover,contentPadding:e.wireframe?0:`${X(e.paddingMD)} ${X(e.paddingContentHorizontalLG)}`,headerPadding:e.wireframe?`${X(e.padding)} ${X(e.paddingLG)}`:0,headerBorderBottom:e.wireframe?`${X(e.lineWidth)} ${e.lineType} ${e.colorSplit}`:"none",headerMarginBottom:e.wireframe?0:e.marginXS,bodyPadding:e.wireframe?e.paddingLG:0,footerPadding:e.wireframe?`${X(e.paddingXS)} ${X(e.padding)}`:0,footerBorderTop:e.wireframe?`${X(e.lineWidth)} ${e.lineType} ${e.colorSplit}`:"none",footerBorderRadius:e.wireframe?`0 0 ${X(e.borderRadiusLG)} ${X(e.borderRadiusLG)}`:0,footerMarginTop:e.wireframe?0:e.marginSM,confirmBodyPadding:e.wireframe?`${X(e.padding*2)} ${X(e.padding*2)} ${X(e.paddingLG)}`:0,confirmIconMarginInlineEnd:e.wireframe?e.margin:e.marginSM,confirmBtnsMarginTop:e.wireframe?e.marginLG:e.marginSM});vn("Modal",e=>{const t=U_(e);return[W_(t),V_(t),Fw(t),of(t,"zoom")]},Y_,{unitless:{titleLineHeight:!0}});function G_(e){return t=>C(ai,{theme:{token:{motion:!1,zIndexPopupBase:0}},children:C(e,{...Object.assign({},t)})})}const K_=(e,t,n,r)=>G_(i=>{const{prefixCls:a,style:l}=i,s=f.exports.useRef(null),[c,u]=f.exports.useState(0),[d,v]=f.exports.useState(0),[h,g]=kt(!1,{value:i.open}),{getPrefixCls:p}=f.exports.useContext(ot),b=p(t||"select",a);f.exports.useEffect(()=>{if(g(!0),typeof ResizeObserver<"u"){const S=new ResizeObserver($=>{const E=$[0].target;u(E.offsetHeight+8),v(E.offsetWidth)}),x=setInterval(()=>{var $;const E=n?`.${n(b)}`:`.${b}-dropdown`,w=($=s.current)===null||$===void 0?void 0:$.querySelector(E);w&&(clearInterval(x),S.observe(w))},10);return()=>{clearInterval(x),S.disconnect()}}},[]);let m=Object.assign(Object.assign({},i),{style:Object.assign(Object.assign({},l),{margin:0}),open:h,visible:h,getPopupContainer:()=>s.current});return r&&(m=r(m)),C("div",{ref:s,style:{paddingBottom:c,position:"relative",minWidth:d},children:C(e,{...Object.assign({},m)})})}),q_=K_,am=function(){if(typeof navigator>"u"||typeof window>"u")return!1;var e=navigator.userAgent||navigator.vendor||window.opera;return/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(e)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw-(n|u)|c55\/|capi|ccwa|cdm-|cell|chtm|cldc|cmd-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc-s|devi|dica|dmob|do(c|p)o|ds(12|-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(-|_)|g1 u|g560|gene|gf-5|g-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd-(m|p|t)|hei-|hi(pt|ta)|hp( i|ip)|hs-c|ht(c(-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i-(20|go|ma)|i230|iac( |-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|-[a-w])|libw|lynx|m1-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|-([1-8]|c))|phil|pire|pl(ay|uc)|pn-2|po(ck|rt|se)|prox|psio|pt-g|qa-a|qc(07|12|21|32|60|-[2-7]|i-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h-|oo|p-)|sdk\/|se(c(-|0|1)|47|mc|nd|ri)|sgh-|shar|sie(-|m)|sk-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h-|v-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl-|tdg-|tel(i|m)|tim-|t-mo|to(pl|sh)|ts(70|m-|m3|m5)|tx-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas-|your|zeto|zte-/i.test(e==null?void 0:e.substr(0,4))};var af=function(t){var n=t.className,r=t.customizeIcon,o=t.customizeIconProps,i=t.children,a=t.onMouseDown,l=t.onClick,s=typeof r=="function"?r(o):r;return C("span",{className:n,onMouseDown:function(u){u.preventDefault(),a==null||a(u)},style:{userSelect:"none",WebkitUserSelect:"none"},unselectable:"on",onClick:l,"aria-hidden":!0,children:s!==void 0?s:C("span",{className:te(n.split(/\s+/).map(function(c){return"".concat(c,"-icon")})),children:i})})},X_=function(t,n,r,o,i){var a=arguments.length>5&&arguments[5]!==void 0?arguments[5]:!1,l=arguments.length>6?arguments[6]:void 0,s=arguments.length>7?arguments[7]:void 0,c=lt.useMemo(function(){if(Qe(o)==="object")return o.clearIcon;if(i)return i},[o,i]),u=lt.useMemo(function(){return!!(!a&&!!o&&(r.length||l)&&!(s==="combobox"&&l===""))},[o,a,r.length,l,s]);return{allowClear:u,clearIcon:C(af,{className:"".concat(t,"-clear"),onMouseDown:n,customizeIcon:c,children:"\xD7"})}},kw=f.exports.createContext(null);function Q_(){return f.exports.useContext(kw)}function Z_(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:10,t=f.exports.useState(!1),n=G(t,2),r=n[0],o=n[1],i=f.exports.useRef(null),a=function(){window.clearTimeout(i.current)};f.exports.useEffect(function(){return a},[]);var l=function(c,u){a(),i.current=window.setTimeout(function(){o(c),u&&u()},e)};return[r,l,a]}function Bw(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:250,t=f.exports.useRef(null),n=f.exports.useRef(null);f.exports.useEffect(function(){return function(){window.clearTimeout(n.current)}},[]);function r(o){(o||t.current===null)&&(t.current=o),window.clearTimeout(n.current),n.current=window.setTimeout(function(){t.current=null},e)}return[function(){return t.current},r]}function J_(e,t,n,r){var o=f.exports.useRef(null);o.current={open:t,triggerOpen:n,customizedTrigger:r},f.exports.useEffect(function(){function i(a){var l;if(!((l=o.current)!==null&&l!==void 0&&l.customizedTrigger)){var s=a.target;s.shadowRoot&&a.composed&&(s=a.composedPath()[0]||s),o.current.open&&e().filter(function(c){return c}).every(function(c){return!c.contains(s)&&c!==s})&&o.current.triggerOpen(!1)}}return window.addEventListener("mousedown",i),function(){return window.removeEventListener("mousedown",i)}},[])}var eA=["prefixCls","invalidate","item","renderItem","responsive","responsiveDisabled","registerSize","itemKey","className","style","children","display","order","component"],qi=void 0;function tA(e,t){var n=e.prefixCls,r=e.invalidate,o=e.item,i=e.renderItem,a=e.responsive,l=e.responsiveDisabled,s=e.registerSize,c=e.itemKey,u=e.className,d=e.style,v=e.children,h=e.display,g=e.order,p=e.component,b=p===void 0?"div":p,m=Je(e,eA),y=a&&!h;function S(R){s(c,R)}f.exports.useEffect(function(){return function(){S(null)}},[]);var x=i&&o!==qi?i(o):v,$;r||($={opacity:y?0:1,height:y?0:qi,overflowY:y?"hidden":qi,order:a?g:qi,pointerEvents:y?"none":qi,position:y?"absolute":qi});var E={};y&&(E["aria-hidden"]=!0);var w=C(b,{className:te(!r&&n,u),style:U(U({},$),d),...E,...m,ref:t,children:x});return a&&(w=C(mr,{onResize:function(P){var N=P.offsetWidth;S(N)},disabled:l,children:w})),w}var Jl=f.exports.forwardRef(tA);Jl.displayName="Item";function nA(e){if(typeof MessageChannel>"u")St(e);else{var t=new MessageChannel;t.port1.onmessage=function(){return e()},t.port2.postMessage(void 0)}}function rA(){var e=f.exports.useRef(null),t=function(r){e.current||(e.current=[],nA(function(){Gn.exports.unstable_batchedUpdates(function(){e.current.forEach(function(o){o()}),e.current=null})})),e.current.push(r)};return t}function Cl(e,t){var n=f.exports.useState(t),r=G(n,2),o=r[0],i=r[1],a=hn(function(l){e(function(){i(l)})});return[o,a]}var Ju=lt.createContext(null),oA=["component"],iA=["className"],aA=["className"],lA=function(t,n){var r=f.exports.useContext(Ju);if(!r){var o=t.component,i=o===void 0?"div":o,a=Je(t,oA);return C(i,{...a,ref:n})}var l=r.className,s=Je(r,iA),c=t.className,u=Je(t,aA);return C(Ju.Provider,{value:null,children:C(Jl,{ref:n,className:te(l,c),...s,...u})})},jw=f.exports.forwardRef(lA);jw.displayName="RawItem";var sA=["prefixCls","data","renderItem","renderRawItem","itemKey","itemWidth","ssr","style","className","maxCount","renderRest","renderRawRest","suffix","component","itemComponent","onVisibleChange"],Hw="responsive",Ww="invalidate";function cA(e){return"+ ".concat(e.length," ...")}function uA(e,t){var n=e.prefixCls,r=n===void 0?"rc-overflow":n,o=e.data,i=o===void 0?[]:o,a=e.renderItem,l=e.renderRawItem,s=e.itemKey,c=e.itemWidth,u=c===void 0?10:c,d=e.ssr,v=e.style,h=e.className,g=e.maxCount,p=e.renderRest,b=e.renderRawRest,m=e.suffix,y=e.component,S=y===void 0?"div":y,x=e.itemComponent,$=e.onVisibleChange,E=Je(e,sA),w=d==="full",R=rA(),P=Cl(R,null),N=G(P,2),I=N[0],z=N[1],F=I||0,T=Cl(R,new Map),D=G(T,2),_=D[0],O=D[1],M=Cl(R,0),L=G(M,2),A=L[0],B=L[1],k=Cl(R,0),j=G(k,2),H=j[0],W=j[1],Y=Cl(R,0),K=G(Y,2),q=K[0],ee=K[1],Z=f.exports.useState(null),Q=G(Z,2),ne=Q[0],ae=Q[1],J=f.exports.useState(null),re=G(J,2),fe=re[0],ve=re[1],pe=f.exports.useMemo(function(){return fe===null&&w?Number.MAX_SAFE_INTEGER:fe||0},[fe,I]),oe=f.exports.useState(!1),se=G(oe,2),le=se[0],Ce=se[1],ce="".concat(r,"-item"),de=Math.max(A,H),xe=g===Hw,he=i.length&&xe,ke=g===Ww,we=he||typeof g=="number"&&i.length>g,ge=f.exports.useMemo(function(){var be=i;return he?I===null&&w?be=i:be=i.slice(0,Math.min(i.length,F/u)):typeof g=="number"&&(be=i.slice(0,g)),be},[i,u,I,g,he]),Pe=f.exports.useMemo(function(){return he?i.slice(pe+1):i.slice(ge.length)},[i,ge,he,pe]),Se=f.exports.useCallback(function(be,Ae){var Me;return typeof s=="function"?s(be):(Me=s&&(be==null?void 0:be[s]))!==null&&Me!==void 0?Me:Ae},[s]),st=f.exports.useCallback(a||function(be){return be},[a]);function nt(be,Ae,Me){fe===be&&(Ae===void 0||Ae===ne)||(ve(be),Me||(Ce(beF){nt($e-1,be-Te-q+H);break}}m&&qe(0)+q>F&&ae(null)}},[F,_,H,q,Se,ge]);var it=le&&!!Pe.length,ft={};ne!==null&&he&&(ft={position:"absolute",left:ne,top:0});var ut={prefixCls:ce,responsive:he,component:x,invalidate:ke},Ue=l?function(be,Ae){var Me=Se(be,Ae);return C(Ju.Provider,{value:U(U({},ut),{},{order:Ae,item:be,itemKey:Me,registerSize:Ee,display:Ae<=pe}),children:l(be,Ae)},Me)}:function(be,Ae){var Me=Se(be,Ae);return f.exports.createElement(Jl,{...ut,order:Ae,key:Me,item:be,renderItem:st,itemKey:Me,registerSize:Ee,display:Ae<=pe})},He,Xe={order:it?pe:Number.MAX_SAFE_INTEGER,className:"".concat(ce,"-rest"),registerSize:_e,display:it};if(b)b&&(He=C(Ju.Provider,{value:U(U({},ut),Xe),children:b(Pe)}));else{var Le=p||cA;He=C(Jl,{...ut,...Xe,children:typeof Le=="function"?Le(Pe):Le})}var Re=ie(S,{className:te(!ke&&r,h),style:v,ref:t,...E,children:[ge.map(Ue),we?He:null,m&&C(Jl,{...ut,responsive:xe,responsiveDisabled:!he,order:pe,className:"".concat(ce,"-suffix"),registerSize:Be,display:!0,style:ft,children:m})]});return xe&&(Re=C(mr,{onResize:Ne,disabled:!he,children:Re})),Re}var Zr=f.exports.forwardRef(uA);Zr.displayName="Overflow";Zr.Item=jw;Zr.RESPONSIVE=Hw;Zr.INVALIDATE=Ww;var dA=function(t,n){var r,o=t.prefixCls,i=t.id,a=t.inputElement,l=t.disabled,s=t.tabIndex,c=t.autoFocus,u=t.autoComplete,d=t.editable,v=t.activeDescendantId,h=t.value,g=t.maxLength,p=t.onKeyDown,b=t.onMouseDown,m=t.onChange,y=t.onPaste,S=t.onCompositionStart,x=t.onCompositionEnd,$=t.open,E=t.attrs,w=a||C("input",{}),R=w,P=R.ref,N=R.props,I=N.onKeyDown,z=N.onChange,F=N.onMouseDown,T=N.onCompositionStart,D=N.onCompositionEnd,_=N.style;return"maxLength"in w.props,w=f.exports.cloneElement(w,U(U(U({type:"search"},N),{},{id:i,ref:xr(n,P),disabled:l,tabIndex:s,autoComplete:u||"off",autoFocus:c,className:te("".concat(o,"-selection-search-input"),(r=w)===null||r===void 0||(r=r.props)===null||r===void 0?void 0:r.className),role:"combobox","aria-expanded":$||!1,"aria-haspopup":"listbox","aria-owns":"".concat(i,"_list"),"aria-autocomplete":"list","aria-controls":"".concat(i,"_list"),"aria-activedescendant":$?v:void 0},E),{},{value:d?h:"",maxLength:g,readOnly:!d,unselectable:d?null:"on",style:U(U({},_),{},{opacity:d?null:0}),onKeyDown:function(M){p(M),I&&I(M)},onMouseDown:function(M){b(M),F&&F(M)},onChange:function(M){m(M),z&&z(M)},onCompositionStart:function(M){S(M),T&&T(M)},onCompositionEnd:function(M){x(M),D&&D(M)},onPaste:y})),w},Vw=f.exports.forwardRef(dA);function Uw(e){return Array.isArray(e)?e:e!==void 0?[e]:[]}var fA=typeof window<"u"&&window.document&&window.document.documentElement,vA=fA;function pA(e){return e!=null}function gA(e){return!e&&e!==0}function gb(e){return["string","number"].includes(Qe(e))}function Yw(e){var t=void 0;return e&&(gb(e.title)?t=e.title.toString():gb(e.label)&&(t=e.label.toString())),t}function hA(e,t){vA?f.exports.useLayoutEffect(e,t):f.exports.useEffect(e,t)}function mA(e){var t;return(t=e.key)!==null&&t!==void 0?t:e.value}var hb=function(t){t.preventDefault(),t.stopPropagation()},yA=function(t){var n=t.id,r=t.prefixCls,o=t.values,i=t.open,a=t.searchValue,l=t.autoClearSearchValue,s=t.inputRef,c=t.placeholder,u=t.disabled,d=t.mode,v=t.showSearch,h=t.autoFocus,g=t.autoComplete,p=t.activeDescendantId,b=t.tabIndex,m=t.removeIcon,y=t.maxTagCount,S=t.maxTagTextLength,x=t.maxTagPlaceholder,$=x===void 0?function(ae){return"+ ".concat(ae.length," ...")}:x,E=t.tagRender,w=t.onToggleOpen,R=t.onRemove,P=t.onInputChange,N=t.onInputPaste,I=t.onInputKeyDown,z=t.onInputMouseDown,F=t.onInputCompositionStart,T=t.onInputCompositionEnd,D=f.exports.useRef(null),_=f.exports.useState(0),O=G(_,2),M=O[0],L=O[1],A=f.exports.useState(!1),B=G(A,2),k=B[0],j=B[1],H="".concat(r,"-selection"),W=i||d==="multiple"&&l===!1||d==="tags"?a:"",Y=d==="tags"||d==="multiple"&&l===!1||v&&(i||k);hA(function(){L(D.current.scrollWidth)},[W]);var K=function(J,re,fe,ve,pe){return ie("span",{title:Yw(J),className:te("".concat(H,"-item"),V({},"".concat(H,"-item-disabled"),fe)),children:[C("span",{className:"".concat(H,"-item-content"),children:re}),ve&&C(af,{className:"".concat(H,"-item-remove"),onMouseDown:hb,onClick:pe,customizeIcon:m,children:"\xD7"})]})},q=function(J,re,fe,ve,pe){var oe=function(le){hb(le),w(!i)};return C("span",{onMouseDown:oe,children:E({label:re,value:J,disabled:fe,closable:ve,onClose:pe})})},ee=function(J){var re=J.disabled,fe=J.label,ve=J.value,pe=!u&&!re,oe=fe;if(typeof S=="number"&&(typeof fe=="string"||typeof fe=="number")){var se=String(oe);se.length>S&&(oe="".concat(se.slice(0,S),"..."))}var le=function(ce){ce&&ce.stopPropagation(),R(J)};return typeof E=="function"?q(ve,oe,re,pe,le):K(J,oe,re,pe,le)},Z=function(J){var re=typeof $=="function"?$(J):$;return K({title:re},re,!1)},Q=ie("div",{className:"".concat(H,"-search"),style:{width:M},onFocus:function(){j(!0)},onBlur:function(){j(!1)},children:[C(Vw,{ref:s,open:i,prefixCls:r,id:n,inputElement:null,disabled:u,autoFocus:h,autoComplete:g,editable:Y,activeDescendantId:p,value:W,onKeyDown:I,onMouseDown:z,onChange:P,onPaste:N,onCompositionStart:F,onCompositionEnd:T,tabIndex:b,attrs:Ka(t,!0)}),ie("span",{ref:D,className:"".concat(H,"-search-mirror"),"aria-hidden":!0,children:[W,"\xA0"]})]}),ne=C(Zr,{prefixCls:"".concat(H,"-overflow"),data:o,renderItem:ee,renderRest:Z,suffix:Q,itemKey:mA,maxCount:y});return ie(Tt,{children:[ne,!o.length&&!W&&C("span",{className:"".concat(H,"-placeholder"),children:c})]})},bA=function(t){var n=t.inputElement,r=t.prefixCls,o=t.id,i=t.inputRef,a=t.disabled,l=t.autoFocus,s=t.autoComplete,c=t.activeDescendantId,u=t.mode,d=t.open,v=t.values,h=t.placeholder,g=t.tabIndex,p=t.showSearch,b=t.searchValue,m=t.activeValue,y=t.maxLength,S=t.onInputKeyDown,x=t.onInputMouseDown,$=t.onInputChange,E=t.onInputPaste,w=t.onInputCompositionStart,R=t.onInputCompositionEnd,P=t.title,N=f.exports.useState(!1),I=G(N,2),z=I[0],F=I[1],T=u==="combobox",D=T||p,_=v[0],O=b||"";T&&m&&!z&&(O=m),f.exports.useEffect(function(){T&&F(!1)},[T,m]);var M=u!=="combobox"&&!d&&!p?!1:!!O,L=P===void 0?Yw(_):P,A=f.exports.useMemo(function(){return _?null:C("span",{className:"".concat(r,"-selection-placeholder"),style:M?{visibility:"hidden"}:void 0,children:h})},[_,M,h,r]);return ie(Tt,{children:[C("span",{className:"".concat(r,"-selection-search"),children:C(Vw,{ref:i,prefixCls:r,id:o,open:d,inputElement:n,disabled:a,autoFocus:l,autoComplete:s,editable:D,activeDescendantId:c,value:O,onKeyDown:S,onMouseDown:x,onChange:function(k){F(!0),$(k)},onPaste:E,onCompositionStart:w,onCompositionEnd:R,tabIndex:g,attrs:Ka(t,!0),maxLength:T?y:void 0})}),!T&&_?C("span",{className:"".concat(r,"-selection-item"),title:L,style:M?{visibility:"hidden"}:void 0,children:_.label}):null,A]})};function SA(e){return![ue.ESC,ue.SHIFT,ue.BACKSPACE,ue.TAB,ue.WIN_KEY,ue.ALT,ue.META,ue.WIN_KEY_RIGHT,ue.CTRL,ue.SEMICOLON,ue.EQUALS,ue.CAPS_LOCK,ue.CONTEXT_MENU,ue.F1,ue.F2,ue.F3,ue.F4,ue.F5,ue.F6,ue.F7,ue.F8,ue.F9,ue.F10,ue.F11,ue.F12].includes(e)}var CA=function(t,n){var r=f.exports.useRef(null),o=f.exports.useRef(!1),i=t.prefixCls,a=t.open,l=t.mode,s=t.showSearch,c=t.tokenWithEnter,u=t.autoClearSearchValue,d=t.onSearch,v=t.onSearchSubmit,h=t.onToggleOpen,g=t.onInputKeyDown,p=t.domRef;f.exports.useImperativeHandle(n,function(){return{focus:function(){r.current.focus()},blur:function(){r.current.blur()}}});var b=Bw(0),m=G(b,2),y=m[0],S=m[1],x=function(O){var M=O.which;(M===ue.UP||M===ue.DOWN)&&O.preventDefault(),g&&g(O),M===ue.ENTER&&l==="tags"&&!o.current&&!a&&(v==null||v(O.target.value)),SA(M)&&h(!0)},$=function(){S(!0)},E=f.exports.useRef(null),w=function(O){d(O,!0,o.current)!==!1&&h(!0)},R=function(){o.current=!0},P=function(O){o.current=!1,l!=="combobox"&&w(O.target.value)},N=function(O){var M=O.target.value;if(c&&E.current&&/[\r\n]/.test(E.current)){var L=E.current.replace(/[\r\n]+$/,"").replace(/\r\n/g," ").replace(/[\r\n]/g," ");M=M.replace(L,E.current)}E.current=null,w(M)},I=function(O){var M=O.clipboardData,L=M==null?void 0:M.getData("text");E.current=L||""},z=function(O){var M=O.target;if(M!==r.current){var L=document.body.style.msTouchAction!==void 0;L?setTimeout(function(){r.current.focus()}):r.current.focus()}},F=function(O){var M=y();O.target!==r.current&&!M&&l!=="combobox"&&O.preventDefault(),(l!=="combobox"&&(!s||!M)||!a)&&(a&&u!==!1&&d("",!0,!1),h())},T={inputRef:r,onInputKeyDown:x,onInputMouseDown:$,onInputChange:N,onInputPaste:I,onInputCompositionStart:R,onInputCompositionEnd:P},D=l==="multiple"||l==="tags"?C(yA,{...t,...T}):C(bA,{...t,...T});return C("div",{ref:p,className:"".concat(i,"-selector"),onClick:z,onMouseDown:F,children:D})},xA=f.exports.forwardRef(CA);function wA(e){var t=e.prefixCls,n=e.align,r=e.arrow,o=e.arrowPos,i=r||{},a=i.className,l=i.content,s=o.x,c=s===void 0?0:s,u=o.y,d=u===void 0?0:u,v=f.exports.useRef();if(!n||!n.points)return null;var h={position:"absolute"};if(n.autoArrow!==!1){var g=n.points[0],p=n.points[1],b=g[0],m=g[1],y=p[0],S=p[1];b===y||!["t","b"].includes(b)?h.top=d:b==="t"?h.top=0:h.bottom=0,m===S||!["l","r"].includes(m)?h.left=c:m==="l"?h.left=0:h.right=0}return C("div",{ref:v,className:te("".concat(t,"-arrow"),a),style:h,children:l})}function $A(e){var t=e.prefixCls,n=e.open,r=e.zIndex,o=e.mask,i=e.motion;return o?C(to,{...i,motionAppear:!0,visible:n,removeOnLeave:!0,children:function(a){var l=a.className;return C("div",{style:{zIndex:r},className:te("".concat(t,"-mask"),l)})}}):null}var EA=f.exports.memo(function(e){var t=e.children;return t},function(e,t){return t.cache}),MA=f.exports.forwardRef(function(e,t){var n=e.popup,r=e.className,o=e.prefixCls,i=e.style,a=e.target,l=e.onVisibleChanged,s=e.open,c=e.keepDom,u=e.fresh,d=e.onClick,v=e.mask,h=e.arrow,g=e.arrowPos,p=e.align,b=e.motion,m=e.maskMotion,y=e.forceRender,S=e.getPopupContainer,x=e.autoDestroy,$=e.portal,E=e.zIndex,w=e.onMouseEnter,R=e.onMouseLeave,P=e.onPointerEnter,N=e.ready,I=e.offsetX,z=e.offsetY,F=e.offsetR,T=e.offsetB,D=e.onAlign,_=e.onPrepare,O=e.stretch,M=e.targetWidth,L=e.targetHeight,A=typeof n=="function"?n():n,B=s||c,k=(S==null?void 0:S.length)>0,j=f.exports.useState(!S||!k),H=G(j,2),W=H[0],Y=H[1];if(Nt(function(){!W&&k&&a&&Y(!0)},[W,k,a]),!W)return null;var K="auto",q={left:"-1000vw",top:"-1000vh",right:K,bottom:K};if(N||!s){var ee,Z=p.points,Q=p.dynamicInset||((ee=p._experimental)===null||ee===void 0?void 0:ee.dynamicInset),ne=Q&&Z[0][1]==="r",ae=Q&&Z[0][0]==="b";ne?(q.right=F,q.left=K):(q.left=I,q.right=K),ae?(q.bottom=T,q.top=K):(q.top=z,q.bottom=K)}var J={};return O&&(O.includes("height")&&L?J.height=L:O.includes("minHeight")&&L&&(J.minHeight=L),O.includes("width")&&M?J.width=M:O.includes("minWidth")&&M&&(J.minWidth=M)),s||(J.pointerEvents="none"),ie($,{open:y||B,getContainer:S&&function(){return S(a)},autoDestroy:x,children:[C($A,{prefixCls:o,open:s,zIndex:E,mask:v,motion:m}),C(mr,{onResize:D,disabled:!s,children:function(re){return C(to,{motionAppear:!0,motionEnter:!0,motionLeave:!0,removeOnLeave:!1,forceRender:y,leavedClassName:"".concat(o,"-hidden"),...b,onAppearPrepare:_,onEnterPrepare:_,visible:s,onVisibleChanged:function(ve){var pe;b==null||(pe=b.onVisibleChanged)===null||pe===void 0||pe.call(b,ve),l(ve)},children:function(fe,ve){var pe=fe.className,oe=fe.style,se=te(o,pe,r);return ie("div",{ref:xr(re,t,ve),className:se,style:U(U(U(U({"--arrow-x":"".concat(g.x||0,"px"),"--arrow-y":"".concat(g.y||0,"px")},q),J),oe),{},{boxSizing:"border-box",zIndex:E},i),onMouseEnter:w,onMouseLeave:R,onPointerEnter:P,onClick:d,children:[h&&C(wA,{prefixCls:o,arrow:h,arrowPos:g,align:p}),C(EA,{cache:!s&&!u,children:A})]})}})}})]})}),OA=f.exports.forwardRef(function(e,t){var n=e.children,r=e.getTriggerDOMNode,o=ki(n),i=f.exports.useCallback(function(l){zh(t,r?r(l):l)},[r]),a=Fi(i,n.ref);return o?f.exports.cloneElement(n,{ref:a}):n}),mb=f.exports.createContext(null);function yb(e){return e?Array.isArray(e)?e:[e]:[]}function RA(e,t,n,r){return f.exports.useMemo(function(){var o=yb(n!=null?n:t),i=yb(r!=null?r:t),a=new Set(o),l=new Set(i);return e&&(a.has("hover")&&(a.delete("hover"),a.add("click")),l.has("hover")&&(l.delete("hover"),l.add("click"))),[a,l]},[e,t,n,r])}function IA(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:[],t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:[],n=arguments.length>2?arguments[2]:void 0;return n?e[0]===t[0]:e[0]===t[0]&&e[1]===t[1]}function PA(e,t,n,r){for(var o=n.points,i=Object.keys(e),a=0;a1&&arguments[1]!==void 0?arguments[1]:1;return Number.isNaN(e)?t:e}function xl(e){return Rs(parseFloat(e),0)}function Sb(e,t){var n=U({},e);return(t||[]).forEach(function(r){if(!(r instanceof HTMLBodyElement||r instanceof HTMLHtmlElement)){var o=qs(r).getComputedStyle(r),i=o.overflow,a=o.overflowClipMargin,l=o.borderTopWidth,s=o.borderBottomWidth,c=o.borderLeftWidth,u=o.borderRightWidth,d=r.getBoundingClientRect(),v=r.offsetHeight,h=r.clientHeight,g=r.offsetWidth,p=r.clientWidth,b=xl(l),m=xl(s),y=xl(c),S=xl(u),x=Rs(Math.round(d.width/g*1e3)/1e3),$=Rs(Math.round(d.height/v*1e3)/1e3),E=(g-p-y-S)*x,w=(v-h-b-m)*$,R=b*$,P=m*$,N=y*x,I=S*x,z=0,F=0;if(i==="clip"){var T=xl(a);z=T*x,F=T*$}var D=d.x+N-z,_=d.y+R-F,O=D+d.width+2*z-N-I-E,M=_+d.height+2*F-R-P-w;n.left=Math.max(n.left,D),n.top=Math.max(n.top,_),n.right=Math.min(n.right,O),n.bottom=Math.min(n.bottom,M)}}),n}function Cb(e){var t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:0,n="".concat(t),r=n.match(/^(.*)\%$/);return r?e*(parseFloat(r[1])/100):parseFloat(n)}function xb(e,t){var n=t||[],r=G(n,2),o=r[0],i=r[1];return[Cb(e.width,o),Cb(e.height,i)]}function wb(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:"";return[e[0],e[1]]}function Xi(e,t){var n=t[0],r=t[1],o,i;return n==="t"?i=e.y:n==="b"?i=e.y+e.height:i=e.y+e.height/2,r==="l"?o=e.x:r==="r"?o=e.x+e.width:o=e.x+e.width/2,{x:o,y:i}}function Mo(e,t){var n={t:"b",b:"t",l:"r",r:"l"};return e.map(function(r,o){return o===t?n[r]||"c":r}).join("")}function TA(e,t,n,r,o,i,a){var l=f.exports.useState({ready:!1,offsetX:0,offsetY:0,offsetR:0,offsetB:0,arrowX:0,arrowY:0,scaleX:1,scaleY:1,align:o[r]||{}}),s=G(l,2),c=s[0],u=s[1],d=f.exports.useRef(0),v=f.exports.useMemo(function(){return t?yg(t):[]},[t]),h=f.exports.useRef({}),g=function(){h.current={}};e||g();var p=hn(function(){if(t&&n&&e){let un=function(tc,ro){var si=arguments.length>2&&arguments[2]!==void 0?arguments[2]:se,Vi=A.x+tc,ul=A.y+ro,yf=Vi+ee,bf=ul+q,Sf=Math.max(Vi,si.left),Cf=Math.max(ul,si.top),je=Math.min(yf,si.right),tt=Math.min(bf,si.bottom);return Math.max(0,(je-Sf)*(tt-Cf))},cl=function(){ct=A.y+Le,We=ct+q,Ve=A.x+Xe,vt=Ve+ee};var Wi=un,iE=cl,y,S,x=t,$=x.ownerDocument,E=qs(x),w=E.getComputedStyle(x),R=w.width,P=w.height,N=w.position,I=x.style.left,z=x.style.top,F=x.style.right,T=x.style.bottom,D=x.style.overflow,_=U(U({},o[r]),i),O=$.createElement("div");(y=x.parentElement)===null||y===void 0||y.appendChild(O),O.style.left="".concat(x.offsetLeft,"px"),O.style.top="".concat(x.offsetTop,"px"),O.style.position=N,O.style.height="".concat(x.offsetHeight,"px"),O.style.width="".concat(x.offsetWidth,"px"),x.style.left="0",x.style.top="0",x.style.right="auto",x.style.bottom="auto",x.style.overflow="hidden";var M;if(Array.isArray(n))M={x:n[0],y:n[1],width:0,height:0};else{var L=n.getBoundingClientRect();M={x:L.x,y:L.y,width:L.width,height:L.height}}var A=x.getBoundingClientRect(),B=$.documentElement,k=B.clientWidth,j=B.clientHeight,H=B.scrollWidth,W=B.scrollHeight,Y=B.scrollTop,K=B.scrollLeft,q=A.height,ee=A.width,Z=M.height,Q=M.width,ne={left:0,top:0,right:k,bottom:j},ae={left:-K,top:-Y,right:H-K,bottom:W-Y},J=_.htmlRegion,re="visible",fe="visibleFirst";J!=="scroll"&&J!==fe&&(J=re);var ve=J===fe,pe=Sb(ae,v),oe=Sb(ne,v),se=J===re?oe:pe,le=ve?oe:se;x.style.left="auto",x.style.top="auto",x.style.right="0",x.style.bottom="0";var Ce=x.getBoundingClientRect();x.style.left=I,x.style.top=z,x.style.right=F,x.style.bottom=T,x.style.overflow=D,(S=x.parentElement)===null||S===void 0||S.removeChild(O);var ce=Rs(Math.round(ee/parseFloat(R)*1e3)/1e3),de=Rs(Math.round(q/parseFloat(P)*1e3)/1e3);if(ce===0||de===0||Wu(n)&&!Jd(n))return;var xe=_.offset,he=_.targetOffset,ke=xb(A,xe),we=G(ke,2),ge=we[0],Pe=we[1],Se=xb(M,he),st=G(Se,2),nt=st[0],Ne=st[1];M.x-=nt,M.y-=Ne;var Ee=_.points||[],_e=G(Ee,2),Be=_e[0],qe=_e[1],it=wb(qe),ft=wb(Be),ut=Xi(M,it),Ue=Xi(A,ft),He=U({},_),Xe=ut.x-Ue.x+ge,Le=ut.y-Ue.y+Pe,Re=un(Xe,Le),be=un(Xe,Le,oe),Ae=Xi(M,["t","l"]),Me=Xi(A,["t","l"]),$e=Xi(M,["b","r"]),Te=Xi(A,["b","r"]),ye=_.overflow||{},Ge=ye.adjustX,Ze=ye.adjustY,et=ye.shiftX,ht=ye.shiftY,mt=function(ro){return typeof ro=="boolean"?ro:ro>=0},ct,We,Ve,vt;cl();var Ie=mt(Ze),ze=ft[0]===it[0];if(Ie&&ft[0]==="t"&&(We>le.bottom||h.current.bt)){var Ke=Le;ze?Ke-=q-Z:Ke=Ae.y-Te.y-Pe;var at=un(Xe,Ke),Gt=un(Xe,Ke,oe);at>Re||at===Re&&(!ve||Gt>=be)?(h.current.bt=!0,Le=Ke,Pe=-Pe,He.points=[Mo(ft,0),Mo(it,0)]):h.current.bt=!1}if(Ie&&ft[0]==="b"&&(ctRe||Zt===Re&&(!ve||Jt>=be)?(h.current.tb=!0,Le=At,Pe=-Pe,He.points=[Mo(ft,0),Mo(it,0)]):h.current.tb=!1}var kn=mt(Ge),qn=ft[1]===it[1];if(kn&&ft[1]==="l"&&(vt>le.right||h.current.rl)){var pn=Xe;qn?pn-=ee-Q:pn=Ae.x-Te.x-ge;var Co=un(pn,Le),xo=un(pn,Le,oe);Co>Re||Co===Re&&(!ve||xo>=be)?(h.current.rl=!0,Xe=pn,ge=-ge,He.points=[Mo(ft,1),Mo(it,1)]):h.current.rl=!1}if(kn&&ft[1]==="r"&&(VeRe||wo===Re&&(!ve||wr>=be)?(h.current.lr=!0,Xe=In,ge=-ge,He.points=[Mo(ft,1),Mo(it,1)]):h.current.lr=!1}cl();var Bn=et===!0?0:et;typeof Bn=="number"&&(Veoe.right&&(Xe-=vt-oe.right-ge,M.x>oe.right-Bn&&(Xe+=M.x-oe.right+Bn)));var sr=ht===!0?0:ht;typeof sr=="number"&&(ctoe.bottom&&(Le-=We-oe.bottom-Pe,M.y>oe.bottom-sr&&(Le+=M.y-oe.bottom+sr)));var $r=A.x+Xe,Ur=$r+ee,Xn=A.y+Le,$o=Xn+q,Er=M.x,bt=Er+Q,dt=M.y,Fe=dt+Z,Ye=Math.max($r,Er),yt=Math.min(Ur,bt),Bt=(Ye+yt)/2,It=Bt-$r,Kt=Math.max(Xn,dt),sn=Math.min($o,Fe),Pn=(Kt+sn)/2,cn=Pn-Xn;a==null||a(t,He);var Tn=Ce.right-A.x-(Xe+A.width),jn=Ce.bottom-A.y-(Le+A.height);u({ready:!0,offsetX:Xe/ce,offsetY:Le/de,offsetR:Tn/ce,offsetB:jn/de,arrowX:It/ce,arrowY:cn/de,scaleX:ce,scaleY:de,align:He})}}),b=function(){d.current+=1;var S=d.current;Promise.resolve().then(function(){d.current===S&&p()})},m=function(){u(function(S){return U(U({},S),{},{ready:!1})})};return Nt(m,[r]),Nt(function(){e||m()},[e]),[c.ready,c.offsetX,c.offsetY,c.offsetR,c.offsetB,c.arrowX,c.arrowY,c.scaleX,c.scaleY,c.align,b]}function NA(e,t,n,r,o){Nt(function(){if(e&&t&&n){let v=function(){r(),o()};var d=v,i=t,a=n,l=yg(i),s=yg(a),c=qs(a),u=new Set([c].concat(Oe(l),Oe(s)));return u.forEach(function(h){h.addEventListener("scroll",v,{passive:!0})}),c.addEventListener("resize",v,{passive:!0}),r(),function(){u.forEach(function(h){h.removeEventListener("scroll",v),c.removeEventListener("resize",v)})}}},[e,t,n])}function _A(e,t,n,r,o,i,a,l){var s=f.exports.useRef(e),c=f.exports.useRef(!1);s.current!==e&&(c.current=!0,s.current=e),f.exports.useEffect(function(){var u=St(function(){c.current=!1});return function(){St.cancel(u)}},[e]),f.exports.useEffect(function(){if(t&&r&&(!o||i)){var u=function(){var E=!1,w=function(N){var I=N.target;E=a(I)},R=function(N){var I=N.target;!c.current&&s.current&&!E&&!a(I)&&l(!1)};return[w,R]},d=u(),v=G(d,2),h=v[0],g=v[1],p=u(),b=G(p,2),m=b[0],y=b[1],S=qs(r);S.addEventListener("mousedown",h,!0),S.addEventListener("click",g,!0),S.addEventListener("contextmenu",g,!0);var x=Hu(n);return x&&(x.addEventListener("mousedown",m,!0),x.addEventListener("click",y,!0),x.addEventListener("contextmenu",y,!0)),function(){S.removeEventListener("mousedown",h,!0),S.removeEventListener("click",g,!0),S.removeEventListener("contextmenu",g,!0),x&&(x.removeEventListener("mousedown",m,!0),x.removeEventListener("click",y,!0),x.removeEventListener("contextmenu",y,!0))}}},[t,n,r,o,i])}var AA=["prefixCls","children","action","showAction","hideAction","popupVisible","defaultPopupVisible","onPopupVisibleChange","afterPopupVisibleChange","mouseEnterDelay","mouseLeaveDelay","focusDelay","blurDelay","mask","maskClosable","getPopupContainer","forceRender","autoDestroy","destroyPopupOnHide","popup","popupClassName","popupStyle","popupPlacement","builtinPlacements","popupAlign","zIndex","stretch","getPopupClassNameFromAlign","fresh","alignPoint","onPopupClick","onPopupAlign","arrow","popupMotion","maskMotion","popupTransitionName","popupAnimation","maskTransitionName","maskAnimation","className","getTriggerDOMNode"];function DA(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:nf,t=f.exports.forwardRef(function(n,r){var o=n.prefixCls,i=o===void 0?"rc-trigger-popup":o,a=n.children,l=n.action,s=l===void 0?"hover":l,c=n.showAction,u=n.hideAction,d=n.popupVisible,v=n.defaultPopupVisible,h=n.onPopupVisibleChange,g=n.afterPopupVisibleChange,p=n.mouseEnterDelay,b=n.mouseLeaveDelay,m=b===void 0?.1:b,y=n.focusDelay,S=n.blurDelay,x=n.mask,$=n.maskClosable,E=$===void 0?!0:$,w=n.getPopupContainer,R=n.forceRender,P=n.autoDestroy,N=n.destroyPopupOnHide,I=n.popup,z=n.popupClassName,F=n.popupStyle,T=n.popupPlacement,D=n.builtinPlacements,_=D===void 0?{}:D,O=n.popupAlign,M=n.zIndex,L=n.stretch,A=n.getPopupClassNameFromAlign,B=n.fresh,k=n.alignPoint,j=n.onPopupClick,H=n.onPopupAlign,W=n.arrow,Y=n.popupMotion,K=n.maskMotion,q=n.popupTransitionName,ee=n.popupAnimation,Z=n.maskTransitionName,Q=n.maskAnimation,ne=n.className,ae=n.getTriggerDOMNode,J=Je(n,AA),re=P||N||!1,fe=f.exports.useState(!1),ve=G(fe,2),pe=ve[0],oe=ve[1];Nt(function(){oe(am())},[]);var se=f.exports.useRef({}),le=f.exports.useContext(mb),Ce=f.exports.useMemo(function(){return{registerSubPopup:function(tt,Vt){se.current[tt]=Vt,le==null||le.registerSubPopup(tt,Vt)}}},[le]),ce=Rw(),de=f.exports.useState(null),xe=G(de,2),he=xe[0],ke=xe[1],we=hn(function(je){Wu(je)&&he!==je&&ke(je),le==null||le.registerSubPopup(ce,je)}),ge=f.exports.useState(null),Pe=G(ge,2),Se=Pe[0],st=Pe[1],nt=f.exports.useRef(null),Ne=hn(function(je){Wu(je)&&Se!==je&&(st(je),nt.current=je)}),Ee=f.exports.Children.only(a),_e=(Ee==null?void 0:Ee.props)||{},Be={},qe=hn(function(je){var tt,Vt,nn=Se;return(nn==null?void 0:nn.contains(je))||((tt=Hu(nn))===null||tt===void 0?void 0:tt.host)===je||je===nn||(he==null?void 0:he.contains(je))||((Vt=Hu(he))===null||Vt===void 0?void 0:Vt.host)===je||je===he||Object.values(se.current).some(function(Ut){return(Ut==null?void 0:Ut.contains(je))||je===Ut})}),it=bb(i,Y,ee,q),ft=bb(i,K,Q,Z),ut=f.exports.useState(v||!1),Ue=G(ut,2),He=Ue[0],Xe=Ue[1],Le=d!=null?d:He,Re=hn(function(je){d===void 0&&Xe(je)});Nt(function(){Xe(d||!1)},[d]);var be=f.exports.useRef(Le);be.current=Le;var Ae=f.exports.useRef([]);Ae.current=[];var Me=hn(function(je){var tt;Re(je),((tt=Ae.current[Ae.current.length-1])!==null&&tt!==void 0?tt:Le)!==je&&(Ae.current.push(je),h==null||h(je))}),$e=f.exports.useRef(),Te=function(){clearTimeout($e.current)},ye=function(tt){var Vt=arguments.length>1&&arguments[1]!==void 0?arguments[1]:0;Te(),Vt===0?Me(tt):$e.current=setTimeout(function(){Me(tt)},Vt*1e3)};f.exports.useEffect(function(){return Te},[]);var Ge=f.exports.useState(!1),Ze=G(Ge,2),et=Ze[0],ht=Ze[1];Nt(function(je){(!je||Le)&&ht(!0)},[Le]);var mt=f.exports.useState(null),ct=G(mt,2),We=ct[0],Ve=ct[1],vt=f.exports.useState([0,0]),Ie=G(vt,2),ze=Ie[0],Ke=Ie[1],at=function(tt){Ke([tt.clientX,tt.clientY])},Gt=TA(Le,he,k?ze:Se,T,_,O,H),At=G(Gt,11),Zt=At[0],Jt=At[1],kn=At[2],qn=At[3],pn=At[4],Co=At[5],xo=At[6],In=At[7],wo=At[8],wr=At[9],Bn=At[10],sr=RA(pe,s,c,u),$r=G(sr,2),Ur=$r[0],Xn=$r[1],$o=Ur.has("click"),Er=Xn.has("click")||Xn.has("contextMenu"),bt=hn(function(){et||Bn()}),dt=function(){be.current&&k&&Er&&ye(!1)};NA(Le,Se,he,bt,dt),Nt(function(){bt()},[ze,T]),Nt(function(){Le&&!(_!=null&&_[T])&&bt()},[JSON.stringify(O)]);var Fe=f.exports.useMemo(function(){var je=PA(_,i,wr,k);return te(je,A==null?void 0:A(wr))},[wr,A,_,i,k]);f.exports.useImperativeHandle(r,function(){return{nativeElement:nt.current,forceAlign:bt}});var Ye=f.exports.useState(0),yt=G(Ye,2),Bt=yt[0],It=yt[1],Kt=f.exports.useState(0),sn=G(Kt,2),Pn=sn[0],cn=sn[1],Tn=function(){if(L&&Se){var tt=Se.getBoundingClientRect();It(tt.width),cn(tt.height)}},jn=function(){Tn(),bt()},Wi=function(tt){ht(!1),Bn(),g==null||g(tt)},iE=function(){return new Promise(function(tt){Tn(),Ve(function(){return tt})})};Nt(function(){We&&(Bn(),We(),Ve(null))},[We]);function un(je,tt,Vt,nn){Be[je]=function(Ut){var nc;nn==null||nn(Ut),ye(tt,Vt);for(var xf=arguments.length,km=new Array(xf>1?xf-1:0),rc=1;rc1?Vt-1:0),Ut=1;Ut1?Vt-1:0),Ut=1;Ut1&&arguments[1]!==void 0?arguments[1]:{},n=t.fieldNames,r=t.childrenAsData,o=[],i=Gw(n,!1),a=i.label,l=i.value,s=i.options,c=i.groupLabel;function u(d,v){!Array.isArray(d)||d.forEach(function(h){if(v||!(s in h)){var g=h[l];o.push({key:$b(h,o.length),groupOption:v,data:h,label:h[a],value:g})}else{var p=h[c];p===void 0&&r&&(p=h.label),o.push({key:$b(h,o.length),group:!0,data:h,label:p}),u(h[s],!0)}})}return u(e,!1),o}function bg(e){var t=U({},e);return"props"in t||Object.defineProperty(t,"props",{get:function(){return Mn(!1,"Return type is option instead of Option instance. Please read value directly instead of reading from `props`."),t}}),t}var jA=function(t,n,r){if(!n||!n.length)return null;var o=!1,i=function l(s,c){var u=kx(c),d=u[0],v=u.slice(1);if(!d)return[s];var h=s.split(d);return o=o||h.length>1,h.reduce(function(g,p){return[].concat(Oe(g),Oe(l(p,v)))},[]).filter(Boolean)},a=i(t,n);return o?typeof r<"u"?a.slice(0,r):a:null},lm=f.exports.createContext(null),HA=["id","prefixCls","className","showSearch","tagRender","direction","omitDomProps","displayValues","onDisplayValuesChange","emptyOptions","notFoundContent","onClear","mode","disabled","loading","getInputElement","getRawInputElement","open","defaultOpen","onDropdownVisibleChange","activeValue","onActiveValueChange","activeDescendantId","searchValue","autoClearSearchValue","onSearch","onSearchSplit","tokenSeparators","allowClear","suffixIcon","clearIcon","OptionList","animation","transitionName","dropdownStyle","dropdownClassName","dropdownMatchSelectWidth","dropdownRender","dropdownAlign","placement","builtinPlacements","getPopupContainer","showAction","onFocus","onBlur","onKeyUp","onKeyDown","onMouseDown"],WA=["value","onChange","removeIcon","placeholder","autoFocus","maxTagCount","maxTagTextLength","maxTagPlaceholder","choiceTransitionName","onInputKeyDown","onPopupScroll","tabIndex"],Sg=function(t){return t==="tags"||t==="multiple"},VA=f.exports.forwardRef(function(e,t){var n,r,o=e.id,i=e.prefixCls,a=e.className,l=e.showSearch,s=e.tagRender,c=e.direction,u=e.omitDomProps,d=e.displayValues,v=e.onDisplayValuesChange,h=e.emptyOptions,g=e.notFoundContent,p=g===void 0?"Not Found":g,b=e.onClear,m=e.mode,y=e.disabled,S=e.loading,x=e.getInputElement,$=e.getRawInputElement,E=e.open,w=e.defaultOpen,R=e.onDropdownVisibleChange,P=e.activeValue,N=e.onActiveValueChange,I=e.activeDescendantId,z=e.searchValue,F=e.autoClearSearchValue,T=e.onSearch,D=e.onSearchSplit,_=e.tokenSeparators,O=e.allowClear,M=e.suffixIcon,L=e.clearIcon,A=e.OptionList,B=e.animation,k=e.transitionName,j=e.dropdownStyle,H=e.dropdownClassName,W=e.dropdownMatchSelectWidth,Y=e.dropdownRender,K=e.dropdownAlign,q=e.placement,ee=e.builtinPlacements,Z=e.getPopupContainer,Q=e.showAction,ne=Q===void 0?[]:Q,ae=e.onFocus,J=e.onBlur,re=e.onKeyUp,fe=e.onKeyDown,ve=e.onMouseDown,pe=Je(e,HA),oe=Sg(m),se=(l!==void 0?l:oe)||m==="combobox",le=U({},pe);WA.forEach(function(Fe){delete le[Fe]}),u==null||u.forEach(function(Fe){delete le[Fe]});var Ce=f.exports.useState(!1),ce=G(Ce,2),de=ce[0],xe=ce[1];f.exports.useEffect(function(){xe(am())},[]);var he=f.exports.useRef(null),ke=f.exports.useRef(null),we=f.exports.useRef(null),ge=f.exports.useRef(null),Pe=f.exports.useRef(null),Se=f.exports.useRef(!1),st=Z_(),nt=G(st,3),Ne=nt[0],Ee=nt[1],_e=nt[2];f.exports.useImperativeHandle(t,function(){var Fe,Ye;return{focus:(Fe=ge.current)===null||Fe===void 0?void 0:Fe.focus,blur:(Ye=ge.current)===null||Ye===void 0?void 0:Ye.blur,scrollTo:function(Bt){var It;return(It=Pe.current)===null||It===void 0?void 0:It.scrollTo(Bt)}}});var Be=f.exports.useMemo(function(){var Fe;if(m!=="combobox")return z;var Ye=(Fe=d[0])===null||Fe===void 0?void 0:Fe.value;return typeof Ye=="string"||typeof Ye=="number"?String(Ye):""},[z,m,d]),qe=m==="combobox"&&typeof x=="function"&&x()||null,it=typeof $=="function"&&$(),ft=Fi(ke,it==null||(n=it.props)===null||n===void 0?void 0:n.ref),ut=f.exports.useState(!1),Ue=G(ut,2),He=Ue[0],Xe=Ue[1];Nt(function(){Xe(!0)},[]);var Le=kt(!1,{defaultValue:w,value:E}),Re=G(Le,2),be=Re[0],Ae=Re[1],Me=He?be:!1,$e=!p&&h;(y||$e&&Me&&m==="combobox")&&(Me=!1);var Te=$e?!1:Me,ye=f.exports.useCallback(function(Fe){var Ye=Fe!==void 0?Fe:!Me;y||(Ae(Ye),Me!==Ye&&(R==null||R(Ye)))},[y,Me,Ae,R]),Ge=f.exports.useMemo(function(){return(_||[]).some(function(Fe){return[` +`,`\r +`].includes(Fe)})},[_]),Ze=f.exports.useContext(lm)||{},et=Ze.maxCount,ht=Ze.rawValues,mt=function(Ye,yt,Bt){if(!((ht==null?void 0:ht.size)>=et)){var It=!0,Kt=Ye;N==null||N(null);var sn=jA(Ye,_,et&&et-ht.size),Pn=Bt?null:sn;return m!=="combobox"&&Pn&&(Kt="",D==null||D(Pn),ye(!1),It=!1),T&&Be!==Kt&&T(Kt,{source:yt?"typing":"effect"}),It}},ct=function(Ye){!Ye||!Ye.trim()||T(Ye,{source:"submit"})};f.exports.useEffect(function(){!Me&&!oe&&m!=="combobox"&&mt("",!1,!1)},[Me]),f.exports.useEffect(function(){be&&y&&Ae(!1),y&&!Se.current&&Ee(!1)},[y]);var We=Bw(),Ve=G(We,2),vt=Ve[0],Ie=Ve[1],ze=function(Ye){var yt=vt(),Bt=Ye.which;if(Bt===ue.ENTER&&(m!=="combobox"&&Ye.preventDefault(),Me||ye(!0)),Ie(!!Be),Bt===ue.BACKSPACE&&!yt&&oe&&!Be&&d.length){for(var It=Oe(d),Kt=null,sn=It.length-1;sn>=0;sn-=1){var Pn=It[sn];if(!Pn.disabled){It.splice(sn,1),Kt=Pn;break}}Kt&&v(It,{type:"remove",values:[Kt]})}for(var cn=arguments.length,Tn=new Array(cn>1?cn-1:0),jn=1;jn1?yt-1:0),It=1;It1?sn-1:0),cn=1;cn0&&arguments[0]!==void 0?arguments[0]:!1;u();var g=function(){l.current.forEach(function(b,m){if(b&&b.offsetParent){var y=ql(b),S=y.offsetHeight;s.current.get(m)!==S&&s.current.set(m,y.offsetHeight)}}),a(function(b){return b+1})};h?g():c.current=St(g)}function v(h,g){var p=e(h),b=l.current.get(p);g?(l.current.set(p,g),d()):l.current.delete(p),!b!=!g&&(g?t==null||t(h):n==null||n(h))}return f.exports.useEffect(function(){return u},[]),[v,d,s.current,i]}var qA=10;function XA(e,t,n,r,o,i,a,l){var s=f.exports.useRef(),c=f.exports.useState(null),u=G(c,2),d=u[0],v=u[1];return Nt(function(){if(d&&d.times=0;T-=1){var D=o(t[T]),_=n.get(D);if(_===void 0){y=!0;break}if(F-=_,F<=0)break}switch($){case"top":x=w-b;break;case"bottom":x=R-m+b;break;default:{var O=e.current.scrollTop,M=O+m;wM&&(S="bottom")}}x!==null&&a(x),x!==d.lastTop&&(y=!0)}y&&v(U(U({},d),{},{times:d.times+1,targetAlign:S,lastTop:x}))}},[d,e.current]),function(h){if(h==null){l();return}if(St.cancel(s.current),typeof h=="number")a(h);else if(h&&Qe(h)==="object"){var g,p=h.align;"index"in h?g=h.index:g=t.findIndex(function(y){return o(y)===h.key});var b=h.offset,m=b===void 0?0:b;v({times:0,index:g,offset:m,originAlign:p})}}}function QA(e,t,n){var r=e.length,o=t.length,i,a;if(r===0&&o===0)return null;r"u"?"undefined":Qe(navigator))==="object"&&/Firefox/i.test(navigator.userAgent);const qw=function(e,t){var n=f.exports.useRef(!1),r=f.exports.useRef(null);function o(){clearTimeout(r.current),n.current=!0,r.current=setTimeout(function(){n.current=!1},50)}var i=f.exports.useRef({top:e,bottom:t});return i.current.top=e,i.current.bottom=t,function(a){var l=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1,s=a<0&&i.current.top||a>0&&i.current.bottom;return l&&s?(clearTimeout(r.current),n.current=!1):(!s||n.current)&&o(),!n.current&&s}};function JA(e,t,n,r,o){var i=f.exports.useRef(0),a=f.exports.useRef(null),l=f.exports.useRef(null),s=f.exports.useRef(!1),c=qw(t,n);function u(b,m){St.cancel(a.current),i.current+=m,l.current=m,!c(m)&&(Ob||b.preventDefault(),a.current=St(function(){var y=s.current?10:1;o(i.current*y),i.current=0}))}function d(b,m){o(m,!0),Ob||b.preventDefault()}var v=f.exports.useRef(null),h=f.exports.useRef(null);function g(b){if(!!e){St.cancel(h.current),h.current=St(function(){v.current=null},2);var m=b.deltaX,y=b.deltaY,S=b.shiftKey,x=m,$=y;(v.current==="sx"||!v.current&&(S||!1)&&y&&!m)&&(x=y,$=0,v.current="sx");var E=Math.abs(x),w=Math.abs($);v.current===null&&(v.current=r&&E>w?"x":"y"),v.current==="y"?u(b,$):d(b,x)}}function p(b){!e||(s.current=b.detail===l.current)}return[g,p]}var e8=14/15;function t8(e,t,n){var r=f.exports.useRef(!1),o=f.exports.useRef(0),i=f.exports.useRef(null),a=f.exports.useRef(null),l,s=function(v){if(r.current){var h=Math.ceil(v.touches[0].pageY),g=o.current-h;o.current=h,n(g)&&v.preventDefault(),clearInterval(a.current),a.current=setInterval(function(){g*=e8,(!n(g,!0)||Math.abs(g)<=.1)&&clearInterval(a.current)},16)}},c=function(){r.current=!1,l()},u=function(v){l(),v.touches.length===1&&!r.current&&(r.current=!0,o.current=Math.ceil(v.touches[0].pageY),i.current=v.target,i.current.addEventListener("touchmove",s),i.current.addEventListener("touchend",c))};l=function(){i.current&&(i.current.removeEventListener("touchmove",s),i.current.removeEventListener("touchend",c))},Nt(function(){return e&&t.current.addEventListener("touchstart",u),function(){var d;(d=t.current)===null||d===void 0||d.removeEventListener("touchstart",u),l(),clearInterval(a.current)}},[e])}var n8=20;function Rb(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:0,t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:0,n=e/t*e;return isNaN(n)&&(n=0),n=Math.max(n,n8),Math.floor(n)}function r8(e,t,n,r){var o=f.exports.useMemo(function(){return[new Map,[]]},[e,n.id,r]),i=G(o,2),a=i[0],l=i[1],s=function(u){var d=arguments.length>1&&arguments[1]!==void 0?arguments[1]:u,v=a.get(u),h=a.get(d);if(v===void 0||h===void 0)for(var g=e.length,p=l.length;pi||!!p),I=g==="rtl",z=te(r,V({},"".concat(r,"-rtl"),I),o),F=u||i8,T=f.exports.useRef(),D=f.exports.useRef(),_=f.exports.useState(0),O=G(_,2),M=O[0],L=O[1],A=f.exports.useState(0),B=G(A,2),k=B[0],j=B[1],H=f.exports.useState(!1),W=G(H,2),Y=W[0],K=W[1],q=function(){K(!0)},ee=function(){K(!1)},Z=f.exports.useCallback(function(Ie){return typeof v=="function"?v(Ie):Ie==null?void 0:Ie[v]},[v]),Q={getKey:Z};function ne(Ie){L(function(ze){var Ke;typeof Ie=="function"?Ke=Ie(ze):Ke=Ie;var at=ft(Ke);return T.current.scrollTop=at,at})}var ae=f.exports.useRef({start:0,end:F.length}),J=f.exports.useRef(),re=ZA(F,Z),fe=G(re,1),ve=fe[0];J.current=ve;var pe=KA(Z,null,null),oe=G(pe,4),se=oe[0],le=oe[1],Ce=oe[2],ce=oe[3],de=f.exports.useMemo(function(){if(!P)return{scrollHeight:void 0,start:0,end:F.length-1,offset:void 0};if(!N){var Ie;return{scrollHeight:((Ie=D.current)===null||Ie===void 0?void 0:Ie.offsetHeight)||0,start:0,end:F.length-1,offset:void 0}}for(var ze=0,Ke,at,Gt,At=F.length,Zt=0;Zt=M&&Ke===void 0&&(Ke=Zt,at=ze),pn>M+i&&Gt===void 0&&(Gt=Zt),ze=pn}return Ke===void 0&&(Ke=0,at=0,Gt=Math.ceil(i/a)),Gt===void 0&&(Gt=F.length-1),Gt=Math.min(Gt+1,F.length-1),{scrollHeight:ze,start:Ke,end:Gt,offset:at}},[N,P,M,F,ce,i]),xe=de.scrollHeight,he=de.start,ke=de.end,we=de.offset;ae.current.start=he,ae.current.end=ke;var ge=f.exports.useState({width:0,height:i}),Pe=G(ge,2),Se=Pe[0],st=Pe[1],nt=function(ze){st({width:ze.width||ze.offsetWidth,height:ze.height||ze.offsetHeight})},Ne=f.exports.useRef(),Ee=f.exports.useRef(),_e=f.exports.useMemo(function(){return Rb(Se.width,p)},[Se.width,p]),Be=f.exports.useMemo(function(){return Rb(Se.height,xe)},[Se.height,xe]),qe=xe-i,it=f.exports.useRef(qe);it.current=qe;function ft(Ie){var ze=Ie;return Number.isNaN(it.current)||(ze=Math.min(ze,it.current)),ze=Math.max(ze,0),ze}var ut=M<=0,Ue=M>=qe,He=qw(ut,Ue),Xe=function(){return{x:I?-k:k,y:M}},Le=f.exports.useRef(Xe()),Re=hn(function(){if(S){var Ie=Xe();(Le.current.x!==Ie.x||Le.current.y!==Ie.y)&&(S(Ie),Le.current=Ie)}});function be(Ie,ze){var Ke=Ie;ze?(Gn.exports.flushSync(function(){j(Ke)}),Re()):ne(Ke)}function Ae(Ie){var ze=Ie.currentTarget.scrollTop;ze!==M&&ne(ze),y==null||y(Ie),Re()}var Me=function(ze){var Ke=ze,at=p-Se.width;return Ke=Math.max(Ke,0),Ke=Math.min(Ke,at),Ke},$e=hn(function(Ie,ze){ze?(Gn.exports.flushSync(function(){j(function(Ke){var at=Ke+(I?-Ie:Ie);return Me(at)})}),Re()):ne(function(Ke){var at=Ke+Ie;return at})}),Te=JA(P,ut,Ue,!!p,$e),ye=G(Te,2),Ge=ye[0],Ze=ye[1];t8(P,T,function(Ie,ze){return He(Ie,ze)?!1:(Ge({preventDefault:function(){},deltaY:Ie}),!0)}),Nt(function(){function Ie(Ke){P&&Ke.preventDefault()}var ze=T.current;return ze.addEventListener("wheel",Ge),ze.addEventListener("DOMMouseScroll",Ze),ze.addEventListener("MozMousePixelScroll",Ie),function(){ze.removeEventListener("wheel",Ge),ze.removeEventListener("DOMMouseScroll",Ze),ze.removeEventListener("MozMousePixelScroll",Ie)}},[P]),Nt(function(){p&&j(function(Ie){return Me(Ie)})},[Se.width,p]);var et=function(){var ze,Ke;(ze=Ne.current)===null||ze===void 0||ze.delayHidden(),(Ke=Ee.current)===null||Ke===void 0||Ke.delayHidden()},ht=XA(T,F,Ce,a,Z,function(){return le(!0)},ne,et);f.exports.useImperativeHandle(t,function(){return{getScrollInfo:Xe,scrollTo:function(ze){function Ke(at){return at&&Qe(at)==="object"&&("left"in at||"top"in at)}Ke(ze)?(ze.left!==void 0&&j(Me(ze.left)),ht(ze.top)):ht(ze)}}}),Nt(function(){if(x){var Ie=F.slice(he,ke+1);x(Ie,F)}},[he,ke,F]);var mt=r8(F,Z,Ce,a),ct=E==null?void 0:E({start:he,end:ke,virtual:N,offsetX:k,offsetY:we,rtl:I,getSize:mt}),We=YA(F,he,ke,p,se,d,Q),Ve=null;i&&(Ve=U(V({},s?"height":"maxHeight",i),a8),P&&(Ve.overflowY="hidden",p&&(Ve.overflowX="hidden"),Y&&(Ve.pointerEvents="none")));var vt={};return I&&(vt.dir="rtl"),ie("div",{style:U(U({},c),{},{position:"relative"}),className:z,...vt,...R,children:[C(mr,{onResize:nt,children:C(m,{className:"".concat(r,"-holder"),style:Ve,ref:T,onScroll:Ae,onMouseEnter:et,children:C(Kw,{prefixCls:r,height:xe,offsetX:k,offsetY:we,scrollWidth:p,onInnerResize:le,ref:D,innerProps:$,rtl:I,extra:ct,children:We})})}),N&&xe>i&&C(Mb,{ref:Ne,prefixCls:r,scrollOffset:M,scrollRange:xe,rtl:I,onScroll:be,onStartMove:q,onStopMove:ee,spinSize:Be,containerSize:Se.height,style:w==null?void 0:w.verticalScrollBar,thumbStyle:w==null?void 0:w.verticalScrollBarThumb}),N&&p>Se.width&&C(Mb,{ref:Ee,prefixCls:r,scrollOffset:k,scrollRange:p,rtl:I,onScroll:be,onStartMove:q,onStopMove:ee,spinSize:_e,containerSize:Se.width,horizontal:!0,style:w==null?void 0:w.horizontalScrollBar,thumbStyle:w==null?void 0:w.horizontalScrollBarThumb})]})}var Xw=f.exports.forwardRef(l8);Xw.displayName="List";function s8(){return/(mac\sos|macintosh)/i.test(navigator.appVersion)}var c8=["disabled","title","children","style","className"];function Ib(e){return typeof e=="string"||typeof e=="number"}var u8=function(t,n){var r=Q_(),o=r.prefixCls,i=r.id,a=r.open,l=r.multiple,s=r.mode,c=r.searchValue,u=r.toggleOpen,d=r.notFoundContent,v=r.onPopupScroll,h=f.exports.useContext(lm),g=h.maxCount,p=h.flattenOptions,b=h.onActiveValue,m=h.defaultActiveFirstOption,y=h.onSelect,S=h.menuItemSelectedIcon,x=h.rawValues,$=h.fieldNames,E=h.virtual,w=h.direction,R=h.listHeight,P=h.listItemHeight,N=h.optionRender,I="".concat(o,"-item"),z=Hs(function(){return p},[a,p],function(Z,Q){return Q[0]&&Z[1]!==Q[1]}),F=f.exports.useRef(null),T=f.exports.useMemo(function(){return l&&typeof g<"u"&&(x==null?void 0:x.size)>=g},[l,g,x==null?void 0:x.size]),D=function(Q){Q.preventDefault()},_=function(Q){var ne;(ne=F.current)===null||ne===void 0||ne.scrollTo(typeof Q=="number"?{index:Q}:Q)},O=function(Q){for(var ne=arguments.length>1&&arguments[1]!==void 0?arguments[1]:1,ae=z.length,J=0;J1&&arguments[1]!==void 0?arguments[1]:!1;B(Q);var ae={source:ne?"keyboard":"mouse"},J=z[Q];if(!J){b(null,-1,ae);return}b(J.value,Q,ae)};f.exports.useEffect(function(){k(m!==!1?O(0):-1)},[z.length,c]);var j=f.exports.useCallback(function(Z){return x.has(Z)&&s!=="combobox"},[s,Oe(x).toString(),x.size]);f.exports.useEffect(function(){var Z=setTimeout(function(){if(!l&&a&&x.size===1){var ne=Array.from(x)[0],ae=z.findIndex(function(J){var re=J.data;return re.value===ne});ae!==-1&&(k(ae),_(ae))}});if(a){var Q;(Q=F.current)===null||Q===void 0||Q.scrollTo(void 0)}return function(){return clearTimeout(Z)}},[a,c]);var H=function(Q){Q!==void 0&&y(Q,{selected:!x.has(Q)}),l||u(!1)};if(f.exports.useImperativeHandle(n,function(){return{onKeyDown:function(Q){var ne=Q.which,ae=Q.ctrlKey;switch(ne){case ue.N:case ue.P:case ue.UP:case ue.DOWN:{var J=0;if(ne===ue.UP?J=-1:ne===ue.DOWN?J=1:s8()&&ae&&(ne===ue.N?J=1:ne===ue.P&&(J=-1)),J!==0){var re=O(A+J,J);_(re),k(re,!0)}break}case ue.ENTER:{var fe,ve=z[A];ve&&!(ve!=null&&(fe=ve.data)!==null&&fe!==void 0&&fe.disabled)&&!T?H(ve.value):H(void 0),a&&Q.preventDefault();break}case ue.ESC:u(!1),a&&Q.stopPropagation()}},onKeyUp:function(){},scrollTo:function(Q){_(Q)}}}),z.length===0)return C("div",{role:"listbox",id:"".concat(i,"_list"),className:"".concat(I,"-empty"),onMouseDown:D,children:d});var W=Object.keys($).map(function(Z){return $[Z]}),Y=function(Q){return Q.label};function K(Z,Q){var ne=Z.group;return{role:ne?"presentation":"option",id:"".concat(i,"_list_").concat(Q)}}var q=function(Q){var ne=z[Q];if(!ne)return null;var ae=ne.data||{},J=ae.value,re=ne.group,fe=Ka(ae,!0),ve=Y(ne);return ne?f.exports.createElement("div",{"aria-label":typeof ve=="string"&&!re?ve:null,...fe,key:Q,...K(ne,Q),"aria-selected":j(J)},J):null},ee={role:"listbox",id:"".concat(i,"_list")};return ie(Tt,{children:[E&&ie("div",{...ee,style:{height:0,width:0,overflow:"hidden"},children:[q(A-1),q(A),q(A+1)]}),C(Xw,{itemKey:"key",ref:F,data:z,height:R,itemHeight:P,fullHeight:!1,onMouseDown:D,onScroll:v,virtual:E,direction:w,innerProps:E?null:ee,children:function(Z,Q){var ne,ae=Z.group,J=Z.groupOption,re=Z.data,fe=Z.label,ve=Z.value,pe=re.key;if(ae){var oe,se=(oe=re.title)!==null&&oe!==void 0?oe:Ib(fe)?fe.toString():void 0;return C("div",{className:te(I,"".concat(I,"-group")),title:se,children:fe!==void 0?fe:pe})}var le=re.disabled,Ce=re.title;re.children;var ce=re.style,de=re.className,xe=Je(re,c8),he=lr(xe,W),ke=j(ve),we=le||!ke&&T,ge="".concat(I,"-option"),Pe=te(I,ge,de,(ne={},V(ne,"".concat(ge,"-grouped"),J),V(ne,"".concat(ge,"-active"),A===Q&&!we),V(ne,"".concat(ge,"-disabled"),we),V(ne,"".concat(ge,"-selected"),ke),ne)),Se=Y(Z),st=!S||typeof S=="function"||ke,nt=typeof Se=="number"?Se:Se||ve,Ne=Ib(nt)?nt.toString():void 0;return Ce!==void 0&&(Ne=Ce),ie("div",{...Ka(he),...E?{}:K(Z,Q),"aria-selected":ke,className:Pe,title:Ne,onMouseMove:function(){A===Q||we||k(Q)},onClick:function(){we||H(ve)},style:ce,children:[C("div",{className:"".concat(ge,"-content"),children:typeof N=="function"?N(Z,{index:Q}):nt}),f.exports.isValidElement(S)||ke,st&&C(af,{className:"".concat(I,"-option-state"),customizeIcon:S,customizeIconProps:{value:ve,disabled:we,isSelected:ke},children:ke?"\u2713":null})]})}})]})},d8=f.exports.forwardRef(u8);const f8=function(e,t){var n=f.exports.useRef({values:new Map,options:new Map}),r=f.exports.useMemo(function(){var i=n.current,a=i.values,l=i.options,s=e.map(function(d){if(d.label===void 0){var v;return U(U({},d),{},{label:(v=a.get(d.value))===null||v===void 0?void 0:v.label})}return d}),c=new Map,u=new Map;return s.forEach(function(d){c.set(d.value,d),u.set(d.value,t.get(d.value)||l.get(d.value))}),n.current.values=c,n.current.options=u,s},[e,t]),o=f.exports.useCallback(function(i){return t.get(i)||n.current.options.get(i)},[t]);return[r,o]};function gv(e,t){return Uw(e).join("").toUpperCase().includes(t)}const v8=function(e,t,n,r,o){return f.exports.useMemo(function(){if(!n||r===!1)return e;var i=t.options,a=t.label,l=t.value,s=[],c=typeof r=="function",u=n.toUpperCase(),d=c?r:function(h,g){return o?gv(g[o],u):g[i]?gv(g[a!=="children"?a:"label"],u):gv(g[l],u)},v=c?function(h){return bg(h)}:function(h){return h};return e.forEach(function(h){if(h[i]){var g=d(n,v(h));if(g)s.push(h);else{var p=h[i].filter(function(b){return d(n,v(b))});p.length&&s.push(U(U({},h),{},V({},i,p)))}return}d(n,v(h))&&s.push(h)}),s},[e,r,o,n,t])};var Pb=0,p8=Rn();function g8(){var e;return p8?(e=Pb,Pb+=1):e="TEST_OR_SSR",e}function h8(e){var t=f.exports.useState(),n=G(t,2),r=n[0],o=n[1];return f.exports.useEffect(function(){o("rc_select_".concat(g8()))},[]),e||r}var m8=["children","value"],y8=["children"];function b8(e){var t=e,n=t.key,r=t.props,o=r.children,i=r.value,a=Je(r,m8);return U({key:n,value:i!==void 0?i:n,children:o},a)}function Qw(e){var t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1;return Qo(e).map(function(n,r){if(!f.exports.isValidElement(n)||!n.type)return null;var o=n,i=o.type.isSelectOptGroup,a=o.key,l=o.props,s=l.children,c=Je(l,y8);return t||!i?b8(n):U(U({key:"__RC_SELECT_GRP__".concat(a===null?r:a,"__"),label:a},c),{},{options:Qw(s)})}).filter(function(n){return n})}var S8=function(t,n,r,o,i){return f.exports.useMemo(function(){var a=t,l=!t;l&&(a=Qw(n));var s=new Map,c=new Map,u=function(h,g,p){p&&typeof p=="string"&&h.set(g[p],g)},d=function v(h){for(var g=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1,p=0;p2&&arguments[2]!==void 0?arguments[2]:{},Ge=ye.source,Ze=Ge===void 0?"keyboard":Ge;ut(Te),a&&r==="combobox"&&$e!==null&&Ze==="keyboard"&&Be(String($e))},[a,r]),Xe=function(Te,ye,Ge){var Ze=function(){var Ke,at=de(Te);return[M?{label:at==null?void 0:at[Y.label],value:Te,key:(Ke=at==null?void 0:at.key)!==null&&Ke!==void 0?Ke:Te}:Te,bg(at)]};if(ye&&h){var et=Ze(),ht=G(et,2),mt=ht[0],ct=ht[1];h(mt,ct)}else if(!ye&&g&&Ge!=="clear"){var We=Ze(),Ve=G(We,2),vt=Ve[0],Ie=Ve[1];g(vt,Ie)}},Le=Tb(function($e,Te){var ye,Ge=j?Te.selected:!0;Ge?ye=j?[].concat(Oe(ce),[$e]):[$e]:ye=ce.filter(function(Ze){return Ze.value!==$e}),nt(ye),Xe($e,Ge),r==="combobox"?Be(""):(!Sg||v)&&(Z(""),Be(""))}),Re=function(Te,ye){nt(Te);var Ge=ye.type,Ze=ye.values;(Ge==="remove"||Ge==="clear")&&Ze.forEach(function(et){Xe(et.value,!1,Ge)})},be=function(Te,ye){if(Z(Te),Be(null),ye.source==="submit"){var Ge=(Te||"").trim();if(Ge){var Ze=Array.from(new Set([].concat(Oe(he),[Ge])));nt(Ze),Xe(Ge,!0),Z("")}return}ye.source!=="blur"&&(r==="combobox"&&nt(Te),u==null||u(Te))},Ae=function(Te){var ye=Te;r!=="tags"&&(ye=Te.map(function(Ze){var et=ae.get(Ze);return et==null?void 0:et.value}).filter(function(Ze){return Ze!==void 0}));var Ge=Array.from(new Set([].concat(Oe(he),Oe(ye))));nt(Ge),Ge.forEach(function(Ze){Xe(Ze,!0)})},Me=f.exports.useMemo(function(){var $e=N!==!1&&b!==!1;return U(U({},Q),{},{flattenOptions:st,onActiveValue:He,defaultActiveFirstOption:Ue,onSelect:Le,menuItemSelectedIcon:P,rawValues:he,fieldNames:Y,virtual:$e,direction:I,listHeight:F,listItemHeight:D,childrenAsData:H,maxCount:A,optionRender:E})},[A,Q,st,He,Ue,Le,P,he,Y,N,b,I,F,D,H,E]);return C(lm.Provider,{value:Me,children:C(VA,{...B,id:k,prefixCls:i,ref:t,omitDomProps:x8,mode:r,displayValues:xe,onDisplayValuesChange:Re,direction:I,searchValue:ee,onSearch:be,autoClearSearchValue:v,onSearchSplit:Ae,dropdownMatchSelectWidth:b,OptionList:d8,emptyOptions:!st.length,activeValue:_e,activeDescendantId:"".concat(k,"_list_").concat(ft)})})}),um=$8;um.Option=cm;um.OptGroup=sm;function ed(e,t,n){return te({[`${e}-status-success`]:t==="success",[`${e}-status-warning`]:t==="warning",[`${e}-status-error`]:t==="error",[`${e}-status-validating`]:t==="validating",[`${e}-has-feedback`]:n})}const dm=(e,t)=>t||e,E8=()=>{const[,e]=Kn(),n=new Mt(e.colorBgBase).toHsl().l<.5?{opacity:.65}:{};return C("svg",{style:n,width:"184",height:"152",viewBox:"0 0 184 152",xmlns:"http://www.w3.org/2000/svg",children:ie("g",{fill:"none",fillRule:"evenodd",children:[ie("g",{transform:"translate(24 31.67)",children:[C("ellipse",{fillOpacity:".8",fill:"#F5F5F7",cx:"67.797",cy:"106.89",rx:"67.797",ry:"12.668"}),C("path",{d:"M122.034 69.674L98.109 40.229c-1.148-1.386-2.826-2.225-4.593-2.225h-51.44c-1.766 0-3.444.839-4.592 2.225L13.56 69.674v15.383h108.475V69.674z",fill:"#AEB8C2"}),C("path",{d:"M101.537 86.214L80.63 61.102c-1.001-1.207-2.507-1.867-4.048-1.867H31.724c-1.54 0-3.047.66-4.048 1.867L6.769 86.214v13.792h94.768V86.214z",fill:"url(#linearGradient-1)",transform:"translate(13.56)"}),C("path",{d:"M33.83 0h67.933a4 4 0 0 1 4 4v93.344a4 4 0 0 1-4 4H33.83a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4z",fill:"#F5F5F7"}),C("path",{d:"M42.678 9.953h50.237a2 2 0 0 1 2 2V36.91a2 2 0 0 1-2 2H42.678a2 2 0 0 1-2-2V11.953a2 2 0 0 1 2-2zM42.94 49.767h49.713a2.262 2.262 0 1 1 0 4.524H42.94a2.262 2.262 0 0 1 0-4.524zM42.94 61.53h49.713a2.262 2.262 0 1 1 0 4.525H42.94a2.262 2.262 0 0 1 0-4.525zM121.813 105.032c-.775 3.071-3.497 5.36-6.735 5.36H20.515c-3.238 0-5.96-2.29-6.734-5.36a7.309 7.309 0 0 1-.222-1.79V69.675h26.318c2.907 0 5.25 2.448 5.25 5.42v.04c0 2.971 2.37 5.37 5.277 5.37h34.785c2.907 0 5.277-2.421 5.277-5.393V75.1c0-2.972 2.343-5.426 5.25-5.426h26.318v33.569c0 .617-.077 1.216-.221 1.789z",fill:"#DCE0E6"})]}),C("path",{d:"M149.121 33.292l-6.83 2.65a1 1 0 0 1-1.317-1.23l1.937-6.207c-2.589-2.944-4.109-6.534-4.109-10.408C138.802 8.102 148.92 0 161.402 0 173.881 0 184 8.102 184 18.097c0 9.995-10.118 18.097-22.599 18.097-4.528 0-8.744-1.066-12.28-2.902z",fill:"#DCE0E6"}),ie("g",{transform:"translate(149.65 15.383)",fill:"#FFF",children:[C("ellipse",{cx:"20.654",cy:"3.167",rx:"2.849",ry:"2.815"}),C("path",{d:"M5.698 5.63H0L2.898.704zM9.259.704h4.985V5.63H9.259z"})]})]})})},M8=E8,O8=()=>{const[,e]=Kn(),{colorFill:t,colorFillTertiary:n,colorFillQuaternary:r,colorBgContainer:o}=e,{borderColor:i,shadowColor:a,contentColor:l}=f.exports.useMemo(()=>({borderColor:new Mt(t).onBackground(o).toHexShortString(),shadowColor:new Mt(n).onBackground(o).toHexShortString(),contentColor:new Mt(r).onBackground(o).toHexShortString()}),[t,n,r,o]);return C("svg",{width:"64",height:"41",viewBox:"0 0 64 41",xmlns:"http://www.w3.org/2000/svg",children:ie("g",{transform:"translate(0 1)",fill:"none",fillRule:"evenodd",children:[C("ellipse",{fill:a,cx:"32",cy:"33",rx:"32",ry:"7"}),ie("g",{fillRule:"nonzero",stroke:i,children:[C("path",{d:"M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z"}),C("path",{d:"M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z",fill:l})]})]})})},R8=O8,I8=e=>{const{componentCls:t,margin:n,marginXS:r,marginXL:o,fontSize:i,lineHeight:a}=e;return{[t]:{marginInline:r,fontSize:i,lineHeight:a,textAlign:"center",[`${t}-image`]:{height:e.emptyImgHeight,marginBottom:r,opacity:e.opacityImage,img:{height:"100%"},svg:{maxWidth:"100%",height:"100%",margin:"auto"}},[`${t}-description`]:{color:e.colorText},[`${t}-footer`]:{marginTop:n},"&-normal":{marginBlock:o,color:e.colorTextDisabled,[`${t}-description`]:{color:e.colorTextDisabled},[`${t}-image`]:{height:e.emptyImgHeightMD}},"&-small":{marginBlock:r,color:e.colorTextDisabled,[`${t}-image`]:{height:e.emptyImgHeightSM}}}}},P8=vn("Empty",e=>{const{componentCls:t,controlHeightLG:n,calc:r}=e,o=$t(e,{emptyImgCls:`${t}-img`,emptyImgHeight:r(n).mul(2.5).equal(),emptyImgHeightMD:n,emptyImgHeightSM:r(n).mul(.875).equal()});return[I8(o)]});var T8=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{var{className:t,rootClassName:n,prefixCls:r,image:o=Zw,description:i,children:a,imageStyle:l,style:s}=e,c=T8(e,["className","rootClassName","prefixCls","image","description","children","imageStyle","style"]);const{getPrefixCls:u,direction:d,empty:v}=f.exports.useContext(ot),h=u("empty",r),[g,p,b]=P8(h),[m]=Wx("Empty"),y=typeof i<"u"?i:m==null?void 0:m.description,S=typeof y=="string"?y:"empty";let x=null;return typeof o=="string"?x=C("img",{alt:S,src:o}):x=o,g(ie("div",{...Object.assign({className:te(p,b,h,v==null?void 0:v.className,{[`${h}-normal`]:o===Jw,[`${h}-rtl`]:d==="rtl"},t,n),style:Object.assign(Object.assign({},v==null?void 0:v.style),s)},c),children:[C("div",{className:`${h}-image`,style:l,children:x}),y&&C("div",{className:`${h}-description`,children:y}),a&&C("div",{className:`${h}-footer`,children:a})]}))};fm.PRESENTED_IMAGE_DEFAULT=Zw;fm.PRESENTED_IMAGE_SIMPLE=Jw;const wl=fm,N8=e=>{const{componentName:t}=e,{getPrefixCls:n}=f.exports.useContext(ot),r=n("empty");switch(t){case"Table":case"List":return C(wl,{image:wl.PRESENTED_IMAGE_SIMPLE});case"Select":case"TreeSelect":case"Cascader":case"Transfer":case"Mentions":return C(wl,{image:wl.PRESENTED_IMAGE_SIMPLE,className:`${r}-small`});default:return C(wl,{})}},_8=N8,A8=["outlined","borderless","filled"],D8=function(e){let t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:void 0;const n=f.exports.useContext(v_);let r;typeof e<"u"?r=e:t===!1?r="borderless":r=n!=null?n:"outlined";const o=A8.includes(r);return[r,o]},vm=D8,L8=e=>{const n={overflow:{adjustX:!0,adjustY:!0,shiftY:!0},htmlRegion:e==="scroll"?"scroll":"visible",dynamicInset:!0};return{bottomLeft:Object.assign(Object.assign({},n),{points:["tl","bl"],offset:[0,4]}),bottomRight:Object.assign(Object.assign({},n),{points:["tr","br"],offset:[0,4]}),topLeft:Object.assign(Object.assign({},n),{points:["bl","tl"],offset:[0,-4]}),topRight:Object.assign(Object.assign({},n),{points:["br","tr"],offset:[0,-4]})}};function z8(e,t){return e||L8(t)}const Nb=e=>{const{optionHeight:t,optionFontSize:n,optionLineHeight:r,optionPadding:o}=e;return{position:"relative",display:"block",minHeight:t,padding:o,color:e.colorText,fontWeight:"normal",fontSize:n,lineHeight:r,boxSizing:"border-box"}},F8=e=>{const{antCls:t,componentCls:n}=e,r=`${n}-item`,o=`&${t}-slide-up-enter${t}-slide-up-enter-active`,i=`&${t}-slide-up-appear${t}-slide-up-appear-active`,a=`&${t}-slide-up-leave${t}-slide-up-leave-active`,l=`${n}-dropdown-placement-`;return[{[`${n}-dropdown`]:Object.assign(Object.assign({},Qt(e)),{position:"absolute",top:-9999,zIndex:e.zIndexPopup,boxSizing:"border-box",padding:e.paddingXXS,overflow:"hidden",fontSize:e.fontSize,fontVariant:"initial",backgroundColor:e.colorBgElevated,borderRadius:e.borderRadiusLG,outline:"none",boxShadow:e.boxShadowSecondary,[` + ${o}${l}bottomLeft, + ${i}${l}bottomLeft + `]:{animationName:nm},[` + ${o}${l}topLeft, + ${i}${l}topLeft, + ${o}${l}topRight, + ${i}${l}topRight + `]:{animationName:om},[`${a}${l}bottomLeft`]:{animationName:rm},[` + ${a}${l}topLeft, + ${a}${l}topRight + `]:{animationName:im},"&-hidden":{display:"none"},[`${r}`]:Object.assign(Object.assign({},Nb(e)),{cursor:"pointer",transition:`background ${e.motionDurationSlow} ease`,borderRadius:e.borderRadiusSM,"&-group":{color:e.colorTextDescription,fontSize:e.fontSizeSM,cursor:"default"},"&-option":{display:"flex","&-content":Object.assign({flex:"auto"},ei),"&-state":{flex:"none",display:"flex",alignItems:"center"},[`&-active:not(${r}-option-disabled)`]:{backgroundColor:e.optionActiveBg},[`&-selected:not(${r}-option-disabled)`]:{color:e.optionSelectedColor,fontWeight:e.optionSelectedFontWeight,backgroundColor:e.optionSelectedBg,[`${r}-option-state`]:{color:e.colorPrimary},[`&:has(+ ${r}-option-selected:not(${r}-option-disabled))`]:{borderEndStartRadius:0,borderEndEndRadius:0,[`& + ${r}-option-selected:not(${r}-option-disabled)`]:{borderStartStartRadius:0,borderStartEndRadius:0}}},"&-disabled":{[`&${r}-option-selected`]:{backgroundColor:e.colorBgContainerDisabled},color:e.colorTextDisabled,cursor:"not-allowed"},"&-grouped":{paddingInlineStart:e.calc(e.controlPaddingHorizontal).mul(2).equal()}},"&-empty":Object.assign(Object.assign({},Nb(e)),{color:e.colorTextDisabled})}),"&-rtl":{direction:"rtl"}})},Xa(e,"slide-up"),Xa(e,"slide-down"),Zu(e,"move-up"),Zu(e,"move-down")]},k8=F8,Qi=2,B8=e=>{const{multipleSelectItemHeight:t,selectHeight:n,lineWidth:r}=e;return e.calc(n).sub(t).div(2).sub(r).equal()},pm=(e,t)=>{const{componentCls:n,iconCls:r}=e,o=`${n}-selection-overflow`,i=e.multipleSelectItemHeight,a=B8(e),l=t?`${n}-${t}`:"";return{[`${n}-multiple${l}`]:{[o]:{position:"relative",display:"flex",flex:"auto",flexWrap:"wrap",maxWidth:"100%","&-item":{flex:"none",alignSelf:"center",maxWidth:"100%",display:"inline-flex"}},[`${n}-selector`]:{display:"flex",flexWrap:"wrap",alignItems:"center",height:"100%",paddingInline:e.calc(Qi).mul(2).equal(),paddingBlock:e.calc(a).sub(Qi).equal(),borderRadius:e.borderRadius,[`${n}-disabled&`]:{background:e.multipleSelectorBgDisabled,cursor:"not-allowed"},"&:after":{display:"inline-block",width:0,margin:`${X(Qi)} 0`,lineHeight:X(i),visibility:"hidden",content:'"\\a0"'}},[`${n}-selection-item`]:{display:"flex",alignSelf:"center",flex:"none",boxSizing:"border-box",maxWidth:"100%",height:i,marginTop:Qi,marginBottom:Qi,lineHeight:X(e.calc(i).sub(e.calc(e.lineWidth).mul(2)).equal()),borderRadius:e.borderRadiusSM,cursor:"default",transition:`font-size ${e.motionDurationSlow}, line-height ${e.motionDurationSlow}, height ${e.motionDurationSlow}`,marginInlineEnd:e.calc(Qi).mul(2).equal(),paddingInlineStart:e.paddingXS,paddingInlineEnd:e.calc(e.paddingXS).div(2).equal(),[`${n}-disabled&`]:{color:e.multipleItemColorDisabled,borderColor:e.multipleItemBorderColorDisabled,cursor:"not-allowed"},"&-content":{display:"inline-block",marginInlineEnd:e.calc(e.paddingXS).div(2).equal(),overflow:"hidden",whiteSpace:"pre",textOverflow:"ellipsis"},"&-remove":Object.assign(Object.assign({},Uh()),{display:"inline-flex",alignItems:"center",color:e.colorIcon,fontWeight:"bold",fontSize:10,lineHeight:"inherit",cursor:"pointer",[`> ${r}`]:{verticalAlign:"-0.2em"},"&:hover":{color:e.colorIconHover}})},[`${o}-item + ${o}-item`]:{[`${n}-selection-search`]:{marginInlineStart:0}},[`${o}-item-suffix`]:{height:"100%"},[`${n}-selection-search`]:{display:"inline-flex",position:"relative",maxWidth:"100%",marginInlineStart:e.calc(e.inputPaddingHorizontalBase).sub(a).equal(),[` + &-input, + &-mirror + `]:{height:i,fontFamily:e.fontFamily,lineHeight:X(i),transition:`all ${e.motionDurationSlow}`},"&-input":{width:"100%",minWidth:4.1},"&-mirror":{position:"absolute",top:0,insetInlineStart:0,insetInlineEnd:"auto",zIndex:999,whiteSpace:"pre",visibility:"hidden"}},[`${n}-selection-placeholder`]:{position:"absolute",top:"50%",insetInlineStart:e.inputPaddingHorizontalBase,insetInlineEnd:e.inputPaddingHorizontalBase,transform:"translateY(-50%)",transition:`all ${e.motionDurationSlow}`}}}};function hv(e,t){const{componentCls:n}=e,r=t?`${n}-${t}`:"",o={[`${n}-multiple${r}`]:{fontSize:e.fontSize,[`${n}-selector`]:{[`${n}-show-search&`]:{cursor:"text"}},[` + &${n}-show-arrow ${n}-selector, + &${n}-allow-clear ${n}-selector + `]:{paddingInlineEnd:e.calc(e.fontSizeIcon).add(e.controlPaddingHorizontal).equal()}}};return[pm(e,t),o]}const j8=e=>{const{componentCls:t}=e,n=$t(e,{selectHeight:e.controlHeightSM,multipleSelectItemHeight:e.controlHeightXS,borderRadius:e.borderRadiusSM,borderRadiusSM:e.borderRadiusXS}),r=$t(e,{fontSize:e.fontSizeLG,selectHeight:e.controlHeightLG,multipleSelectItemHeight:e.multipleItemHeightLG,borderRadius:e.borderRadiusLG,borderRadiusSM:e.borderRadius});return[hv(e),hv(n,"sm"),{[`${t}-multiple${t}-sm`]:{[`${t}-selection-placeholder`]:{insetInline:e.calc(e.controlPaddingHorizontalSM).sub(e.lineWidth).equal()},[`${t}-selection-search`]:{marginInlineStart:2}}},hv(r,"lg")]};function mv(e,t){const{componentCls:n,inputPaddingHorizontalBase:r,borderRadius:o}=e,i=e.calc(e.controlHeight).sub(e.calc(e.lineWidth).mul(2)).equal(),a=t?`${n}-${t}`:"";return{[`${n}-single${a}`]:{fontSize:e.fontSize,height:e.controlHeight,[`${n}-selector`]:Object.assign(Object.assign({},Qt(e,!0)),{display:"flex",borderRadius:o,[`${n}-selection-search`]:{position:"absolute",top:0,insetInlineStart:r,insetInlineEnd:r,bottom:0,"&-input":{width:"100%",WebkitAppearance:"textfield"}},[` + ${n}-selection-item, + ${n}-selection-placeholder + `]:{padding:0,lineHeight:X(i),transition:`all ${e.motionDurationSlow}, visibility 0s`,alignSelf:"center"},[`${n}-selection-placeholder`]:{transition:"none",pointerEvents:"none"},[["&:after",`${n}-selection-item:empty:after`,`${n}-selection-placeholder:empty:after`].join(",")]:{display:"inline-block",width:0,visibility:"hidden",content:'"\\a0"'}}),[` + &${n}-show-arrow ${n}-selection-item, + &${n}-show-arrow ${n}-selection-placeholder + `]:{paddingInlineEnd:e.showArrowPaddingInlineEnd},[`&${n}-open ${n}-selection-item`]:{color:e.colorTextPlaceholder},[`&:not(${n}-customize-input)`]:{[`${n}-selector`]:{width:"100%",height:"100%",padding:`0 ${X(r)}`,[`${n}-selection-search-input`]:{height:i},"&:after":{lineHeight:X(i)}}},[`&${n}-customize-input`]:{[`${n}-selector`]:{"&:after":{display:"none"},[`${n}-selection-search`]:{position:"static",width:"100%"},[`${n}-selection-placeholder`]:{position:"absolute",insetInlineStart:0,insetInlineEnd:0,padding:`0 ${X(r)}`,"&:after":{display:"none"}}}}}}}function H8(e){const{componentCls:t}=e,n=e.calc(e.controlPaddingHorizontalSM).sub(e.lineWidth).equal();return[mv(e),mv($t(e,{controlHeight:e.controlHeightSM,borderRadius:e.borderRadiusSM}),"sm"),{[`${t}-single${t}-sm`]:{[`&:not(${t}-customize-input)`]:{[`${t}-selection-search`]:{insetInlineStart:n,insetInlineEnd:n},[`${t}-selector`]:{padding:`0 ${X(n)}`},[`&${t}-show-arrow ${t}-selection-search`]:{insetInlineEnd:e.calc(n).add(e.calc(e.fontSize).mul(1.5)).equal()},[` + &${t}-show-arrow ${t}-selection-item, + &${t}-show-arrow ${t}-selection-placeholder + `]:{paddingInlineEnd:e.calc(e.fontSize).mul(1.5).equal()}}}},mv($t(e,{controlHeight:e.singleItemHeightLG,fontSize:e.fontSizeLG,borderRadius:e.borderRadiusLG}),"lg")]}const W8=e=>{const{fontSize:t,lineHeight:n,controlHeight:r,controlPaddingHorizontal:o,zIndexPopupBase:i,colorText:a,fontWeightStrong:l,controlItemBgActive:s,controlItemBgHover:c,colorBgContainer:u,colorFillSecondary:d,controlHeightLG:v,controlHeightSM:h,colorBgContainerDisabled:g,colorTextDisabled:p}=e;return{zIndexPopup:i+50,optionSelectedColor:a,optionSelectedFontWeight:l,optionSelectedBg:s,optionActiveBg:c,optionPadding:`${(r-t*n)/2}px ${o}px`,optionFontSize:t,optionLineHeight:n,optionHeight:r,selectorBg:u,clearBg:u,singleItemHeightLG:v,multipleItemBg:d,multipleItemBorderColor:"transparent",multipleItemHeight:h,multipleItemHeightLG:r,multipleSelectorBgDisabled:g,multipleItemColorDisabled:p,multipleItemBorderColorDisabled:"transparent",showArrowPaddingInlineEnd:Math.ceil(e.fontSize*1.25)}},e2=(e,t)=>{const{componentCls:n,antCls:r,controlOutlineWidth:o}=e;return{[`&:not(${n}-customize-input) ${n}-selector`]:{border:`${X(e.lineWidth)} ${e.lineType} ${t.borderColor}`,background:e.selectorBg},[`&:not(${n}-disabled):not(${n}-customize-input):not(${r}-pagination-size-changer)`]:{[`&:hover ${n}-selector`]:{borderColor:t.hoverBorderHover},[`${n}-focused& ${n}-selector`]:{borderColor:t.activeBorderColor,boxShadow:`0 0 0 ${X(o)} ${t.activeShadowColor}`,outline:0}}}},_b=(e,t)=>({[`&${e.componentCls}-status-${t.status}`]:Object.assign({},e2(e,t))}),V8=e=>({"&-outlined":Object.assign(Object.assign(Object.assign(Object.assign({},e2(e,{borderColor:e.colorBorder,hoverBorderHover:e.colorPrimaryHover,activeBorderColor:e.colorPrimary,activeShadowColor:e.controlOutline})),_b(e,{status:"error",borderColor:e.colorError,hoverBorderHover:e.colorErrorHover,activeBorderColor:e.colorError,activeShadowColor:e.colorErrorOutline})),_b(e,{status:"warning",borderColor:e.colorWarning,hoverBorderHover:e.colorWarningHover,activeBorderColor:e.colorWarning,activeShadowColor:e.colorWarningOutline})),{[`&${e.componentCls}-disabled`]:{[`&:not(${e.componentCls}-customize-input) ${e.componentCls}-selector`]:{background:e.colorBgContainerDisabled,color:e.colorTextDisabled}},[`&${e.componentCls}-multiple ${e.componentCls}-selection-item`]:{background:e.multipleItemBg,border:`${X(e.lineWidth)} ${e.lineType} ${e.multipleItemBorderColor}`}})}),t2=(e,t)=>{const{componentCls:n,antCls:r}=e;return{[`&:not(${n}-customize-input) ${n}-selector`]:{background:t.bg,border:`${X(e.lineWidth)} ${e.lineType} transparent`,color:t.color},[`&:not(${n}-disabled):not(${n}-customize-input):not(${r}-pagination-size-changer)`]:{[`&:hover ${n}-selector`]:{background:t.hoverBg},[`${n}-focused& ${n}-selector`]:{background:e.selectorBg,borderColor:t.activeBorderColor,outline:0}}}},Ab=(e,t)=>({[`&${e.componentCls}-status-${t.status}`]:Object.assign({},t2(e,t))}),U8=e=>({"&-filled":Object.assign(Object.assign(Object.assign(Object.assign({},t2(e,{bg:e.colorFillTertiary,hoverBg:e.colorFillSecondary,activeBorderColor:e.colorPrimary,color:e.colorText})),Ab(e,{status:"error",bg:e.colorErrorBg,hoverBg:e.colorErrorBgHover,activeBorderColor:e.colorError,color:e.colorError})),Ab(e,{status:"warning",bg:e.colorWarningBg,hoverBg:e.colorWarningBgHover,activeBorderColor:e.colorWarning,color:e.colorWarning})),{[`&${e.componentCls}-disabled`]:{[`&:not(${e.componentCls}-customize-input) ${e.componentCls}-selector`]:{borderColor:e.colorBorder,background:e.colorBgContainerDisabled,color:e.colorTextDisabled}},[`&${e.componentCls}-multiple ${e.componentCls}-selection-item`]:{background:e.colorBgContainer,border:`${X(e.lineWidth)} ${e.lineType} ${e.colorSplit}`}})}),Y8=e=>({"&-borderless":{[`${e.componentCls}-selector`]:{background:"transparent",borderColor:"transparent"},[`&${e.componentCls}-disabled`]:{[`&:not(${e.componentCls}-customize-input) ${e.componentCls}-selector`]:{color:e.colorTextDisabled}},[`&${e.componentCls}-multiple ${e.componentCls}-selection-item`]:{background:e.multipleItemBg,border:`${X(e.lineWidth)} ${e.lineType} ${e.multipleItemBorderColor}`}}}),G8=e=>({[e.componentCls]:Object.assign(Object.assign(Object.assign({},V8(e)),U8(e)),Y8(e))}),K8=G8,q8=e=>{const{componentCls:t}=e;return{position:"relative",transition:`all ${e.motionDurationMid} ${e.motionEaseInOut}`,input:{cursor:"pointer"},[`${t}-show-search&`]:{cursor:"text",input:{cursor:"auto",color:"inherit",height:"100%"}},[`${t}-disabled&`]:{cursor:"not-allowed",input:{cursor:"not-allowed"}}}},X8=e=>{const{componentCls:t}=e;return{[`${t}-selection-search-input`]:{margin:0,padding:0,background:"transparent",border:"none",outline:"none",appearance:"none",fontFamily:"inherit","&::-webkit-search-cancel-button":{display:"none","-webkit-appearance":"none"}}}},Q8=e=>{const{antCls:t,componentCls:n,inputPaddingHorizontalBase:r,iconCls:o}=e;return{[n]:Object.assign(Object.assign({},Qt(e)),{position:"relative",display:"inline-block",cursor:"pointer",[`&:not(${n}-customize-input) ${n}-selector`]:Object.assign(Object.assign({},q8(e)),X8(e)),[`${n}-selection-item`]:Object.assign(Object.assign({flex:1,fontWeight:"normal",position:"relative",userSelect:"none"},ei),{[`> ${t}-typography`]:{display:"inline"}}),[`${n}-selection-placeholder`]:Object.assign(Object.assign({},ei),{flex:1,color:e.colorTextPlaceholder,pointerEvents:"none"}),[`${n}-arrow`]:Object.assign(Object.assign({},Uh()),{position:"absolute",top:"50%",insetInlineStart:"auto",insetInlineEnd:r,height:e.fontSizeIcon,marginTop:e.calc(e.fontSizeIcon).mul(-1).div(2).equal(),color:e.colorTextQuaternary,fontSize:e.fontSizeIcon,lineHeight:1,textAlign:"center",pointerEvents:"none",display:"flex",alignItems:"center",transition:`opacity ${e.motionDurationSlow} ease`,[o]:{verticalAlign:"top",transition:`transform ${e.motionDurationSlow}`,"> svg":{verticalAlign:"top"},[`&:not(${n}-suffix)`]:{pointerEvents:"auto"}},[`${n}-disabled &`]:{cursor:"not-allowed"},"> *:not(:last-child)":{marginInlineEnd:8}}),[`${n}-clear`]:{position:"absolute",top:"50%",insetInlineStart:"auto",insetInlineEnd:r,zIndex:1,display:"inline-block",width:e.fontSizeIcon,height:e.fontSizeIcon,marginTop:e.calc(e.fontSizeIcon).mul(-1).div(2).equal(),color:e.colorTextQuaternary,fontSize:e.fontSizeIcon,fontStyle:"normal",lineHeight:1,textAlign:"center",textTransform:"none",cursor:"pointer",opacity:0,transition:`color ${e.motionDurationMid} ease, opacity ${e.motionDurationSlow} ease`,textRendering:"auto","&:before":{display:"block"},"&:hover":{color:e.colorTextTertiary}},"&:hover":{[`${n}-clear`]:{opacity:1},[`${n}-arrow:not(:last-child)`]:{opacity:0}}}),[`${n}-has-feedback`]:{[`${n}-clear`]:{insetInlineEnd:e.calc(r).add(e.fontSize).add(e.paddingXS).equal()}}}},Z8=e=>{const{componentCls:t}=e;return[{[t]:{[`&${t}-in-form-item`]:{width:"100%"}}},Q8(e),H8(e),j8(e),k8(e),{[`${t}-rtl`]:{direction:"rtl"}},tf(e,{borderElCls:`${t}-selector`,focusElCls:`${t}-focused`})]},J8=vn("Select",(e,t)=>{let{rootPrefixCls:n}=t;const r=$t(e,{rootPrefixCls:n,inputPaddingHorizontalBase:e.calc(e.paddingSM).sub(1).equal(),multipleSelectItemHeight:e.multipleItemHeight,selectHeight:e.controlHeight});return[Z8(r),K8(r)]},W8,{unitless:{optionLineHeight:!0,optionSelectedFontWeight:!0}});function eD(e){let{suffixIcon:t,clearIcon:n,menuItemSelectedIcon:r,removeIcon:o,loading:i,multiple:a,hasFeedback:l,prefixCls:s,showSuffixIcon:c,feedbackIcon:u,showArrow:d,componentName:v}=e;const h=n!=null?n:C(Nd,{}),g=y=>t===null&&!l&&!d?null:ie(Tt,{children:[c!==!1&&y,l&&u]});let p=null;if(t!==void 0)p=g(t);else if(i)p=g(C(ux,{spin:!0}));else{const y=`${s}-suffix`;p=S=>{let{open:x,showSearch:$}=S;return g(x&&$?C(_d,{className:y}):C(qI,{className:y}))}}let b=null;r!==void 0?b=r:a?b=C(lx,{}):b=null;let m=null;return o!==void 0?m=o:m=C(eo,{}),{clearIcon:h,suffixIcon:p,itemIcon:b,removeIcon:m}}function tD(e,t){return t!==void 0?t:e!==null}var nD=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{var n;const{prefixCls:r,bordered:o,className:i,rootClassName:a,getPopupContainer:l,popupClassName:s,dropdownClassName:c,listHeight:u=256,placement:d,listItemHeight:v,size:h,disabled:g,notFoundContent:p,status:b,builtinPlacements:m,dropdownMatchSelectWidth:y,popupMatchSelectWidth:S,direction:x,style:$,allowClear:E,variant:w,dropdownStyle:R,transitionName:P,tagRender:N,maxCount:I}=e,z=nD(e,["prefixCls","bordered","className","rootClassName","getPopupContainer","popupClassName","dropdownClassName","listHeight","placement","listItemHeight","size","disabled","notFoundContent","status","builtinPlacements","dropdownMatchSelectWidth","popupMatchSelectWidth","direction","style","allowClear","variant","dropdownStyle","transitionName","tagRender","maxCount"]),{getPopupContainer:F,getPrefixCls:T,renderEmpty:D,direction:_,virtual:O,popupMatchSelectWidth:M,popupOverflow:L,select:A}=f.exports.useContext(ot),[,B]=Kn(),k=v!=null?v:B==null?void 0:B.controlHeight,j=T("select",r),H=T(),W=x!=null?x:_,{compactSize:Y,compactItemClassnames:K}=ef(j,W),[q,ee]=vm(w,o),Z=no(j),[Q,ne,ae]=J8(j,Z),J=f.exports.useMemo(()=>{const{mode:Be}=e;if(Be!=="combobox")return Be===n2?"combobox":Be},[e.mode]),re=J==="multiple"||J==="tags",fe=tD(e.suffixIcon,e.showArrow),ve=(n=S!=null?S:y)!==null&&n!==void 0?n:M,{status:pe,hasFeedback:oe,isFormItemInput:se,feedbackIcon:le}=f.exports.useContext(Jr),Ce=dm(pe,b);let ce;p!==void 0?ce=p:J==="combobox"?ce=null:ce=(D==null?void 0:D("Select"))||C(_8,{componentName:"Select"});const{suffixIcon:de,itemIcon:xe,removeIcon:he,clearIcon:ke}=eD(Object.assign(Object.assign({},z),{multiple:re,hasFeedback:oe,feedbackIcon:le,showSuffixIcon:fe,prefixCls:j,componentName:"Select"})),we=E===!0?{clearIcon:ke}:E,ge=lr(z,["suffixIcon","itemIcon"]),Pe=te(s||c,{[`${j}-dropdown-${W}`]:W==="rtl"},a,ae,Z,ne),Se=So(Be=>{var qe;return(qe=h!=null?h:Y)!==null&&qe!==void 0?qe:Be}),st=f.exports.useContext(rl),nt=g!=null?g:st,Ne=te({[`${j}-lg`]:Se==="large",[`${j}-sm`]:Se==="small",[`${j}-rtl`]:W==="rtl",[`${j}-${q}`]:ee,[`${j}-in-form-item`]:se},ed(j,Ce,oe),K,A==null?void 0:A.className,i,a,ae,Z,ne),Ee=f.exports.useMemo(()=>d!==void 0?d:W==="rtl"?"bottomRight":"bottomLeft",[d,W]),[_e]=Qd("SelectLike",R==null?void 0:R.zIndex);return Q(C(um,{...Object.assign({ref:t,virtual:O,showSearch:A==null?void 0:A.showSearch},ge,{style:Object.assign(Object.assign({},A==null?void 0:A.style),$),dropdownMatchSelectWidth:ve,transitionName:ni(H,"slide-up",P),builtinPlacements:z8(m,L),listHeight:u,listItemHeight:k,mode:J,prefixCls:j,placement:Ee,direction:W,suffixIcon:de,menuItemSelectedIcon:xe,removeIcon:he,allowClear:we,notFoundContent:ce,className:Ne,getPopupContainer:l||F,dropdownClassName:Pe,disabled:nt,dropdownStyle:Object.assign(Object.assign({},R),{zIndex:_e}),maxCount:re?I:void 0,tagRender:re?N:void 0})}))},ol=f.exports.forwardRef(rD),oD=q_(ol);ol.SECRET_COMBOBOX_MODE_DO_NOT_USE=n2;ol.Option=cm;ol.OptGroup=sm;ol._InternalPanelDoNotUseOrYouWillBeFired=oD;const r2=ol,o2=["xxl","xl","lg","md","sm","xs"],iD=e=>({xs:`(max-width: ${e.screenXSMax}px)`,sm:`(min-width: ${e.screenSM}px)`,md:`(min-width: ${e.screenMD}px)`,lg:`(min-width: ${e.screenLG}px)`,xl:`(min-width: ${e.screenXL}px)`,xxl:`(min-width: ${e.screenXXL}px)`}),aD=e=>{const t=e,n=[].concat(o2).reverse();return n.forEach((r,o)=>{const i=r.toUpperCase(),a=`screen${i}Min`,l=`screen${i}`;if(!(t[a]<=t[l]))throw new Error(`${a}<=${l} fails : !(${t[a]}<=${t[l]})`);if(o{const n=new Map;let r=-1,o={};return{matchHandlers:{},dispatch(i){return o=i,n.forEach(a=>a(o)),n.size>=1},subscribe(i){return n.size||this.register(),r+=1,n.set(r,i),i(o),r},unsubscribe(i){n.delete(i),n.size||this.unregister()},unregister(){Object.keys(t).forEach(i=>{const a=t[i],l=this.matchHandlers[a];l==null||l.mql.removeListener(l==null?void 0:l.listener)}),n.clear()},register(){Object.keys(t).forEach(i=>{const a=t[i],l=c=>{let{matches:u}=c;this.dispatch(Object.assign(Object.assign({},o),{[i]:u}))},s=window.matchMedia(a);s.addListener(l),this.matchHandlers[a]={mql:s,listener:l},l(s)})},responsiveMap:t}},[e])}function sD(){const[,e]=f.exports.useReducer(t=>t+1,0);return e}function cD(){let e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:!0;const t=f.exports.useRef({}),n=sD(),r=lD();return Nt(()=>{const o=r.subscribe(i=>{t.current=i,e&&n()});return()=>r.unsubscribe(o)},[]),t.current}const uD=f.exports.createContext({}),Cg=uD,dD=e=>{const{antCls:t,componentCls:n,iconCls:r,avatarBg:o,avatarColor:i,containerSize:a,containerSizeLG:l,containerSizeSM:s,textFontSize:c,textFontSizeLG:u,textFontSizeSM:d,borderRadius:v,borderRadiusLG:h,borderRadiusSM:g,lineWidth:p,lineType:b}=e,m=(y,S,x)=>({width:y,height:y,borderRadius:"50%",[`&${n}-square`]:{borderRadius:x},[`&${n}-icon`]:{fontSize:S,[`> ${r}`]:{margin:0}}});return{[n]:Object.assign(Object.assign(Object.assign(Object.assign({},Qt(e)),{position:"relative",display:"inline-flex",justifyContent:"center",alignItems:"center",overflow:"hidden",color:i,whiteSpace:"nowrap",textAlign:"center",verticalAlign:"middle",background:o,border:`${X(p)} ${b} transparent`,["&-image"]:{background:"transparent"},[`${t}-image-img`]:{display:"block"}}),m(a,c,v)),{["&-lg"]:Object.assign({},m(l,u,h)),["&-sm"]:Object.assign({},m(s,d,g)),"> img":{display:"block",width:"100%",height:"100%",objectFit:"cover"}})}},fD=e=>{const{componentCls:t,groupBorderColor:n,groupOverlapping:r,groupSpace:o}=e;return{[`${t}-group`]:{display:"inline-flex",[`${t}`]:{borderColor:n},["> *:not(:first-child)"]:{marginInlineStart:r}},[`${t}-group-popover`]:{[`${t} + ${t}`]:{marginInlineStart:o}}}},vD=e=>{const{controlHeight:t,controlHeightLG:n,controlHeightSM:r,fontSize:o,fontSizeLG:i,fontSizeXL:a,fontSizeHeading3:l,marginXS:s,marginXXS:c,colorBorderBg:u}=e;return{containerSize:t,containerSizeLG:n,containerSizeSM:r,textFontSize:Math.round((i+a)/2),textFontSizeLG:l,textFontSizeSM:o,groupSpace:c,groupOverlapping:-s,groupBorderColor:u}},i2=vn("Avatar",e=>{const{colorTextLightSolid:t,colorTextPlaceholder:n}=e,r=$t(e,{avatarBg:n,avatarColor:t});return[dD(r),fD(r)]},vD);var pD=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{const[n,r]=f.exports.useState(1),[o,i]=f.exports.useState(!1),[a,l]=f.exports.useState(!0),s=f.exports.useRef(null),c=f.exports.useRef(null),u=xr(t,s),{getPrefixCls:d,avatar:v}=f.exports.useContext(ot),h=f.exports.useContext(Cg),g=()=>{if(!c.current||!s.current)return;const q=c.current.offsetWidth,ee=s.current.offsetWidth;if(q!==0&&ee!==0){const{gap:Z=4}=e;Z*2{i(!0)},[]),f.exports.useEffect(()=>{l(!0),r(1)},[e.src]),f.exports.useEffect(g,[e.gap]);const p=()=>{const{onError:q}=e;(q==null?void 0:q())!==!1&&l(!1)},{prefixCls:b,shape:m,size:y,src:S,srcSet:x,icon:$,className:E,rootClassName:w,alt:R,draggable:P,children:N,crossOrigin:I}=e,z=pD(e,["prefixCls","shape","size","src","srcSet","icon","className","rootClassName","alt","draggable","children","crossOrigin"]),F=So(q=>{var ee,Z;return(Z=(ee=y!=null?y:h==null?void 0:h.size)!==null&&ee!==void 0?ee:q)!==null&&Z!==void 0?Z:"default"}),T=Object.keys(typeof F=="object"?F||{}:{}).some(q=>["xs","sm","md","lg","xl","xxl"].includes(q)),D=cD(T),_=f.exports.useMemo(()=>{if(typeof F!="object")return{};const q=o2.find(Z=>D[Z]),ee=F[q];return ee?{width:ee,height:ee,fontSize:ee&&($||N)?ee/2:18}:{}},[D,F]),O=d("avatar",b),M=no(O),[L,A,B]=i2(O,M),k=te({[`${O}-lg`]:F==="large",[`${O}-sm`]:F==="small"}),j=f.exports.isValidElement(S),H=m||(h==null?void 0:h.shape)||"circle",W=te(O,k,v==null?void 0:v.className,`${O}-${H}`,{[`${O}-image`]:j||S&&a,[`${O}-icon`]:!!$},B,M,E,w,A),Y=typeof F=="number"?{width:F,height:F,fontSize:$?F/2:18}:{};let K;if(typeof S=="string"&&a)K=C("img",{src:S,draggable:P,srcSet:x,onError:p,alt:R,crossOrigin:I});else if(j)K=S;else if($)K=$;else if(o||n!==1){const q=`scale(${n})`,ee={msTransform:q,WebkitTransform:q,transform:q};K=C(mr,{onResize:g,children:C("span",{className:`${O}-string`,ref:c,style:Object.assign({},ee),children:N})})}else K=C("span",{className:`${O}-string`,style:{opacity:0},ref:c,children:N});return delete z.onError,delete z.gap,L(C("span",{...Object.assign({},z,{style:Object.assign(Object.assign(Object.assign(Object.assign({},Y),_),v==null?void 0:v.style),z.style),className:W,ref:u}),children:K}))},hD=f.exports.forwardRef(gD),a2=hD,td=e=>e?typeof e=="function"?e():e:null;function gm(e){var t=e.children,n=e.prefixCls,r=e.id,o=e.overlayInnerStyle,i=e.className,a=e.style;return C("div",{className:te("".concat(n,"-content"),i),style:a,children:C("div",{className:"".concat(n,"-inner"),id:r,role:"tooltip",style:o,children:typeof t=="function"?t():t})})}var Zi={shiftX:64,adjustY:1},Ji={adjustX:1,shiftY:!0},ur=[0,0],mD={left:{points:["cr","cl"],overflow:Ji,offset:[-4,0],targetOffset:ur},right:{points:["cl","cr"],overflow:Ji,offset:[4,0],targetOffset:ur},top:{points:["bc","tc"],overflow:Zi,offset:[0,-4],targetOffset:ur},bottom:{points:["tc","bc"],overflow:Zi,offset:[0,4],targetOffset:ur},topLeft:{points:["bl","tl"],overflow:Zi,offset:[0,-4],targetOffset:ur},leftTop:{points:["tr","tl"],overflow:Ji,offset:[-4,0],targetOffset:ur},topRight:{points:["br","tr"],overflow:Zi,offset:[0,-4],targetOffset:ur},rightTop:{points:["tl","tr"],overflow:Ji,offset:[4,0],targetOffset:ur},bottomRight:{points:["tr","br"],overflow:Zi,offset:[0,4],targetOffset:ur},rightBottom:{points:["bl","br"],overflow:Ji,offset:[4,0],targetOffset:ur},bottomLeft:{points:["tl","bl"],overflow:Zi,offset:[0,4],targetOffset:ur},leftBottom:{points:["br","bl"],overflow:Ji,offset:[-4,0],targetOffset:ur}},yD=["overlayClassName","trigger","mouseEnterDelay","mouseLeaveDelay","overlayStyle","prefixCls","children","onVisibleChange","afterVisibleChange","transitionName","animation","motion","placement","align","destroyTooltipOnHide","defaultVisible","getTooltipContainer","overlayInnerStyle","arrowContent","overlay","id","showArrow"],bD=function(t,n){var r=t.overlayClassName,o=t.trigger,i=o===void 0?["hover"]:o,a=t.mouseEnterDelay,l=a===void 0?0:a,s=t.mouseLeaveDelay,c=s===void 0?.1:s,u=t.overlayStyle,d=t.prefixCls,v=d===void 0?"rc-tooltip":d,h=t.children,g=t.onVisibleChange,p=t.afterVisibleChange,b=t.transitionName,m=t.animation,y=t.motion,S=t.placement,x=S===void 0?"right":S,$=t.align,E=$===void 0?{}:$,w=t.destroyTooltipOnHide,R=w===void 0?!1:w,P=t.defaultVisible,N=t.getTooltipContainer,I=t.overlayInnerStyle;t.arrowContent;var z=t.overlay,F=t.id,T=t.showArrow,D=T===void 0?!0:T,_=Je(t,yD),O=f.exports.useRef(null);f.exports.useImperativeHandle(n,function(){return O.current});var M=U({},_);"visible"in t&&(M.popupVisible=t.visible);var L=function(){return C(gm,{prefixCls:v,id:F,overlayInnerStyle:I,children:z},"content")};return C(lf,{popupClassName:r,prefixCls:v,popup:L,action:i,builtinPlacements:mD,popupPlacement:x,ref:O,popupAlign:E,getPopupContainer:N,onPopupVisibleChange:g,afterPopupVisibleChange:p,popupTransitionName:b,popupAnimation:m,popupMotion:y,defaultPopupVisible:P,autoDestroy:R,mouseLeaveDelay:c,popupStyle:u,mouseEnterDelay:l,arrow:D,...M,children:h})};const SD=f.exports.forwardRef(bD);function hm(e){const{sizePopupArrow:t,borderRadiusXS:n,borderRadiusOuter:r}=e,o=t/2,i=0,a=o,l=r*1/Math.sqrt(2),s=o-r*(1-1/Math.sqrt(2)),c=o-n*(1/Math.sqrt(2)),u=r*(Math.sqrt(2)-1)+n*(1/Math.sqrt(2)),d=2*o-c,v=u,h=2*o-l,g=s,p=2*o-i,b=a,m=o*Math.sqrt(2)+r*(Math.sqrt(2)-2),y=r*(Math.sqrt(2)-1),S=`polygon(${y}px 100%, 50% ${y}px, ${2*o-y}px 100%, ${y}px 100%)`,x=`path('M ${i} ${a} A ${r} ${r} 0 0 0 ${l} ${s} L ${c} ${u} A ${n} ${n} 0 0 1 ${d} ${v} L ${h} ${g} A ${r} ${r} 0 0 0 ${p} ${b} Z')`;return{arrowShadowWidth:m,arrowPath:x,arrowPolygon:S}}const l2=(e,t,n)=>{const{sizePopupArrow:r,arrowPolygon:o,arrowPath:i,arrowShadowWidth:a,borderRadiusXS:l,calc:s}=e;return{pointerEvents:"none",width:r,height:r,overflow:"hidden","&::before":{position:"absolute",bottom:0,insetInlineStart:0,width:r,height:s(r).div(2).equal(),background:t,clipPath:{_multi_value_:!0,value:[o,i]},content:'""'},"&::after":{content:'""',position:"absolute",width:a,height:a,bottom:0,insetInline:0,margin:"auto",borderRadius:{_skip_check_:!0,value:`0 0 ${X(l)} 0`},transform:"translateY(50%) rotate(-135deg)",boxShadow:n,zIndex:0,background:"transparent"}}},s2=8;function mm(e){const{contentRadius:t,limitVerticalRadius:n}=e,r=t>12?t+2:12;return{arrowOffsetHorizontal:r,arrowOffsetVertical:n?s2:r}}function _c(e,t){return e?t:{}}function c2(e,t,n){const{componentCls:r,boxShadowPopoverArrow:o,arrowOffsetVertical:i,arrowOffsetHorizontal:a}=e,{arrowDistance:l=0,arrowPlacement:s={left:!0,right:!0,top:!0,bottom:!0}}=n||{};return{[r]:Object.assign(Object.assign(Object.assign(Object.assign({[`${r}-arrow`]:[Object.assign(Object.assign({position:"absolute",zIndex:1,display:"block"},l2(e,t,o)),{"&:before":{background:t}})]},_c(!!s.top,{[[`&-placement-top > ${r}-arrow`,`&-placement-topLeft > ${r}-arrow`,`&-placement-topRight > ${r}-arrow`].join(",")]:{bottom:l,transform:"translateY(100%) rotate(180deg)"},[`&-placement-top > ${r}-arrow`]:{left:{_skip_check_:!0,value:"50%"},transform:"translateX(-50%) translateY(100%) rotate(180deg)"},[`&-placement-topLeft > ${r}-arrow`]:{left:{_skip_check_:!0,value:a}},[`&-placement-topRight > ${r}-arrow`]:{right:{_skip_check_:!0,value:a}}})),_c(!!s.bottom,{[[`&-placement-bottom > ${r}-arrow`,`&-placement-bottomLeft > ${r}-arrow`,`&-placement-bottomRight > ${r}-arrow`].join(",")]:{top:l,transform:"translateY(-100%)"},[`&-placement-bottom > ${r}-arrow`]:{left:{_skip_check_:!0,value:"50%"},transform:"translateX(-50%) translateY(-100%)"},[`&-placement-bottomLeft > ${r}-arrow`]:{left:{_skip_check_:!0,value:a}},[`&-placement-bottomRight > ${r}-arrow`]:{right:{_skip_check_:!0,value:a}}})),_c(!!s.left,{[[`&-placement-left > ${r}-arrow`,`&-placement-leftTop > ${r}-arrow`,`&-placement-leftBottom > ${r}-arrow`].join(",")]:{right:{_skip_check_:!0,value:l},transform:"translateX(100%) rotate(90deg)"},[`&-placement-left > ${r}-arrow`]:{top:{_skip_check_:!0,value:"50%"},transform:"translateY(-50%) translateX(100%) rotate(90deg)"},[`&-placement-leftTop > ${r}-arrow`]:{top:i},[`&-placement-leftBottom > ${r}-arrow`]:{bottom:i}})),_c(!!s.right,{[[`&-placement-right > ${r}-arrow`,`&-placement-rightTop > ${r}-arrow`,`&-placement-rightBottom > ${r}-arrow`].join(",")]:{left:{_skip_check_:!0,value:l},transform:"translateX(-100%) rotate(-90deg)"},[`&-placement-right > ${r}-arrow`]:{top:{_skip_check_:!0,value:"50%"},transform:"translateY(-50%) translateX(-100%) rotate(-90deg)"},[`&-placement-rightTop > ${r}-arrow`]:{top:i},[`&-placement-rightBottom > ${r}-arrow`]:{bottom:i}}))}}function CD(e,t,n,r){if(r===!1)return{adjustX:!1,adjustY:!1};const o=r&&typeof r=="object"?r:{},i={};switch(e){case"top":case"bottom":i.shiftX=t.arrowOffsetHorizontal*2+n,i.shiftY=!0,i.adjustY=!0;break;case"left":case"right":i.shiftY=t.arrowOffsetVertical*2+n,i.shiftX=!0,i.adjustX=!0;break}const a=Object.assign(Object.assign({},i),o);return a.shiftX||(a.adjustX=!0),a.shiftY||(a.adjustY=!0),a}const Db={left:{points:["cr","cl"]},right:{points:["cl","cr"]},top:{points:["bc","tc"]},bottom:{points:["tc","bc"]},topLeft:{points:["bl","tl"]},leftTop:{points:["tr","tl"]},topRight:{points:["br","tr"]},rightTop:{points:["tl","tr"]},bottomRight:{points:["tr","br"]},rightBottom:{points:["bl","br"]},bottomLeft:{points:["tl","bl"]},leftBottom:{points:["br","bl"]}},xD={topLeft:{points:["bl","tc"]},leftTop:{points:["tr","cl"]},topRight:{points:["br","tc"]},rightTop:{points:["tl","cr"]},bottomRight:{points:["tr","bc"]},rightBottom:{points:["bl","cr"]},bottomLeft:{points:["tl","bc"]},leftBottom:{points:["br","cl"]}},wD=new Set(["topLeft","topRight","bottomLeft","bottomRight","leftTop","leftBottom","rightTop","rightBottom"]);function $D(e){const{arrowWidth:t,autoAdjustOverflow:n,arrowPointAtCenter:r,offset:o,borderRadius:i,visibleFirst:a}=e,l=t/2,s={};return Object.keys(Db).forEach(c=>{const u=r&&xD[c]||Db[c],d=Object.assign(Object.assign({},u),{offset:[0,0],dynamicInset:!0});switch(s[c]=d,wD.has(c)&&(d.autoArrow=!1),c){case"top":case"topLeft":case"topRight":d.offset[1]=-l-o;break;case"bottom":case"bottomLeft":case"bottomRight":d.offset[1]=l+o;break;case"left":case"leftTop":case"leftBottom":d.offset[0]=-l-o;break;case"right":case"rightTop":case"rightBottom":d.offset[0]=l+o;break}const v=mm({contentRadius:i,limitVerticalRadius:!0});if(r)switch(c){case"topLeft":case"bottomLeft":d.offset[0]=-v.arrowOffsetHorizontal-l;break;case"topRight":case"bottomRight":d.offset[0]=v.arrowOffsetHorizontal+l;break;case"leftTop":case"rightTop":d.offset[1]=-v.arrowOffsetHorizontal-l;break;case"leftBottom":case"rightBottom":d.offset[1]=v.arrowOffsetHorizontal+l;break}d.overflow=CD(c,v,t,n),a&&(d.htmlRegion="visibleFirst")}),s}const ED=e=>{const{componentCls:t,tooltipMaxWidth:n,tooltipColor:r,tooltipBg:o,tooltipBorderRadius:i,zIndexPopup:a,controlHeight:l,boxShadowSecondary:s,paddingSM:c,paddingXS:u}=e;return[{[t]:Object.assign(Object.assign(Object.assign(Object.assign({},Qt(e)),{position:"absolute",zIndex:a,display:"block",width:"max-content",maxWidth:n,visibility:"visible",transformOrigin:"var(--arrow-x, 50%) var(--arrow-y, 50%)","&-hidden":{display:"none"},"--antd-arrow-background-color":o,[`${t}-inner`]:{minWidth:l,minHeight:l,padding:`${X(e.calc(c).div(2).equal())} ${X(u)}`,color:r,textAlign:"start",textDecoration:"none",wordWrap:"break-word",backgroundColor:o,borderRadius:i,boxShadow:s,boxSizing:"border-box"},[["&-placement-left","&-placement-leftTop","&-placement-leftBottom","&-placement-right","&-placement-rightTop","&-placement-rightBottom"].join(",")]:{[`${t}-inner`]:{borderRadius:e.min(i,s2)}},[`${t}-content`]:{position:"relative"}}),ow(e,(d,v)=>{let{darkColor:h}=v;return{[`&${t}-${d}`]:{[`${t}-inner`]:{backgroundColor:h},[`${t}-arrow`]:{"--antd-arrow-background-color":h}}}})),{"&-rtl":{direction:"rtl"}})},c2(e,"var(--antd-arrow-background-color)"),{[`${t}-pure`]:{position:"relative",maxWidth:"none",margin:e.sizePopupArrow}}]},MD=e=>Object.assign(Object.assign({zIndexPopup:e.zIndexPopupBase+70},mm({contentRadius:e.borderRadius,limitVerticalRadius:!0})),hm($t(e,{borderRadiusOuter:Math.min(e.borderRadiusOuter,4)}))),u2=function(e){let t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!0;return vn("Tooltip",r=>{const{borderRadius:o,colorTextLightSolid:i,colorBgSpotlight:a}=r,l=$t(r,{tooltipMaxWidth:250,tooltipColor:i,tooltipBorderRadius:o,tooltipBg:a});return[ED(l),of(r,"zoom-big-fast")]},MD,{resetStyle:!1,injectStyle:t})(e)},OD=$s.map(e=>`${e}-inverse`),RD=["success","processing","error","default","warning"];function d2(e){return(arguments.length>1&&arguments[1]!==void 0?arguments[1]:!0)?[].concat(Oe(OD),Oe($s)).includes(e):$s.includes(e)}function ID(e){return RD.includes(e)}function f2(e,t){const n=d2(t),r=te({[`${e}-${t}`]:t&&n}),o={},i={};return t&&!n&&(o.background=t,i["--antd-arrow-background-color"]=t),{className:r,overlayStyle:o,arrowStyle:i}}const PD=e=>{const{prefixCls:t,className:n,placement:r="top",title:o,color:i,overlayInnerStyle:a}=e,{getPrefixCls:l}=f.exports.useContext(ot),s=l("tooltip",t),[c,u,d]=u2(s),v=f2(s,i),h=v.arrowStyle,g=Object.assign(Object.assign({},a),v.overlayStyle),p=te(u,d,s,`${s}-pure`,`${s}-placement-${r}`,n,v.className);return c(ie("div",{className:p,style:h,children:[C("div",{className:`${s}-arrow`}),C(gm,{...Object.assign({},e,{className:u,prefixCls:s,overlayInnerStyle:g}),children:o})]}))},TD=PD;var ND=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{var n,r;const{prefixCls:o,openClassName:i,getTooltipContainer:a,overlayClassName:l,color:s,overlayInnerStyle:c,children:u,afterOpenChange:d,afterVisibleChange:v,destroyTooltipOnHide:h,arrow:g=!0,title:p,overlay:b,builtinPlacements:m,arrowPointAtCenter:y=!1,autoAdjustOverflow:S=!0}=e,x=!!g,[,$]=Kn(),{getPopupContainer:E,getPrefixCls:w,direction:R}=f.exports.useContext(ot),P=jx(),N=f.exports.useRef(null),I=()=>{var ce;(ce=N.current)===null||ce===void 0||ce.forceAlign()};f.exports.useImperativeHandle(t,()=>({forceAlign:I,forcePopupAlign:()=>{P.deprecated(!1,"forcePopupAlign","forceAlign"),I()}}));const[z,F]=kt(!1,{value:(n=e.open)!==null&&n!==void 0?n:e.visible,defaultValue:(r=e.defaultOpen)!==null&&r!==void 0?r:e.defaultVisible}),T=!p&&!b&&p!==0,D=ce=>{var de,xe;F(T?!1:ce),T||((de=e.onOpenChange)===null||de===void 0||de.call(e,ce),(xe=e.onVisibleChange)===null||xe===void 0||xe.call(e,ce))},_=f.exports.useMemo(()=>{var ce,de;let xe=y;return typeof g=="object"&&(xe=(de=(ce=g.pointAtCenter)!==null&&ce!==void 0?ce:g.arrowPointAtCenter)!==null&&de!==void 0?de:y),m||$D({arrowPointAtCenter:xe,autoAdjustOverflow:S,arrowWidth:x?$.sizePopupArrow:0,borderRadius:$.borderRadius,offset:$.marginXXS,visibleFirst:!0})},[y,g,m,$]),O=f.exports.useMemo(()=>p===0?p:b||p||"",[b,p]),M=C(ig,{children:typeof O=="function"?O():O}),{getPopupContainer:L,placement:A="top",mouseEnterDelay:B=.1,mouseLeaveDelay:k=.1,overlayStyle:j,rootClassName:H}=e,W=ND(e,["getPopupContainer","placement","mouseEnterDelay","mouseLeaveDelay","overlayStyle","rootClassName"]),Y=w("tooltip",o),K=w(),q=e["data-popover-inject"];let ee=z;!("open"in e)&&!("visible"in e)&&T&&(ee=!1);const Z=Es(u)&&!hw(u)?u:C("span",{children:u}),Q=Z.props,ne=!Q.className||typeof Q.className=="string"?te(Q.className,i||`${Y}-open`):Q.className,[ae,J,re]=u2(Y,!q),fe=f2(Y,s),ve=fe.arrowStyle,pe=Object.assign(Object.assign({},c),fe.overlayStyle),oe=te(l,{[`${Y}-rtl`]:R==="rtl"},fe.className,H,J,re),[se,le]=Qd("Tooltip",W.zIndex),Ce=C(SD,{...Object.assign({},W,{zIndex:se,showArrow:x,placement:A,mouseEnterDelay:B,mouseLeaveDelay:k,prefixCls:Y,overlayClassName:oe,overlayStyle:Object.assign(Object.assign({},ve),j),getTooltipContainer:L||a||E,ref:N,builtinPlacements:_,overlay:M,visible:ee,onVisibleChange:D,afterVisibleChange:d!=null?d:v,overlayInnerStyle:pe,arrowContent:C("span",{className:`${Y}-arrow-content`}),motion:{motionName:ni(K,"zoom-big-fast",e.transitionName),motionDeadline:1e3},destroyTooltipOnHide:!!h}),children:ee?ti(Z,{className:ne}):Z});return ae(f.exports.createElement(mw.Provider,{value:le},Ce))});v2._InternalPanelDoNotUseOrYouWillBeFired=TD;const p2=v2,_D=e=>{const{componentCls:t,popoverColor:n,titleMinWidth:r,fontWeightStrong:o,innerPadding:i,boxShadowSecondary:a,colorTextHeading:l,borderRadiusLG:s,zIndexPopup:c,titleMarginBottom:u,colorBgElevated:d,popoverBg:v,titleBorderBottom:h,innerContentPadding:g,titlePadding:p}=e;return[{[t]:Object.assign(Object.assign({},Qt(e)),{position:"absolute",top:0,left:{_skip_check_:!0,value:0},zIndex:c,fontWeight:"normal",whiteSpace:"normal",textAlign:"start",cursor:"auto",userSelect:"text",transformOrigin:"var(--arrow-x, 50%) var(--arrow-y, 50%)","--antd-arrow-background-color":d,"&-rtl":{direction:"rtl"},"&-hidden":{display:"none"},[`${t}-content`]:{position:"relative"},[`${t}-inner`]:{backgroundColor:v,backgroundClip:"padding-box",borderRadius:s,boxShadow:a,padding:i},[`${t}-title`]:{minWidth:r,marginBottom:u,color:l,fontWeight:o,borderBottom:h,padding:p},[`${t}-inner-content`]:{color:n,padding:g}})},c2(e,"var(--antd-arrow-background-color)"),{[`${t}-pure`]:{position:"relative",maxWidth:"none",margin:e.sizePopupArrow,display:"inline-block",[`${t}-content`]:{display:"inline-block"}}}]},AD=e=>{const{componentCls:t}=e;return{[t]:$s.map(n=>{const r=e[`${n}6`];return{[`&${t}-${n}`]:{"--antd-arrow-background-color":r,[`${t}-inner`]:{backgroundColor:r},[`${t}-arrow`]:{background:"transparent"}}}})}},DD=e=>{const{lineWidth:t,controlHeight:n,fontHeight:r,padding:o,wireframe:i,zIndexPopupBase:a,borderRadiusLG:l,marginXS:s,lineType:c,colorSplit:u,paddingSM:d}=e,v=n-r,h=v/2,g=v/2-t,p=o;return Object.assign(Object.assign(Object.assign({titleMinWidth:177,zIndexPopup:a+30},hm(e)),mm({contentRadius:l,limitVerticalRadius:!0})),{innerPadding:i?0:12,titleMarginBottom:i?0:s,titlePadding:i?`${h}px ${p}px ${g}px`:0,titleBorderBottom:i?`${t}px ${c} ${u}`:"none",innerContentPadding:i?`${d}px ${p}px`:0})},g2=vn("Popover",e=>{const{colorBgElevated:t,colorText:n}=e,r=$t(e,{popoverBg:t,popoverColor:n});return[_D(r),AD(r),of(r,"zoom-big")]},DD,{resetStyle:!1,deprecatedTokens:[["width","titleMinWidth"],["minWidth","titleMinWidth"]]});var LD=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o!t&&!n?null:ie(Tt,{children:[t&&C("div",{className:`${e}-title`,children:td(t)}),C("div",{className:`${e}-inner-content`,children:td(n)})]}),FD=e=>{const{hashId:t,prefixCls:n,className:r,style:o,placement:i="top",title:a,content:l,children:s}=e;return ie("div",{className:te(t,n,`${n}-pure`,`${n}-placement-${i}`,r),style:o,children:[C("div",{className:`${n}-arrow`}),C(gm,{...Object.assign({},e,{className:t,prefixCls:n}),children:s||zD(n,a,l)})]})},kD=e=>{const{prefixCls:t,className:n}=e,r=LD(e,["prefixCls","className"]),{getPrefixCls:o}=f.exports.useContext(ot),i=o("popover",t),[a,l,s]=g2(i);return a(C(FD,{...Object.assign({},r,{prefixCls:i,hashId:l,className:te(n,s)})}))},BD=kD;var jD=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{let{title:t,content:n,prefixCls:r}=e;return ie(Tt,{children:[t&&C("div",{className:`${r}-title`,children:td(t)}),C("div",{className:`${r}-inner-content`,children:td(n)})]})},h2=f.exports.forwardRef((e,t)=>{const{prefixCls:n,title:r,content:o,overlayClassName:i,placement:a="top",trigger:l="hover",mouseEnterDelay:s=.1,mouseLeaveDelay:c=.1,overlayStyle:u={}}=e,d=jD(e,["prefixCls","title","content","overlayClassName","placement","trigger","mouseEnterDelay","mouseLeaveDelay","overlayStyle"]),{getPrefixCls:v}=f.exports.useContext(ot),h=v("popover",n),[g,p,b]=g2(h),m=v(),y=te(i,p,b);return g(C(p2,{...Object.assign({placement:a,trigger:l,mouseEnterDelay:s,mouseLeaveDelay:c,overlayStyle:u},d,{prefixCls:h,overlayClassName:y,ref:t,overlay:r||o?C(HD,{prefixCls:h,title:r,content:o}):null,transitionName:ni(m,"zoom-big",d.transitionName),"data-popover-inject":!0})}))});h2._InternalPanelDoNotUseOrYouWillBeFired=BD;const WD=h2,Lb=e=>{const{size:t,shape:n}=f.exports.useContext(Cg),r=f.exports.useMemo(()=>({size:e.size||t,shape:e.shape||n}),[e.size,e.shape,t,n]);return C(Cg.Provider,{value:r,children:e.children})},VD=e=>{const{getPrefixCls:t,direction:n}=f.exports.useContext(ot),{prefixCls:r,className:o,rootClassName:i,style:a,maxCount:l,maxStyle:s,size:c,shape:u,maxPopoverPlacement:d="top",maxPopoverTrigger:v="hover",children:h}=e,g=t("avatar",r),p=`${g}-group`,b=no(g),[m,y,S]=i2(g,b),x=te(p,{[`${p}-rtl`]:n==="rtl"},S,b,o,i,y),$=Qo(h).map((w,R)=>ti(w,{key:`avatar-key-${R}`})),E=$.length;if(l&&l1&&arguments[1]!==void 0?arguments[1]:!1;if(Jd(e)){var n=e.nodeName.toLowerCase(),r=["input","select","textarea","button"].includes(n)||e.isContentEditable||n==="a"&&!!e.getAttribute("href"),o=e.getAttribute("tabindex"),i=Number(o),a=null;return o&&!Number.isNaN(i)?a=i:r&&a===null&&(a=0),r&&e.disabled&&(a=null),a!==null&&(a>=0||t&&a<0)}return!1}function rL(e){var t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1,n=Oe(e.querySelectorAll("*")).filter(function(r){return zb(r,t)});return zb(e,t)&&n.unshift(e),n}var xg=ue.LEFT,wg=ue.RIGHT,$g=ue.UP,au=ue.DOWN,lu=ue.ENTER,$2=ue.ESC,$l=ue.HOME,El=ue.END,Fb=[$g,au,xg,wg];function oL(e,t,n,r){var o,i,a,l,s="prev",c="next",u="children",d="parent";if(e==="inline"&&r===lu)return{inlineTrigger:!0};var v=(o={},V(o,$g,s),V(o,au,c),o),h=(i={},V(i,xg,n?c:s),V(i,wg,n?s:c),V(i,au,u),V(i,lu,u),i),g=(a={},V(a,$g,s),V(a,au,c),V(a,lu,u),V(a,$2,d),V(a,xg,n?u:d),V(a,wg,n?d:u),a),p={inline:v,horizontal:h,vertical:g,inlineSub:v,horizontalSub:g,verticalSub:g},b=(l=p["".concat(e).concat(t?"":"Sub")])===null||l===void 0?void 0:l[r];switch(b){case s:return{offset:-1,sibling:!0};case c:return{offset:1,sibling:!0};case d:return{offset:-1,sibling:!1};case u:return{offset:1,sibling:!1};default:return null}}function iL(e){for(var t=e;t;){if(t.getAttribute("data-menu-list"))return t;t=t.parentElement}return null}function aL(e,t){for(var n=e||document.activeElement;n;){if(t.has(n))return n;n=n.parentElement}return null}function bm(e,t){var n=rL(e,!0);return n.filter(function(r){return t.has(r)})}function kb(e,t,n){var r=arguments.length>3&&arguments[3]!==void 0?arguments[3]:1;if(!e)return null;var o=bm(e,t),i=o.length,a=o.findIndex(function(l){return n===l});return r<0?a===-1?a=i-1:a-=1:r>0&&(a+=1),a=(a+i)%i,o[a]}var Eg=function(t,n){var r=new Set,o=new Map,i=new Map;return t.forEach(function(a){var l=document.querySelector("[data-menu-id='".concat(b2(n,a),"']"));l&&(r.add(l),i.set(l,a),o.set(a,l))}),{elements:r,key2element:o,element2key:i}};function lL(e,t,n,r,o,i,a,l,s,c){var u=f.exports.useRef(),d=f.exports.useRef();d.current=t;var v=function(){St.cancel(u.current)};return f.exports.useEffect(function(){return function(){v()}},[]),function(h){var g=h.which;if([].concat(Fb,[lu,$2,$l,El]).includes(g)){var p=i(),b=Eg(p,r),m=b,y=m.elements,S=m.key2element,x=m.element2key,$=S.get(t),E=aL($,y),w=x.get(E),R=oL(e,a(w,!0).length===1,n,g);if(!R&&g!==$l&&g!==El)return;(Fb.includes(g)||[$l,El].includes(g))&&h.preventDefault();var P=function(O){if(O){var M=O,L=O.querySelector("a");L!=null&&L.getAttribute("href")&&(M=L);var A=x.get(O);l(A),v(),u.current=St(function(){d.current===A&&M.focus()})}};if([$l,El].includes(g)||R.sibling||!E){var N;!E||e==="inline"?N=o.current:N=iL(E);var I,z=bm(N,y);g===$l?I=z[0]:g===El?I=z[z.length-1]:I=kb(N,y,E,R.offset),P(I)}else if(R.inlineTrigger)s(w);else if(R.offset>0)s(w,!0),v(),u.current=St(function(){b=Eg(p,r);var _=E.getAttribute("aria-controls"),O=document.getElementById(_),M=kb(O,b.elements);P(M)},5);else if(R.offset<0){var F=a(w,!0),T=F[F.length-2],D=S.get(T);s(T,!1),P(D)}}c==null||c(h)}}function sL(e){Promise.resolve().then(e)}var Sm="__RC_UTIL_PATH_SPLIT__",Bb=function(t){return t.join(Sm)},cL=function(t){return t.split(Sm)},Mg="rc-menu-more";function uL(){var e=f.exports.useState({}),t=G(e,2),n=t[1],r=f.exports.useRef(new Map),o=f.exports.useRef(new Map),i=f.exports.useState([]),a=G(i,2),l=a[0],s=a[1],c=f.exports.useRef(0),u=f.exports.useRef(!1),d=function(){u.current||n({})},v=f.exports.useCallback(function(S,x){var $=Bb(x);o.current.set($,S),r.current.set(S,$),c.current+=1;var E=c.current;sL(function(){E===c.current&&d()})},[]),h=f.exports.useCallback(function(S,x){var $=Bb(x);o.current.delete($),r.current.delete(S)},[]),g=f.exports.useCallback(function(S){s(S)},[]),p=f.exports.useCallback(function(S,x){var $=r.current.get(S)||"",E=cL($);return x&&l.includes(E[0])&&E.unshift(Mg),E},[l]),b=f.exports.useCallback(function(S,x){return S.some(function($){var E=p($,!0);return E.includes(x)})},[p]),m=function(){var x=Oe(r.current.keys());return l.length&&x.push(Mg),x},y=f.exports.useCallback(function(S){var x="".concat(r.current.get(S)).concat(Sm),$=new Set;return Oe(o.current.keys()).forEach(function(E){E.startsWith(x)&&$.add(o.current.get(E))}),$},[]);return f.exports.useEffect(function(){return function(){u.current=!0}},[]),{registerPath:v,unregisterPath:h,refreshOverflowKeys:g,isSubPathKey:b,getKeyPath:p,getKeys:m,getSubPathKeys:y}}function _l(e){var t=f.exports.useRef(e);t.current=e;var n=f.exports.useCallback(function(){for(var r,o=arguments.length,i=new Array(o),a=0;a1&&(y.motionAppear=!1);var S=y.onVisibleChanged;return y.onVisibleChanged=function(x){return!v.current&&!x&&b(!0),S==null?void 0:S(x)},p?null:C(Is,{mode:i,locked:!v.current,children:C(to,{visible:m,...y,forceRender:s,removeOnLeave:!1,leavedClassName:"".concat(l,"-hidden"),children:function(x){var $=x.className,E=x.style;return C(Cm,{id:t,className:$,style:E,children:o})}})})}var OL=["style","className","title","eventKey","warnKey","disabled","internalPopupClose","children","itemIcon","expandIcon","popupClassName","popupOffset","popupStyle","onClick","onMouseEnter","onMouseLeave","onTitleClick","onTitleMouseEnter","onTitleMouseLeave"],RL=["active"],IL=function(t){var n,r=t.style,o=t.className,i=t.title,a=t.eventKey;t.warnKey;var l=t.disabled,s=t.internalPopupClose,c=t.children,u=t.itemIcon,d=t.expandIcon,v=t.popupClassName,h=t.popupOffset,g=t.popupStyle,p=t.onClick,b=t.onMouseEnter,m=t.onMouseLeave,y=t.onTitleClick,S=t.onTitleMouseEnter,x=t.onTitleMouseLeave,$=Je(t,OL),E=S2(a),w=f.exports.useContext(jr),R=w.prefixCls,P=w.mode,N=w.openKeys,I=w.disabled,z=w.overflowDisabled,F=w.activeKey,T=w.selectedKeys,D=w.itemIcon,_=w.expandIcon,O=w.onItemClick,M=w.onOpenChange,L=w.onActive,A=f.exports.useContext(ym),B=A._internalRenderSubMenuItem,k=f.exports.useContext(w2),j=k.isSubPathKey,H=Xs(),W="".concat(R,"-submenu"),Y=I||l,K=f.exports.useRef(),q=f.exports.useRef(),ee=u!=null?u:D,Z=d!=null?d:_,Q=N.includes(a),ne=!z&&Q,ae=j(T,a),J=E2(a,Y,S,x),re=J.active,fe=Je(J,RL),ve=f.exports.useState(!1),pe=G(ve,2),oe=pe[0],se=pe[1],le=function(_e){Y||se(_e)},Ce=function(_e){le(!0),b==null||b({key:a,domEvent:_e})},ce=function(_e){le(!1),m==null||m({key:a,domEvent:_e})},de=f.exports.useMemo(function(){return re||(P!=="inline"?oe||j([F],a):!1)},[P,re,F,oe,a,j]),xe=M2(H.length),he=function(_e){Y||(y==null||y({key:a,domEvent:_e}),P==="inline"&&M(a,!Q))},ke=_l(function(Ee){p==null||p(nd(Ee)),O(Ee)}),we=function(_e){P!=="inline"&&M(a,_e)},ge=function(){L(a)},Pe=E&&"".concat(E,"-popup"),Se=ie("div",{role:"menuitem",style:xe,className:"".concat(W,"-title"),tabIndex:Y?null:-1,ref:K,title:typeof i=="string"?i:null,"data-menu-id":z&&E?null:E,"aria-expanded":ne,"aria-haspopup":!0,"aria-controls":Pe,"aria-disabled":Y,onClick:he,onFocus:ge,...fe,children:[i,C(O2,{icon:P!=="horizontal"?Z:void 0,props:U(U({},t),{},{isOpen:ne,isSubMenu:!0}),children:C("i",{className:"".concat(W,"-arrow")})})]}),st=f.exports.useRef(P);if(P!=="inline"&&H.length>1?st.current="vertical":st.current=P,!z){var nt=st.current;Se=C(EL,{mode:nt,prefixCls:W,visible:!s&&ne&&P!=="inline",popupClassName:v,popupOffset:h,popupStyle:g,popup:C(Is,{mode:nt==="horizontal"?"vertical":nt,children:C(Cm,{id:Pe,ref:q,children:c})}),disabled:Y,onVisibleChange:we,children:Se})}var Ne=ie(Zr.Item,{role:"none",...$,component:"li",style:r,className:te(W,"".concat(W,"-").concat(P),o,(n={},V(n,"".concat(W,"-open"),ne),V(n,"".concat(W,"-active"),de),V(n,"".concat(W,"-selected"),ae),V(n,"".concat(W,"-disabled"),Y),n)),onMouseEnter:Ce,onMouseLeave:ce,children:[Se,!z&&C(ML,{id:Pe,open:ne,keyPath:H,children:c})]});return B&&(Ne=B(Ne,t,{selected:ae,active:de,open:ne,disabled:Y})),C(Is,{onItemClick:ke,mode:P==="horizontal"?"vertical":P,itemIcon:ee,expandIcon:Z,children:Ne})};function wm(e){var t=e.eventKey,n=e.children,r=Xs(t),o=xm(n,r),i=sf();f.exports.useEffect(function(){if(i)return i.registerPath(t,r),function(){i.unregisterPath(t,r)}},[r]);var a;return i?a=o:a=C(IL,{...e,children:o}),C(x2.Provider,{value:r,children:a})}var PL=["className","title","eventKey","children"],TL=["children"],NL=function(t){var n=t.className,r=t.title;t.eventKey;var o=t.children,i=Je(t,PL),a=f.exports.useContext(jr),l=a.prefixCls,s="".concat(l,"-item-group");return ie("li",{role:"presentation",...i,onClick:function(u){return u.stopPropagation()},className:te(s,n),children:[C("div",{role:"presentation",className:"".concat(s,"-title"),title:typeof r=="string"?r:void 0,children:r}),C("ul",{role:"group",className:"".concat(s,"-list"),children:o})]})};function I2(e){var t=e.children,n=Je(e,TL),r=Xs(n.eventKey),o=xm(t,r),i=sf();return i?o:C(NL,{...lr(n,["warnKey"]),children:o})}function P2(e){var t=e.className,n=e.style,r=f.exports.useContext(jr),o=r.prefixCls,i=sf();return i?null:C("li",{role:"separator",className:te("".concat(o,"-item-divider"),t),style:n})}var _L=["label","children","key","type"];function Og(e){return(e||[]).map(function(t,n){if(t&&Qe(t)==="object"){var r=t,o=r.label,i=r.children,a=r.key,l=r.type,s=Je(r,_L),c=a!=null?a:"tmp-".concat(n);return i||l==="group"?l==="group"?C(I2,{...s,title:o,children:Og(i)},c):C(wm,{...s,title:o,children:Og(i)},c):l==="divider"?C(P2,{...s},c):C(cf,{...s,children:o},c)}return null}).filter(function(t){return t})}function AL(e,t,n){var r=e;return t&&(r=Og(t)),xm(r,n)}var DL=["prefixCls","rootClassName","style","className","tabIndex","items","children","direction","id","mode","inlineCollapsed","disabled","disabledOverflow","subMenuOpenDelay","subMenuCloseDelay","forceSubMenuRender","defaultOpenKeys","openKeys","activeKey","defaultActiveFirst","selectable","multiple","defaultSelectedKeys","selectedKeys","onSelect","onDeselect","inlineIndent","motion","defaultMotions","triggerSubMenuAction","builtinPlacements","itemIcon","expandIcon","overflowedIndicator","overflowedIndicatorPopupClassName","getPopupContainer","onClick","onOpenChange","onKeyDown","openAnimation","openTransitionName","_internalRenderMenuItem","_internalRenderSubMenuItem"],na=[],LL=f.exports.forwardRef(function(e,t){var n,r,o=e,i=o.prefixCls,a=i===void 0?"rc-menu":i,l=o.rootClassName,s=o.style,c=o.className,u=o.tabIndex,d=u===void 0?0:u,v=o.items,h=o.children,g=o.direction,p=o.id,b=o.mode,m=b===void 0?"vertical":b,y=o.inlineCollapsed,S=o.disabled,x=o.disabledOverflow,$=o.subMenuOpenDelay,E=$===void 0?.1:$,w=o.subMenuCloseDelay,R=w===void 0?.1:w,P=o.forceSubMenuRender,N=o.defaultOpenKeys,I=o.openKeys,z=o.activeKey,F=o.defaultActiveFirst,T=o.selectable,D=T===void 0?!0:T,_=o.multiple,O=_===void 0?!1:_,M=o.defaultSelectedKeys,L=o.selectedKeys,A=o.onSelect,B=o.onDeselect,k=o.inlineIndent,j=k===void 0?24:k,H=o.motion,W=o.defaultMotions,Y=o.triggerSubMenuAction,K=Y===void 0?"hover":Y,q=o.builtinPlacements,ee=o.itemIcon,Z=o.expandIcon,Q=o.overflowedIndicator,ne=Q===void 0?"...":Q,ae=o.overflowedIndicatorPopupClassName,J=o.getPopupContainer,re=o.onClick,fe=o.onOpenChange,ve=o.onKeyDown;o.openAnimation,o.openTransitionName;var pe=o._internalRenderMenuItem,oe=o._internalRenderSubMenuItem,se=Je(o,DL),le=f.exports.useMemo(function(){return AL(h,v,na)},[h,v]),Ce=f.exports.useState(!1),ce=G(Ce,2),de=ce[0],xe=ce[1],he=f.exports.useRef(),ke=fL(p),we=g==="rtl",ge=kt(N,{value:I,postState:function(dt){return dt||na}}),Pe=G(ge,2),Se=Pe[0],st=Pe[1],nt=function(dt){var Fe=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1;function Ye(){st(dt),fe==null||fe(dt)}Fe?Gn.exports.flushSync(Ye):Ye()},Ne=f.exports.useState(Se),Ee=G(Ne,2),_e=Ee[0],Be=Ee[1],qe=f.exports.useRef(!1),it=f.exports.useMemo(function(){return(m==="inline"||m==="vertical")&&y?["vertical",y]:[m,!1]},[m,y]),ft=G(it,2),ut=ft[0],Ue=ft[1],He=ut==="inline",Xe=f.exports.useState(ut),Le=G(Xe,2),Re=Le[0],be=Le[1],Ae=f.exports.useState(Ue),Me=G(Ae,2),$e=Me[0],Te=Me[1];f.exports.useEffect(function(){be(ut),Te(Ue),qe.current&&(He?st(_e):nt(na))},[ut,Ue]);var ye=f.exports.useState(0),Ge=G(ye,2),Ze=Ge[0],et=Ge[1],ht=Ze>=le.length-1||Re!=="horizontal"||x;f.exports.useEffect(function(){He&&Be(Se)},[Se]),f.exports.useEffect(function(){return qe.current=!0,function(){qe.current=!1}},[]);var mt=uL(),ct=mt.registerPath,We=mt.unregisterPath,Ve=mt.refreshOverflowKeys,vt=mt.isSubPathKey,Ie=mt.getKeyPath,ze=mt.getKeys,Ke=mt.getSubPathKeys,at=f.exports.useMemo(function(){return{registerPath:ct,unregisterPath:We}},[ct,We]),Gt=f.exports.useMemo(function(){return{isSubPathKey:vt}},[vt]);f.exports.useEffect(function(){Ve(ht?na:le.slice(Ze+1).map(function(bt){return bt.key}))},[Ze,ht]);var At=kt(z||F&&((n=le[0])===null||n===void 0?void 0:n.key),{value:z}),Zt=G(At,2),Jt=Zt[0],kn=Zt[1],qn=_l(function(bt){kn(bt)}),pn=_l(function(){kn(void 0)});f.exports.useImperativeHandle(t,function(){return{list:he.current,focus:function(dt){var Fe,Ye=ze(),yt=Eg(Ye,ke),Bt=yt.elements,It=yt.key2element,Kt=yt.element2key,sn=bm(he.current,Bt),Pn=Jt!=null?Jt:sn[0]?Kt.get(sn[0]):(Fe=le.find(function(jn){return!jn.props.disabled}))===null||Fe===void 0?void 0:Fe.key,cn=It.get(Pn);if(Pn&&cn){var Tn;cn==null||(Tn=cn.focus)===null||Tn===void 0||Tn.call(cn,dt)}}}});var Co=kt(M||[],{value:L,postState:function(dt){return Array.isArray(dt)?dt:dt==null?na:[dt]}}),xo=G(Co,2),In=xo[0],wo=xo[1],wr=function(dt){if(D){var Fe=dt.key,Ye=In.includes(Fe),yt;O?Ye?yt=In.filter(function(It){return It!==Fe}):yt=[].concat(Oe(In),[Fe]):yt=[Fe],wo(yt);var Bt=U(U({},dt),{},{selectedKeys:yt});Ye?B==null||B(Bt):A==null||A(Bt)}!O&&Se.length&&Re!=="inline"&&nt(na)},Bn=_l(function(bt){re==null||re(nd(bt)),wr(bt)}),sr=_l(function(bt,dt){var Fe=Se.filter(function(yt){return yt!==bt});if(dt)Fe.push(bt);else if(Re!=="inline"){var Ye=Ke(bt);Fe=Fe.filter(function(yt){return!Ye.has(yt)})}Vs(Se,Fe,!0)||nt(Fe,!0)}),$r=function(dt,Fe){var Ye=Fe!=null?Fe:!Se.includes(dt);sr(dt,Ye)},Ur=lL(Re,Jt,we,ke,he,ze,Ie,kn,$r,ve);f.exports.useEffect(function(){xe(!0)},[]);var Xn=f.exports.useMemo(function(){return{_internalRenderMenuItem:pe,_internalRenderSubMenuItem:oe}},[pe,oe]),$o=Re!=="horizontal"||x?le:le.map(function(bt,dt){return C(Is,{overflowDisabled:dt>Ze,children:bt},bt.key)}),Er=C(Zr,{id:p,ref:he,prefixCls:"".concat(a,"-overflow"),component:"ul",itemComponent:cf,className:te(a,"".concat(a,"-root"),"".concat(a,"-").concat(Re),c,(r={},V(r,"".concat(a,"-inline-collapsed"),$e),V(r,"".concat(a,"-rtl"),we),r),l),dir:g,style:s,role:"menu",tabIndex:d,data:$o,renderRawItem:function(dt){return dt},renderRawRest:function(dt){var Fe=dt.length,Ye=Fe?le.slice(-Fe):null;return C(wm,{eventKey:Mg,title:ne,disabled:ht,internalPopupClose:Fe===0,popupClassName:ae,children:Ye})},maxCount:Re!=="horizontal"||x?Zr.INVALIDATE:Zr.RESPONSIVE,ssr:"full","data-menu-list":!0,onVisibleChange:function(dt){et(dt)},onKeyDown:Ur,...se});return C(ym.Provider,{value:Xn,children:C(y2.Provider,{value:ke,children:ie(Is,{prefixCls:a,rootClassName:l,mode:Re,openKeys:Se,rtl:we,disabled:S,motion:de?H:null,defaultMotions:de?W:null,activeKey:Jt,onActive:qn,onInactive:pn,selectedKeys:In,inlineIndent:j,subMenuOpenDelay:E,subMenuCloseDelay:R,forceSubMenuRender:P,builtinPlacements:q,triggerSubMenuAction:K,getPopupContainer:J,itemIcon:ee,expandIcon:Z,onItemClick:Bn,onOpenChange:sr,children:[C(w2.Provider,{value:Gt,children:Er}),C("div",{style:{display:"none"},"aria-hidden":!0,children:C(C2.Provider,{value:at,children:le})})]})})})}),Qs=LL;Qs.Item=cf;Qs.SubMenu=wm;Qs.ItemGroup=I2;Qs.Divider=P2;var $m={exports:{}};(function(e,t){(function(n,r){e.exports=r()})(Hr,function(){var n=1e3,r=6e4,o=36e5,i="millisecond",a="second",l="minute",s="hour",c="day",u="week",d="month",v="quarter",h="year",g="date",p="Invalid Date",b=/^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/,m=/\[([^\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g,y={name:"en",weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),ordinal:function(T){var D=["th","st","nd","rd"],_=T%100;return"["+T+(D[(_-20)%10]||D[_]||D[0])+"]"}},S=function(T,D,_){var O=String(T);return!O||O.length>=D?T:""+Array(D+1-O.length).join(_)+T},x={s:S,z:function(T){var D=-T.utcOffset(),_=Math.abs(D),O=Math.floor(_/60),M=_%60;return(D<=0?"+":"-")+S(O,2,"0")+":"+S(M,2,"0")},m:function T(D,_){if(D.date()<_.date())return-T(_,D);var O=12*(_.year()-D.year())+(_.month()-D.month()),M=D.clone().add(O,d),L=_-M<0,A=D.clone().add(O+(L?-1:1),d);return+(-(O+(_-M)/(L?M-A:A-M))||0)},a:function(T){return T<0?Math.ceil(T)||0:Math.floor(T)},p:function(T){return{M:d,y:h,w:u,d:c,D:g,h:s,m:l,s:a,ms:i,Q:v}[T]||String(T||"").toLowerCase().replace(/s$/,"")},u:function(T){return T===void 0}},$="en",E={};E[$]=y;var w="$isDayjsObject",R=function(T){return T instanceof z||!(!T||!T[w])},P=function T(D,_,O){var M;if(!D)return $;if(typeof D=="string"){var L=D.toLowerCase();E[L]&&(M=L),_&&(E[L]=_,M=L);var A=D.split("-");if(!M&&A.length>1)return T(A[0])}else{var B=D.name;E[B]=D,M=B}return!O&&M&&($=M),M||!O&&$},N=function(T,D){if(R(T))return T.clone();var _=typeof D=="object"?D:{};return _.date=T,_.args=arguments,new z(_)},I=x;I.l=P,I.i=R,I.w=function(T,D){return N(T,{locale:D.$L,utc:D.$u,x:D.$x,$offset:D.$offset})};var z=function(){function T(_){this.$L=P(_.locale,null,!0),this.parse(_),this.$x=this.$x||_.x||{},this[w]=!0}var D=T.prototype;return D.parse=function(_){this.$d=function(O){var M=O.date,L=O.utc;if(M===null)return new Date(NaN);if(I.u(M))return new Date;if(M instanceof Date)return new Date(M);if(typeof M=="string"&&!/Z$/i.test(M)){var A=M.match(b);if(A){var B=A[2]-1||0,k=(A[7]||"0").substring(0,3);return L?new Date(Date.UTC(A[1],B,A[3]||1,A[4]||0,A[5]||0,A[6]||0,k)):new Date(A[1],B,A[3]||1,A[4]||0,A[5]||0,A[6]||0,k)}}return new Date(M)}(_),this.init()},D.init=function(){var _=this.$d;this.$y=_.getFullYear(),this.$M=_.getMonth(),this.$D=_.getDate(),this.$W=_.getDay(),this.$H=_.getHours(),this.$m=_.getMinutes(),this.$s=_.getSeconds(),this.$ms=_.getMilliseconds()},D.$utils=function(){return I},D.isValid=function(){return this.$d.toString()!==p},D.isSame=function(_,O){var M=N(_);return this.startOf(O)<=M&&M<=this.endOf(O)},D.isAfter=function(_,O){return N(_)25){var u=a(this).startOf(r).add(1,r).date(c),d=a(this).endOf(n);if(u.isBefore(d))return 1}var v=a(this).startOf(r).date(c).startOf(n).subtract(1,"millisecond"),h=this.diff(v,n,!0);return h<0?a(this).startOf("week").week():Math.ceil(h)},l.weeks=function(s){return s===void 0&&(s=null),this.week(s)}}})})(_2);const kL=_2.exports;var A2={exports:{}};(function(e,t){(function(n,r){e.exports=r()})(Hr,function(){return function(n,r){r.prototype.weekYear=function(){var o=this.month(),i=this.week(),a=this.year();return i===1&&o===11?a+1:o===0&&i>=52?a-1:a}}})})(A2);const BL=A2.exports;var D2={exports:{}};(function(e,t){(function(n,r){e.exports=r()})(Hr,function(){return function(n,r){var o=r.prototype,i=o.format;o.format=function(a){var l=this,s=this.$locale();if(!this.isValid())return i.bind(this)(a);var c=this.$utils(),u=(a||"YYYY-MM-DDTHH:mm:ssZ").replace(/\[([^\]]+)]|Q|wo|ww|w|WW|W|zzz|z|gggg|GGGG|Do|X|x|k{1,2}|S/g,function(d){switch(d){case"Q":return Math.ceil((l.$M+1)/3);case"Do":return s.ordinal(l.$D);case"gggg":return l.weekYear();case"GGGG":return l.isoWeekYear();case"wo":return s.ordinal(l.week(),"W");case"w":case"ww":return c.s(l.week(),d==="w"?1:2,"0");case"W":case"WW":return c.s(l.isoWeek(),d==="W"?1:2,"0");case"k":case"kk":return c.s(String(l.$H===0?24:l.$H),d==="k"?1:2,"0");case"X":return Math.floor(l.$d.getTime()/1e3);case"x":return l.$d.getTime();case"z":return"["+l.offsetName()+"]";case"zzz":return"["+l.offsetName("long")+"]";default:return d}});return i.bind(this)(u)}}})})(D2);const jL=D2.exports;var L2={exports:{}};(function(e,t){(function(n,r){e.exports=r()})(Hr,function(){var n={LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},r=/(\[[^[]*\])|([-_:/.,()\s]+)|(A|a|YYYY|YY?|MM?M?M?|Do|DD?|hh?|HH?|mm?|ss?|S{1,3}|z|ZZ?)/g,o=/\d\d/,i=/\d\d?/,a=/\d*[^-_:/,()\s\d]+/,l={},s=function(p){return(p=+p)+(p>68?1900:2e3)},c=function(p){return function(b){this[p]=+b}},u=[/[+-]\d\d:?(\d\d)?|Z/,function(p){(this.zone||(this.zone={})).offset=function(b){if(!b||b==="Z")return 0;var m=b.match(/([+-]|\d\d)/g),y=60*m[1]+(+m[2]||0);return y===0?0:m[0]==="+"?-y:y}(p)}],d=function(p){var b=l[p];return b&&(b.indexOf?b:b.s.concat(b.f))},v=function(p,b){var m,y=l.meridiem;if(y){for(var S=1;S<=24;S+=1)if(p.indexOf(y(S,0,b))>-1){m=S>12;break}}else m=p===(b?"pm":"PM");return m},h={A:[a,function(p){this.afternoon=v(p,!1)}],a:[a,function(p){this.afternoon=v(p,!0)}],S:[/\d/,function(p){this.milliseconds=100*+p}],SS:[o,function(p){this.milliseconds=10*+p}],SSS:[/\d{3}/,function(p){this.milliseconds=+p}],s:[i,c("seconds")],ss:[i,c("seconds")],m:[i,c("minutes")],mm:[i,c("minutes")],H:[i,c("hours")],h:[i,c("hours")],HH:[i,c("hours")],hh:[i,c("hours")],D:[i,c("day")],DD:[o,c("day")],Do:[a,function(p){var b=l.ordinal,m=p.match(/\d+/);if(this.day=m[0],b)for(var y=1;y<=31;y+=1)b(y).replace(/\[|\]/g,"")===p&&(this.day=y)}],M:[i,c("month")],MM:[o,c("month")],MMM:[a,function(p){var b=d("months"),m=(d("monthsShort")||b.map(function(y){return y.slice(0,3)})).indexOf(p)+1;if(m<1)throw new Error;this.month=m%12||m}],MMMM:[a,function(p){var b=d("months").indexOf(p)+1;if(b<1)throw new Error;this.month=b%12||b}],Y:[/[+-]?\d+/,c("year")],YY:[o,function(p){this.year=s(p)}],YYYY:[/\d{4}/,c("year")],Z:u,ZZ:u};function g(p){var b,m;b=p,m=l&&l.formats;for(var y=(p=b.replace(/(\[[^\]]+])|(LTS?|l{1,4}|L{1,4})/g,function(P,N,I){var z=I&&I.toUpperCase();return N||m[I]||n[I]||m[z].replace(/(\[[^\]]+])|(MMMM|MM|DD|dddd)/g,function(F,T,D){return T||D.slice(1)})})).match(r),S=y.length,x=0;x-1)return new Date((O==="X"?1e3:1)*_);var L=g(O)(_),A=L.year,B=L.month,k=L.day,j=L.hours,H=L.minutes,W=L.seconds,Y=L.milliseconds,K=L.zone,q=new Date,ee=k||(A||B?1:q.getDate()),Z=A||q.getFullYear(),Q=0;A&&!B||(Q=B>0?B-1:q.getMonth());var ne=j||0,ae=H||0,J=W||0,re=Y||0;return K?new Date(Date.UTC(Z,Q,ee,ne,ae,J,re+60*K.offset*1e3)):M?new Date(Date.UTC(Z,Q,ee,ne,ae,J,re)):new Date(Z,Q,ee,ne,ae,J,re)}catch{return new Date("")}}($,R,E),this.init(),z&&z!==!0&&(this.$L=this.locale(z).$L),I&&$!=this.format(R)&&(this.$d=new Date("")),l={}}else if(R instanceof Array)for(var F=R.length,T=1;T<=F;T+=1){w[1]=R[T-1];var D=m.apply(this,w);if(D.isValid()){this.$d=D.$d,this.$L=D.$L,this.init();break}T===F&&(this.$d=new Date(""))}else S.call(this,x)}}})})(L2);const HL=L2.exports;Lt.extend(HL);Lt.extend(jL);Lt.extend(zL);Lt.extend(FL);Lt.extend(kL);Lt.extend(BL);Lt.extend(function(e,t){var n=t.prototype,r=n.format;n.format=function(i){var a=(i||"").replace("Wo","wo");return r.bind(this)(a)}});var WL={bn_BD:"bn-bd",by_BY:"be",en_GB:"en-gb",en_US:"en",fr_BE:"fr",fr_CA:"fr-ca",hy_AM:"hy-am",kmr_IQ:"ku",nl_BE:"nl-be",pt_BR:"pt-br",zh_CN:"zh-cn",zh_HK:"zh-hk",zh_TW:"zh-tw"},ci=function(t){var n=WL[t];return n||t.split("_")[0]},Hb=function(){nx(!1,"Not match any format. Please help to fire a issue about this.")},VL={getNow:function(){return Lt()},getFixedDate:function(t){return Lt(t,["YYYY-M-DD","YYYY-MM-DD"])},getEndDate:function(t){return t.endOf("month")},getWeekDay:function(t){var n=t.locale("en");return n.weekday()+n.localeData().firstDayOfWeek()},getYear:function(t){return t.year()},getMonth:function(t){return t.month()},getDate:function(t){return t.date()},getHour:function(t){return t.hour()},getMinute:function(t){return t.minute()},getSecond:function(t){return t.second()},getMillisecond:function(t){return t.millisecond()},addYear:function(t,n){return t.add(n,"year")},addMonth:function(t,n){return t.add(n,"month")},addDate:function(t,n){return t.add(n,"day")},setYear:function(t,n){return t.year(n)},setMonth:function(t,n){return t.month(n)},setDate:function(t,n){return t.date(n)},setHour:function(t,n){return t.hour(n)},setMinute:function(t,n){return t.minute(n)},setSecond:function(t,n){return t.second(n)},setMillisecond:function(t,n){return t.millisecond(n)},isAfter:function(t,n){return t.isAfter(n)},isValidate:function(t){return t.isValid()},locale:{getWeekFirstDay:function(t){return Lt().locale(ci(t)).localeData().firstDayOfWeek()},getWeekFirstDate:function(t,n){return n.locale(ci(t)).weekday(0)},getWeek:function(t,n){return n.locale(ci(t)).week()},getShortWeekDays:function(t){return Lt().locale(ci(t)).localeData().weekdaysMin()},getShortMonths:function(t){return Lt().locale(ci(t)).localeData().monthsShort()},format:function(t,n,r){return n.locale(ci(t)).format(r)},parse:function(t,n,r){for(var o=ci(t),i=0;i2&&arguments[2]!==void 0?arguments[2]:"0",r=String(e);r.length1&&(a=t.addDate(a,-7)),a}function mn(e,t){var n=t.generateConfig,r=t.locale,o=t.format;return e?typeof o=="function"?o(e):n.locale.format(r.locale,e,o):""}function Vb(e,t,n){var r=t,o=["getHour","getMinute","getSecond","getMillisecond"],i=["setHour","setMinute","setSecond","setMillisecond"];return i.forEach(function(a,l){n?r=e[a](r,e[o[l]](n)):r=e[a](r,0)}),r}function oz(e,t,n,r,o,i){var a=e;function l(d,v,h){var g=i[d](a),p=h.find(function(S){return S.value===g});if(!p||p.disabled){var b=h.filter(function(S){return!S.disabled}),m=Oe(b).reverse(),y=m.find(function(S){return S.value<=g})||b[0];y&&(g=y.value,a=i[v](a,g))}return g}var s=l("getHour","setHour",t()),c=l("getMinute","setMinute",n(s)),u=l("getSecond","setSecond",r(s,c));return l("getMillisecond","setMillisecond",o(s,c,u)),a}function Dc(){return[]}function Lc(e,t){for(var n=arguments.length>2&&arguments[2]!==void 0?arguments[2]:1,r=arguments.length>3&&arguments[3]!==void 0?arguments[3]:!1,o=arguments.length>4&&arguments[4]!==void 0?arguments[4]:[],i=arguments.length>5&&arguments[5]!==void 0?arguments[5]:2,a=[],l=n>=1?n|0:1,s=e;s<=t;s+=l){var c=o.includes(s);(!c||!r)&&a.push({label:z2(s,i),value:s,disabled:c})}return a}function H2(e){var t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},n=arguments.length>2?arguments[2]:void 0,r=t||{},o=r.use12Hours,i=r.hourStep,a=i===void 0?1:i,l=r.minuteStep,s=l===void 0?1:l,c=r.secondStep,u=c===void 0?1:c,d=r.millisecondStep,v=d===void 0?100:d,h=r.hideDisabledOptions,g=r.disabledTime,p=r.disabledHours,b=r.disabledMinutes,m=r.disabledSeconds,y=f.exports.useMemo(function(){return n||e.getNow()},[n,e]),S=f.exports.useCallback(function(M){var L=(g==null?void 0:g(M))||{};return[L.disabledHours||p||Dc,L.disabledMinutes||b||Dc,L.disabledSeconds||m||Dc,L.disabledMilliseconds||Dc]},[g,p,b,m]),x=f.exports.useMemo(function(){return S(y)},[y,S]),$=G(x,4),E=$[0],w=$[1],R=$[2],P=$[3],N=f.exports.useCallback(function(M,L,A,B){var k=Lc(0,23,a,h,M()),j=o?k.map(function(K){return U(U({},K),{},{label:z2(K.value%12||12,2)})}):k,H=function(q){return Lc(0,59,s,h,L(q))},W=function(q,ee){return Lc(0,59,u,h,A(q,ee))},Y=function(q,ee,Z){return Lc(0,999,v,h,B(q,ee,Z),3)};return[j,H,W,Y]},[h,a,o,v,s,u]),I=f.exports.useMemo(function(){return N(E,w,R,P)},[N,E,w,R,P]),z=G(I,4),F=z[0],T=z[1],D=z[2],_=z[3],O=function(L,A){var B=function(){return F},k=T,j=D,H=_;if(A){var W=S(A),Y=G(W,4),K=Y[0],q=Y[1],ee=Y[2],Z=Y[3],Q=N(K,q,ee,Z),ne=G(Q,4),ae=ne[0],J=ne[1],re=ne[2],fe=ne[3];B=function(){return ae},k=J,j=re,H=fe}var ve=oz(L,B,k,j,H,e);return ve};return[O,F,T,D,_]}function iz(e,t,n){function r(o,i){var a=o.findIndex(function(s){return xi(e,t,s,i,n)});if(a===-1)return[].concat(Oe(o),[i]);var l=Oe(o);return l.splice(a,1),l}return r}var Hi=f.exports.createContext(null);function df(){return f.exports.useContext(Hi)}function il(e,t){var n=e.prefixCls,r=e.generateConfig,o=e.locale,i=e.disabledDate,a=e.minDate,l=e.maxDate,s=e.cellRender,c=e.hoverValue,u=e.hoverRangeValue,d=e.onHover,v=e.values,h=e.pickerValue,g=e.onSelect,p=e.prevIcon,b=e.nextIcon,m=e.superPrevIcon,y=e.superNextIcon,S=r.getNow(),x={now:S,values:v,pickerValue:h,prefixCls:n,disabledDate:i,minDate:a,maxDate:l,cellRender:s,hoverValue:c,hoverRangeValue:u,onHover:d,locale:o,generateConfig:r,onSelect:g,panelType:t,prevIcon:p,nextIcon:b,superPrevIcon:m,superNextIcon:y};return[x,S]}var Ps=f.exports.createContext({});function Zs(e){for(var t=e.rowNum,n=e.colNum,r=e.baseDate,o=e.getCellDate,i=e.prefixColumn,a=e.rowClassName,l=e.titleFormat,s=e.getCellText,c=e.getCellClassName,u=e.headerCells,d=e.cellSelection,v=d===void 0?!0:d,h=e.disabledDate,g=df(),p=g.prefixCls,b=g.panelType,m=g.now,y=g.disabledDate,S=g.cellRender,x=g.onHover,$=g.hoverValue,E=g.hoverRangeValue,w=g.generateConfig,R=g.values,P=g.locale,N=g.onSelect,I=h||y,z="".concat(p,"-cell"),F=f.exports.useContext(Ps),T=F.onCellDblClick,D=function(j){return R.some(function(H){return H&&xi(w,P,j,H,b)})},_=[],O=0;O1&&arguments[1]!==void 0?arguments[1]:!1;Ce(Ee),b==null||b(Ee),_e&&ce(Ee)},xe=function(Ee,_e){ee(Ee),_e&&de(_e),ce(_e,Ee)},he=function(Ee){if(pe(Ee),de(Ee),q!==x){var _e=["decade","year"],Be=[].concat(_e,["month"]),qe={quarter:[].concat(_e,["quarter"]),week:[].concat(Oe(Be),["week"]),date:[].concat(Oe(Be),["date"])},it=qe[x]||Be,ft=it.indexOf(q),ut=it[ft+1];ut&&xe(ut,Ee)}},ke=f.exports.useMemo(function(){var Ne,Ee;if(Array.isArray(w)){var _e=G(w,2);Ne=_e[0],Ee=_e[1]}else Ne=w;return!Ne&&!Ee?null:(Ne=Ne||Ee,Ee=Ee||Ne,o.isAfter(Ne,Ee)?[Ee,Ne]:[Ne,Ee])},[w,o]),we=GL(R,P,N),ge=z[Z]||hz[Z]||ff,Pe=f.exports.useContext(Ps),Se=f.exports.useMemo(function(){return U(U({},Pe),{},{hideHeader:F})},[Pe,F]),st="".concat(T,"-panel"),nt=k2(e,["showWeek","prevIcon","nextIcon","superPrevIcon","superNextIcon","disabledDate","minDate","maxDate","onHover"]);return C(Ps.Provider,{value:Se,children:C("div",{ref:D,tabIndex:s,className:te(st,V({},"".concat(st,"-rtl"),i==="rtl")),children:C(ge,{...nt,showTime:H,prefixCls:T,locale:k,generateConfig:o,onModeChange:xe,pickerValue:le,onPickerValueChange:function(Ee){de(Ee,!0)},value:fe[0],onSelect:he,values:fe,cellRender:we,hoverRangeValue:ke,hoverValue:E})})})}var yz=f.exports.memo(f.exports.forwardRef(mz));const V2=f.exports.createContext(null),bz=V2.Provider,U2=f.exports.createContext(null),Sz=U2.Provider;var Cz=["prefixCls","className","style","checked","disabled","defaultChecked","type","title","onChange"],xz=f.exports.forwardRef(function(e,t){var n,r=e.prefixCls,o=r===void 0?"rc-checkbox":r,i=e.className,a=e.style,l=e.checked,s=e.disabled,c=e.defaultChecked,u=c===void 0?!1:c,d=e.type,v=d===void 0?"checkbox":d,h=e.title,g=e.onChange,p=Je(e,Cz),b=f.exports.useRef(null),m=kt(u,{value:l}),y=G(m,2),S=y[0],x=y[1];f.exports.useImperativeHandle(t,function(){return{focus:function(){var R;(R=b.current)===null||R===void 0||R.focus()},blur:function(){var R;(R=b.current)===null||R===void 0||R.blur()},input:b.current}});var $=te(o,i,(n={},V(n,"".concat(o,"-checked"),S),V(n,"".concat(o,"-disabled"),s),n)),E=function(R){s||("checked"in e||x(R.target.checked),g==null||g({target:U(U({},e),{},{type:v,checked:R.target.checked}),stopPropagation:function(){R.stopPropagation()},preventDefault:function(){R.preventDefault()},nativeEvent:R.nativeEvent}))};return ie("span",{className:$,title:h,style:a,children:[C("input",{...p,className:"".concat(o,"-input"),ref:b,onChange:E,disabled:s,checked:!!S,type:v}),C("span",{className:"".concat(o,"-inner")})]})});const wz=e=>{const{componentCls:t,antCls:n}=e,r=`${t}-group`;return{[r]:Object.assign(Object.assign({},Qt(e)),{display:"inline-block",fontSize:0,[`&${r}-rtl`]:{direction:"rtl"},[`${n}-badge ${n}-badge-count`]:{zIndex:1},[`> ${n}-badge:not(:first-child) > ${n}-button-wrapper`]:{borderInlineStart:"none"}})}},$z=e=>{const{componentCls:t,wrapperMarginInlineEnd:n,colorPrimary:r,radioSize:o,motionDurationSlow:i,motionDurationMid:a,motionEaseInOutCirc:l,colorBgContainer:s,colorBorder:c,lineWidth:u,colorBgContainerDisabled:d,colorTextDisabled:v,paddingXS:h,dotColorDisabled:g,lineType:p,radioColor:b,radioBgColor:m,calc:y}=e,S=`${t}-inner`,x=4,$=y(o).sub(y(x).mul(2)),E=y(1).mul(o).equal();return{[`${t}-wrapper`]:Object.assign(Object.assign({},Qt(e)),{display:"inline-flex",alignItems:"baseline",marginInlineStart:0,marginInlineEnd:n,cursor:"pointer",[`&${t}-wrapper-rtl`]:{direction:"rtl"},"&-disabled":{cursor:"not-allowed",color:e.colorTextDisabled},"&::after":{display:"inline-block",width:0,overflow:"hidden",content:'"\\a0"'},[`${t}-checked::after`]:{position:"absolute",insetBlockStart:0,insetInlineStart:0,width:"100%",height:"100%",border:`${X(u)} ${p} ${r}`,borderRadius:"50%",visibility:"hidden",content:'""'},[t]:Object.assign(Object.assign({},Qt(e)),{position:"relative",display:"inline-block",outline:"none",cursor:"pointer",alignSelf:"center",borderRadius:"50%"}),[`${t}-wrapper:hover &, + &:hover ${S}`]:{borderColor:r},[`${t}-input:focus-visible + ${S}`]:Object.assign({},Yh(e)),[`${t}:hover::after, ${t}-wrapper:hover &::after`]:{visibility:"visible"},[`${t}-inner`]:{"&::after":{boxSizing:"border-box",position:"absolute",insetBlockStart:"50%",insetInlineStart:"50%",display:"block",width:E,height:E,marginBlockStart:y(1).mul(o).div(-2).equal(),marginInlineStart:y(1).mul(o).div(-2).equal(),backgroundColor:b,borderBlockStart:0,borderInlineStart:0,borderRadius:E,transform:"scale(0)",opacity:0,transition:`all ${i} ${l}`,content:'""'},boxSizing:"border-box",position:"relative",insetBlockStart:0,insetInlineStart:0,display:"block",width:E,height:E,backgroundColor:s,borderColor:c,borderStyle:"solid",borderWidth:u,borderRadius:"50%",transition:`all ${a}`},[`${t}-input`]:{position:"absolute",inset:0,zIndex:1,cursor:"pointer",opacity:0},[`${t}-checked`]:{[S]:{borderColor:r,backgroundColor:m,"&::after":{transform:`scale(${e.calc(e.dotSize).div(o).equal()})`,opacity:1,transition:`all ${i} ${l}`}}},[`${t}-disabled`]:{cursor:"not-allowed",[S]:{backgroundColor:d,borderColor:c,cursor:"not-allowed","&::after":{backgroundColor:g}},[`${t}-input`]:{cursor:"not-allowed"},[`${t}-disabled + span`]:{color:v,cursor:"not-allowed"},[`&${t}-checked`]:{[S]:{"&::after":{transform:`scale(${y($).div(o).equal({unit:!1})})`}}}},[`span${t} + *`]:{paddingInlineStart:h,paddingInlineEnd:h}})}},Ez=e=>{const{buttonColor:t,controlHeight:n,componentCls:r,lineWidth:o,lineType:i,colorBorder:a,motionDurationSlow:l,motionDurationMid:s,buttonPaddingInline:c,fontSize:u,buttonBg:d,fontSizeLG:v,controlHeightLG:h,controlHeightSM:g,paddingXS:p,borderRadius:b,borderRadiusSM:m,borderRadiusLG:y,buttonCheckedBg:S,buttonSolidCheckedColor:x,colorTextDisabled:$,colorBgContainerDisabled:E,buttonCheckedBgDisabled:w,buttonCheckedColorDisabled:R,colorPrimary:P,colorPrimaryHover:N,colorPrimaryActive:I,buttonSolidCheckedBg:z,buttonSolidCheckedHoverBg:F,buttonSolidCheckedActiveBg:T,calc:D}=e;return{[`${r}-button-wrapper`]:{position:"relative",display:"inline-block",height:n,margin:0,paddingInline:c,paddingBlock:0,color:t,fontSize:u,lineHeight:X(D(n).sub(D(o).mul(2)).equal()),background:d,border:`${X(o)} ${i} ${a}`,borderBlockStartWidth:D(o).add(.02).equal(),borderInlineStartWidth:0,borderInlineEndWidth:o,cursor:"pointer",transition:[`color ${s}`,`background ${s}`,`box-shadow ${s}`].join(","),a:{color:t},[`> ${r}-button`]:{position:"absolute",insetBlockStart:0,insetInlineStart:0,zIndex:-1,width:"100%",height:"100%"},"&:not(:first-child)":{"&::before":{position:"absolute",insetBlockStart:D(o).mul(-1).equal(),insetInlineStart:D(o).mul(-1).equal(),display:"block",boxSizing:"content-box",width:1,height:"100%",paddingBlock:o,paddingInline:0,backgroundColor:a,transition:`background-color ${l}`,content:'""'}},"&:first-child":{borderInlineStart:`${X(o)} ${i} ${a}`,borderStartStartRadius:b,borderEndStartRadius:b},"&:last-child":{borderStartEndRadius:b,borderEndEndRadius:b},"&:first-child:last-child":{borderRadius:b},[`${r}-group-large &`]:{height:h,fontSize:v,lineHeight:X(D(h).sub(D(o).mul(2)).equal()),"&:first-child":{borderStartStartRadius:y,borderEndStartRadius:y},"&:last-child":{borderStartEndRadius:y,borderEndEndRadius:y}},[`${r}-group-small &`]:{height:g,paddingInline:D(p).sub(o).equal(),paddingBlock:0,lineHeight:X(D(g).sub(D(o).mul(2)).equal()),"&:first-child":{borderStartStartRadius:m,borderEndStartRadius:m},"&:last-child":{borderStartEndRadius:m,borderEndEndRadius:m}},"&:hover":{position:"relative",color:P},"&:has(:focus-visible)":Object.assign({},Yh(e)),[`${r}-inner, input[type='checkbox'], input[type='radio']`]:{width:0,height:0,opacity:0,pointerEvents:"none"},[`&-checked:not(${r}-button-wrapper-disabled)`]:{zIndex:1,color:P,background:S,borderColor:P,"&::before":{backgroundColor:P},"&:first-child":{borderColor:P},"&:hover":{color:N,borderColor:N,"&::before":{backgroundColor:N}},"&:active":{color:I,borderColor:I,"&::before":{backgroundColor:I}}},[`${r}-group-solid &-checked:not(${r}-button-wrapper-disabled)`]:{color:x,background:z,borderColor:z,"&:hover":{color:x,background:F,borderColor:F},"&:active":{color:x,background:T,borderColor:T}},"&-disabled":{color:$,backgroundColor:E,borderColor:a,cursor:"not-allowed","&:first-child, &:hover":{color:$,backgroundColor:E,borderColor:a}},[`&-disabled${r}-button-wrapper-checked`]:{color:R,backgroundColor:w,borderColor:a,boxShadow:"none"}}}},Mz=e=>{const{wireframe:t,padding:n,marginXS:r,lineWidth:o,fontSizeLG:i,colorText:a,colorBgContainer:l,colorTextDisabled:s,controlItemBgActiveDisabled:c,colorTextLightSolid:u,colorPrimary:d,colorPrimaryHover:v,colorPrimaryActive:h,colorWhite:g}=e,p=4,b=i,m=t?b-p*2:b-(p+o)*2;return{radioSize:b,dotSize:m,dotColorDisabled:s,buttonSolidCheckedColor:u,buttonSolidCheckedBg:d,buttonSolidCheckedHoverBg:v,buttonSolidCheckedActiveBg:h,buttonBg:l,buttonCheckedBg:l,buttonColor:a,buttonCheckedBgDisabled:c,buttonCheckedColorDisabled:s,buttonPaddingInline:n-o,wrapperMarginInlineEnd:r,radioColor:t?d:g,radioBgColor:t?l:d}},Y2=vn("Radio",e=>{const{controlOutline:t,controlOutlineWidth:n}=e,r=`0 0 0 ${X(n)} ${t}`,i=$t(e,{radioFocusShadow:r,radioButtonFocusShadow:r});return[wz(i),$z(i),Ez(i)]},Mz,{unitless:{radioSize:!0,dotSize:!0}});var Oz=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{var n,r;const o=f.exports.useContext(V2),i=f.exports.useContext(U2),{getPrefixCls:a,direction:l,radio:s}=f.exports.useContext(ot),c=f.exports.useRef(null),u=xr(t,c),{isFormItemInput:d}=f.exports.useContext(Jr),v=T=>{var D,_;(D=e.onChange)===null||D===void 0||D.call(e,T),(_=o==null?void 0:o.onChange)===null||_===void 0||_.call(o,T)},{prefixCls:h,className:g,rootClassName:p,children:b,style:m,title:y}=e,S=Oz(e,["prefixCls","className","rootClassName","children","style","title"]),x=a("radio",h),$=((o==null?void 0:o.optionType)||i)==="button",E=$?`${x}-button`:x,w=no(x),[R,P,N]=Y2(x,w),I=Object.assign({},S),z=f.exports.useContext(rl);o&&(I.name=o.name,I.onChange=v,I.checked=e.value===o.value,I.disabled=(n=I.disabled)!==null&&n!==void 0?n:o.disabled),I.disabled=(r=I.disabled)!==null&&r!==void 0?r:z;const F=te(`${E}-wrapper`,{[`${E}-wrapper-checked`]:I.checked,[`${E}-wrapper-disabled`]:I.disabled,[`${E}-wrapper-rtl`]:l==="rtl",[`${E}-wrapper-in-form-item`]:d},s==null?void 0:s.className,g,p,P,N,w);return R(C(Qh,{component:"Radio",disabled:I.disabled,children:ie("label",{className:F,style:Object.assign(Object.assign({},s==null?void 0:s.style),m),onMouseEnter:e.onMouseEnter,onMouseLeave:e.onMouseLeave,title:y,children:[C(xz,{...Object.assign({},I,{className:te(I.className,!$&&Xh),type:"radio",prefixCls:E,ref:u})}),b!==void 0?C("span",{children:b}):null]})}))},Iz=f.exports.forwardRef(Rz),rd=Iz,Pz=f.exports.forwardRef((e,t)=>{const{getPrefixCls:n,direction:r}=f.exports.useContext(ot),[o,i]=kt(e.defaultValue,{value:e.value}),a=T=>{const D=o,_=T.target.value;"value"in e||i(_);const{onChange:O}=e;O&&_!==D&&O(T)},{prefixCls:l,className:s,rootClassName:c,options:u,buttonStyle:d="outline",disabled:v,children:h,size:g,style:p,id:b,onMouseEnter:m,onMouseLeave:y,onFocus:S,onBlur:x}=e,$=n("radio",l),E=`${$}-group`,w=no($),[R,P,N]=Y2($,w);let I=h;u&&u.length>0&&(I=u.map(T=>typeof T=="string"||typeof T=="number"?C(rd,{prefixCls:$,disabled:v,value:T,checked:o===T,children:T},T.toString()):C(rd,{prefixCls:$,disabled:T.disabled||v,value:T.value,checked:o===T.value,title:T.title,style:T.style,id:T.id,required:T.required,children:T.label},`radio-group-value-options-${T.value}`)));const z=So(g),F=te(E,`${E}-${d}`,{[`${E}-${z}`]:z,[`${E}-rtl`]:r==="rtl"},s,c,P,N,w);return R(C("div",{...Object.assign({},Ka(e,{aria:!0,data:!0}),{className:F,style:p,onMouseEnter:m,onMouseLeave:y,onFocus:S,onBlur:x,id:b,ref:t}),children:C(bz,{value:{onChange:a,value:o,disabled:e.disabled,name:e.name,optionType:e.optionType},children:I})}))}),G2=f.exports.memo(Pz);var Tz=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{const{getPrefixCls:n}=f.exports.useContext(ot),{prefixCls:r}=e,o=Tz(e,["prefixCls"]),i=n("radio",r);return C(Sz,{value:"button",children:C(rd,{...Object.assign({prefixCls:i},o,{type:"radio",ref:t})})})},Ig=f.exports.forwardRef(Nz),Om=rd;Om.Button=Ig;Om.Group=G2;Om.__ANT_RADIO=!0;const _z=10,Az=20;function Dz(e){const{fullscreen:t,validRange:n,generateConfig:r,locale:o,prefixCls:i,value:a,onChange:l,divRef:s}=e,c=r.getYear(a||r.getNow());let u=c-_z,d=u+Az;n&&(u=r.getYear(n[0]),d=r.getYear(n[1])+1);const v=o&&o.year==="\u5E74"?"\u5E74":"",h=[];for(let g=u;g{let p=r.setYear(a,g);if(n){const[b,m]=n,y=r.getYear(p),S=r.getMonth(p);y===r.getYear(m)&&S>r.getMonth(m)&&(p=r.setMonth(p,r.getMonth(m))),y===r.getYear(b)&&Ss.current})}function Lz(e){const{prefixCls:t,fullscreen:n,validRange:r,value:o,generateConfig:i,locale:a,onChange:l,divRef:s}=e,c=i.getMonth(o||i.getNow());let u=0,d=11;if(r){const[g,p]=r,b=i.getYear(o);i.getYear(p)===b&&(d=i.getMonth(p)),i.getYear(g)===b&&(u=i.getMonth(g))}const v=a.shortMonths||i.locale.getShortMonths(a.locale),h=[];for(let g=u;g<=d;g+=1)h.push({label:v[g],value:g});return C(r2,{size:n?void 0:"small",className:`${t}-month-select`,value:c,options:h,onChange:g=>{l(i.setMonth(o,g))},getPopupContainer:()=>s.current})}function zz(e){const{prefixCls:t,locale:n,mode:r,fullscreen:o,onModeChange:i}=e;return ie(G2,{onChange:a=>{let{target:{value:l}}=a;i(l)},value:r,size:o?void 0:"small",className:`${t}-mode-switch`,children:[C(Ig,{value:"month",children:n.month}),C(Ig,{value:"year",children:n.year})]})}function Fz(e){const{prefixCls:t,fullscreen:n,mode:r,onChange:o,onModeChange:i}=e,a=f.exports.useRef(null),l=f.exports.useContext(Jr),s=f.exports.useMemo(()=>Object.assign(Object.assign({},l),{isFormItemInput:!1}),[l]),c=Object.assign(Object.assign({},e),{fullscreen:n,divRef:a});return ie("div",{className:`${t}-header`,ref:a,children:[ie(Jr.Provider,{value:s,children:[C(Dz,{...Object.assign({},c,{onChange:u=>{o(u,"year")}})}),r==="month"&&C(Lz,{...Object.assign({},c,{onChange:u=>{o(u,"month")}})})]}),C(zz,{...Object.assign({},c,{onModeChange:i})})]})}function K2(e){return $t(e,{inputAffixPadding:e.paddingXXS})}const q2=e=>{const{controlHeight:t,fontSize:n,lineHeight:r,lineWidth:o,controlHeightSM:i,controlHeightLG:a,fontSizeLG:l,lineHeightLG:s,paddingSM:c,controlPaddingHorizontalSM:u,controlPaddingHorizontal:d,colorFillAlter:v,colorPrimaryHover:h,colorPrimary:g,controlOutlineWidth:p,controlOutline:b,colorErrorOutline:m,colorWarningOutline:y,colorBgContainer:S}=e;return{paddingBlock:Math.max(Math.round((t-n*r)/2*10)/10-o,0),paddingBlockSM:Math.max(Math.round((i-n*r)/2*10)/10-o,0),paddingBlockLG:Math.ceil((a-l*s)/2*10)/10-o,paddingInline:c-o,paddingInlineSM:u-o,paddingInlineLG:d-o,addonBg:v,activeBorderColor:g,hoverBorderColor:h,activeShadow:`0 0 0 ${p}px ${b}`,errorActiveShadow:`0 0 0 ${p}px ${m}`,warningActiveShadow:`0 0 0 ${p}px ${y}`,hoverBg:S,activeBg:S,inputFontSize:n,inputFontSizeLG:l,inputFontSizeSM:n}},kz=e=>({borderColor:e.hoverBorderColor,backgroundColor:e.hoverBg}),Rm=e=>({color:e.colorTextDisabled,backgroundColor:e.colorBgContainerDisabled,borderColor:e.colorBorder,boxShadow:"none",cursor:"not-allowed",opacity:1,"input[disabled]":{cursor:"not-allowed"},"&:hover:not([disabled])":Object.assign({},kz($t(e,{hoverBorderColor:e.colorBorder,hoverBg:e.colorBgContainerDisabled})))}),X2=(e,t)=>({background:e.colorBgContainer,borderWidth:e.lineWidth,borderStyle:e.lineType,borderColor:t.borderColor,"&:hover":{borderColor:t.hoverBorderColor,backgroundColor:e.hoverBg},"&:focus, &:focus-within":{borderColor:t.activeBorderColor,boxShadow:t.activeShadow,outline:0,backgroundColor:e.activeBg}}),Ub=(e,t)=>({[`&${e.componentCls}-status-${t.status}:not(${e.componentCls}-disabled)`]:Object.assign(Object.assign({},X2(e,t)),{[`${e.componentCls}-prefix, ${e.componentCls}-suffix`]:{color:t.affixColor}})}),Q2=(e,t)=>({"&-outlined":Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({},X2(e,{borderColor:e.colorBorder,hoverBorderColor:e.hoverBorderColor,activeBorderColor:e.activeBorderColor,activeShadow:e.activeShadow})),{[`&${e.componentCls}-disabled, &[disabled]`]:Object.assign({},Rm(e))}),Ub(e,{status:"error",borderColor:e.colorError,hoverBorderColor:e.colorErrorBorderHover,activeBorderColor:e.colorError,activeShadow:e.errorActiveShadow,affixColor:e.colorError})),Ub(e,{status:"warning",borderColor:e.colorWarning,hoverBorderColor:e.colorWarningBorderHover,activeBorderColor:e.colorWarning,activeShadow:e.warningActiveShadow,affixColor:e.colorWarning})),t)}),Yb=(e,t)=>({[`&${e.componentCls}-group-wrapper-status-${t.status}`]:{[`${e.componentCls}-group-addon`]:{borderColor:t.addonBorderColor,color:t.addonColor}}}),Bz=e=>({"&-outlined":Object.assign(Object.assign(Object.assign({[`${e.componentCls}-group`]:{"&-addon":{background:e.addonBg,border:`${X(e.lineWidth)} ${e.lineType} ${e.colorBorder}`},"&-addon:first-child":{borderInlineEnd:0},"&-addon:last-child":{borderInlineStart:0}}},Yb(e,{status:"error",addonBorderColor:e.colorError,addonColor:e.colorErrorText})),Yb(e,{status:"warning",addonBorderColor:e.colorWarning,addonColor:e.colorWarningText})),{[`&${e.componentCls}-group-wrapper-disabled`]:{[`${e.componentCls}-group-addon`]:Object.assign({},Rm(e))}})}),Z2=(e,t)=>({"&-borderless":Object.assign({background:"transparent",border:"none","&:focus, &:focus-within":{outline:"none"},[`&${e.componentCls}-disabled, &[disabled]`]:{color:e.colorTextDisabled}},t)}),J2=(e,t)=>({background:t.bg,borderWidth:e.lineWidth,borderStyle:e.lineType,borderColor:"transparent",["input&, & input, textarea&, & textarea"]:{color:t==null?void 0:t.inputColor},"&:hover":{background:t.hoverBg},"&:focus, &:focus-within":{outline:0,borderColor:t.activeBorderColor,backgroundColor:e.activeBg}}),Gb=(e,t)=>({[`&${e.componentCls}-status-${t.status}:not(${e.componentCls}-disabled)`]:Object.assign(Object.assign({},J2(e,t)),{[`${e.componentCls}-prefix, ${e.componentCls}-suffix`]:{color:t.affixColor}})}),e$=(e,t)=>({"&-filled":Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({},J2(e,{bg:e.colorFillTertiary,hoverBg:e.colorFillSecondary,activeBorderColor:e.colorPrimary})),{[`&${e.componentCls}-disabled, &[disabled]`]:Object.assign({},Rm(e))}),Gb(e,{status:"error",bg:e.colorErrorBg,hoverBg:e.colorErrorBgHover,activeBorderColor:e.colorError,inputColor:e.colorErrorText,affixColor:e.colorError})),Gb(e,{status:"warning",bg:e.colorWarningBg,hoverBg:e.colorWarningBgHover,activeBorderColor:e.colorWarning,inputColor:e.colorWarningText,affixColor:e.colorWarning})),t)}),Kb=(e,t)=>({[`&${e.componentCls}-group-wrapper-status-${t.status}`]:{[`${e.componentCls}-group-addon`]:{background:t.addonBg,color:t.addonColor}}}),jz=e=>({"&-filled":Object.assign(Object.assign(Object.assign({[`${e.componentCls}-group`]:{"&-addon":{background:e.colorFillTertiary},[`${e.componentCls}-filled:not(:focus):not(:focus-within)`]:{"&:not(:first-child)":{borderInlineStart:`${X(e.lineWidth)} ${e.lineType} ${e.colorSplit}`},"&:not(:last-child)":{borderInlineEnd:`${X(e.lineWidth)} ${e.lineType} ${e.colorSplit}`}}}},Kb(e,{status:"error",addonBg:e.colorErrorBg,addonColor:e.colorErrorText})),Kb(e,{status:"warning",addonBg:e.colorWarningBg,addonColor:e.colorWarningText})),{[`&${e.componentCls}-group-wrapper-disabled`]:{[`${e.componentCls}-group`]:{"&-addon":{background:e.colorFillTertiary,color:e.colorTextDisabled},"&-addon:first-child":{borderInlineStart:`${X(e.lineWidth)} ${e.lineType} ${e.colorBorder}`,borderTop:`${X(e.lineWidth)} ${e.lineType} ${e.colorBorder}`,borderBottom:`${X(e.lineWidth)} ${e.lineType} ${e.colorBorder}`},"&-addon:last-child":{borderInlineEnd:`${X(e.lineWidth)} ${e.lineType} ${e.colorBorder}`,borderTop:`${X(e.lineWidth)} ${e.lineType} ${e.colorBorder}`,borderBottom:`${X(e.lineWidth)} ${e.lineType} ${e.colorBorder}`}}}})}),t$=e=>({"&::-moz-placeholder":{opacity:1},"&::placeholder":{color:e,userSelect:"none"},"&:placeholder-shown":{textOverflow:"ellipsis"}}),n$=e=>{const{paddingBlockLG:t,lineHeightLG:n,borderRadiusLG:r,paddingInlineLG:o}=e;return{padding:`${X(t)} ${X(o)}`,fontSize:e.inputFontSizeLG,lineHeight:n,borderRadius:r}},r$=e=>({padding:`${X(e.paddingBlockSM)} ${X(e.paddingInlineSM)}`,fontSize:e.inputFontSizeSM,borderRadius:e.borderRadiusSM}),o$=e=>Object.assign(Object.assign({position:"relative",display:"inline-block",width:"100%",minWidth:0,padding:`${X(e.paddingBlock)} ${X(e.paddingInline)}`,color:e.colorText,fontSize:e.inputFontSize,lineHeight:e.lineHeight,borderRadius:e.borderRadius,transition:`all ${e.motionDurationMid}`},t$(e.colorTextPlaceholder)),{"textarea&":{maxWidth:"100%",height:"auto",minHeight:e.controlHeight,lineHeight:e.lineHeight,verticalAlign:"bottom",transition:`all ${e.motionDurationSlow}, height 0s`,resize:"vertical"},"&-lg":Object.assign({},n$(e)),"&-sm":Object.assign({},r$(e)),"&-rtl":{direction:"rtl"},"&-textarea-rtl":{direction:"rtl"}}),Hz=e=>{const{componentCls:t,antCls:n}=e;return{position:"relative",display:"table",width:"100%",borderCollapse:"separate",borderSpacing:0,["&[class*='col-']"]:{paddingInlineEnd:e.paddingXS,"&:last-child":{paddingInlineEnd:0}},[`&-lg ${t}, &-lg > ${t}-group-addon`]:Object.assign({},n$(e)),[`&-sm ${t}, &-sm > ${t}-group-addon`]:Object.assign({},r$(e)),[`&-lg ${n}-select-single ${n}-select-selector`]:{height:e.controlHeightLG},[`&-sm ${n}-select-single ${n}-select-selector`]:{height:e.controlHeightSM},[`> ${t}`]:{display:"table-cell","&:not(:first-child):not(:last-child)":{borderRadius:0}},[`${t}-group`]:{["&-addon, &-wrap"]:{display:"table-cell",width:1,whiteSpace:"nowrap",verticalAlign:"middle","&:not(:first-child):not(:last-child)":{borderRadius:0}},"&-wrap > *":{display:"block !important"},"&-addon":{position:"relative",padding:`0 ${X(e.paddingInline)}`,color:e.colorText,fontWeight:"normal",fontSize:e.inputFontSize,textAlign:"center",borderRadius:e.borderRadius,transition:`all ${e.motionDurationSlow}`,lineHeight:1,[`${n}-select`]:{margin:`${X(e.calc(e.paddingBlock).add(1).mul(-1).equal())} ${X(e.calc(e.paddingInline).mul(-1).equal())}`,[`&${n}-select-single:not(${n}-select-customize-input):not(${n}-pagination-size-changer)`]:{[`${n}-select-selector`]:{backgroundColor:"inherit",border:`${X(e.lineWidth)} ${e.lineType} transparent`,boxShadow:"none"}},"&-open, &-focused":{[`${n}-select-selector`]:{color:e.colorPrimary}}},[`${n}-cascader-picker`]:{margin:`-9px ${X(e.calc(e.paddingInline).mul(-1).equal())}`,backgroundColor:"transparent",[`${n}-cascader-input`]:{textAlign:"start",border:0,boxShadow:"none"}}}},[`${t}`]:{width:"100%",marginBottom:0,textAlign:"inherit","&:focus":{zIndex:1,borderInlineEndWidth:1},"&:hover":{zIndex:1,borderInlineEndWidth:1,[`${t}-search-with-button &`]:{zIndex:0}}},[`> ${t}:first-child, ${t}-group-addon:first-child`]:{borderStartEndRadius:0,borderEndEndRadius:0,[`${n}-select ${n}-select-selector`]:{borderStartEndRadius:0,borderEndEndRadius:0}},[`> ${t}-affix-wrapper`]:{[`&:not(:first-child) ${t}`]:{borderStartStartRadius:0,borderEndStartRadius:0},[`&:not(:last-child) ${t}`]:{borderStartEndRadius:0,borderEndEndRadius:0}},[`> ${t}:last-child, ${t}-group-addon:last-child`]:{borderStartStartRadius:0,borderEndStartRadius:0,[`${n}-select ${n}-select-selector`]:{borderStartStartRadius:0,borderEndStartRadius:0}},[`${t}-affix-wrapper`]:{"&:not(:last-child)":{borderStartEndRadius:0,borderEndEndRadius:0,[`${t}-search &`]:{borderStartStartRadius:e.borderRadius,borderEndStartRadius:e.borderRadius}},[`&:not(:first-child), ${t}-search &:not(:first-child)`]:{borderStartStartRadius:0,borderEndStartRadius:0}},[`&${t}-group-compact`]:Object.assign(Object.assign({display:"block"},Us()),{[`${t}-group-addon, ${t}-group-wrap, > ${t}`]:{"&:not(:first-child):not(:last-child)":{borderInlineEndWidth:e.lineWidth,"&:hover":{zIndex:1},"&:focus":{zIndex:1}}},"& > *":{display:"inline-block",float:"none",verticalAlign:"top",borderRadius:0},[` + & > ${t}-affix-wrapper, + & > ${t}-number-affix-wrapper, + & > ${n}-picker-range + `]:{display:"inline-flex"},"& > *:not(:last-child)":{marginInlineEnd:e.calc(e.lineWidth).mul(-1).equal(),borderInlineEndWidth:e.lineWidth},[`${t}`]:{float:"none"},[`& > ${n}-select > ${n}-select-selector, + & > ${n}-select-auto-complete ${t}, + & > ${n}-cascader-picker ${t}, + & > ${t}-group-wrapper ${t}`]:{borderInlineEndWidth:e.lineWidth,borderRadius:0,"&:hover":{zIndex:1},"&:focus":{zIndex:1}},[`& > ${n}-select-focused`]:{zIndex:1},[`& > ${n}-select > ${n}-select-arrow`]:{zIndex:1},[`& > *:first-child, + & > ${n}-select:first-child > ${n}-select-selector, + & > ${n}-select-auto-complete:first-child ${t}, + & > ${n}-cascader-picker:first-child ${t}`]:{borderStartStartRadius:e.borderRadius,borderEndStartRadius:e.borderRadius},[`& > *:last-child, + & > ${n}-select:last-child > ${n}-select-selector, + & > ${n}-cascader-picker:last-child ${t}, + & > ${n}-cascader-picker-focused:last-child ${t}`]:{borderInlineEndWidth:e.lineWidth,borderStartEndRadius:e.borderRadius,borderEndEndRadius:e.borderRadius},[`& > ${n}-select-auto-complete ${t}`]:{verticalAlign:"top"},[`${t}-group-wrapper + ${t}-group-wrapper`]:{marginInlineStart:e.calc(e.lineWidth).mul(-1).equal(),[`${t}-affix-wrapper`]:{borderRadius:0}},[`${t}-group-wrapper:not(:last-child)`]:{[`&${t}-search > ${t}-group`]:{[`& > ${t}-group-addon > ${t}-search-button`]:{borderRadius:0},[`& > ${t}`]:{borderStartStartRadius:e.borderRadius,borderStartEndRadius:0,borderEndEndRadius:0,borderEndStartRadius:e.borderRadius}}}})}},Wz=e=>{const{componentCls:t,controlHeightSM:n,lineWidth:r,calc:o}=e,i=16,a=o(n).sub(o(r).mul(2)).sub(i).div(2).equal();return{[t]:Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({},Qt(e)),o$(e)),Q2(e)),e$(e)),Z2(e)),{'&[type="color"]':{height:e.controlHeight,[`&${t}-lg`]:{height:e.controlHeightLG},[`&${t}-sm`]:{height:n,paddingTop:a,paddingBottom:a}},'&[type="search"]::-webkit-search-cancel-button, &[type="search"]::-webkit-search-decoration':{"-webkit-appearance":"none"}})}},Vz=e=>{const{componentCls:t}=e;return{[`${t}-clear-icon`]:{margin:0,color:e.colorTextQuaternary,fontSize:e.fontSizeIcon,verticalAlign:-1,cursor:"pointer",transition:`color ${e.motionDurationSlow}`,"&:hover":{color:e.colorTextTertiary},"&:active":{color:e.colorText},"&-hidden":{visibility:"hidden"},"&-has-suffix":{margin:`0 ${X(e.inputAffixPadding)}`}}}},Uz=e=>{const{componentCls:t,inputAffixPadding:n,colorTextDescription:r,motionDurationSlow:o,colorIcon:i,colorIconHover:a,iconCls:l}=e;return{[`${t}-affix-wrapper`]:Object.assign(Object.assign(Object.assign(Object.assign({},o$(e)),{display:"inline-flex",[`&:not(${t}-disabled):hover`]:{zIndex:1,[`${t}-search-with-button &`]:{zIndex:0}},"&-focused, &:focus":{zIndex:1},[`> input${t}`]:{padding:0,fontSize:"inherit",border:"none",borderRadius:0,outline:"none",background:"transparent",color:"inherit","&::-ms-reveal":{display:"none"},"&:focus":{boxShadow:"none !important"}},"&::before":{display:"inline-block",width:0,visibility:"hidden",content:'"\\a0"'},[`${t}`]:{"&-prefix, &-suffix":{display:"flex",flex:"none",alignItems:"center","> *:not(:last-child)":{marginInlineEnd:e.paddingXS}},"&-show-count-suffix":{color:r},"&-show-count-has-suffix":{marginInlineEnd:e.paddingXXS},"&-prefix":{marginInlineEnd:n},"&-suffix":{marginInlineStart:n}}}),Vz(e)),{[`${l}${t}-password-icon`]:{color:i,cursor:"pointer",transition:`all ${o}`,"&:hover":{color:a}}})}},Yz=e=>{const{componentCls:t,borderRadiusLG:n,borderRadiusSM:r}=e;return{[`${t}-group`]:Object.assign(Object.assign(Object.assign({},Qt(e)),Hz(e)),{"&-rtl":{direction:"rtl"},"&-wrapper":Object.assign(Object.assign(Object.assign({display:"inline-block",width:"100%",textAlign:"start",verticalAlign:"top","&-rtl":{direction:"rtl"},"&-lg":{[`${t}-group-addon`]:{borderRadius:n,fontSize:e.inputFontSizeLG}},"&-sm":{[`${t}-group-addon`]:{borderRadius:r}}},Bz(e)),jz(e)),{[`&:not(${t}-compact-first-item):not(${t}-compact-last-item)${t}-compact-item`]:{[`${t}, ${t}-group-addon`]:{borderRadius:0}},[`&:not(${t}-compact-last-item)${t}-compact-first-item`]:{[`${t}, ${t}-group-addon`]:{borderStartEndRadius:0,borderEndEndRadius:0}},[`&:not(${t}-compact-first-item)${t}-compact-last-item`]:{[`${t}, ${t}-group-addon`]:{borderStartStartRadius:0,borderEndStartRadius:0}},[`&:not(${t}-compact-last-item)${t}-compact-item`]:{[`${t}-affix-wrapper`]:{borderStartEndRadius:0,borderEndEndRadius:0}}})})}},Gz=e=>{const{componentCls:t,antCls:n}=e,r=`${t}-search`;return{[r]:{[`${t}`]:{"&:hover, &:focus":{borderColor:e.colorPrimaryHover,[`+ ${t}-group-addon ${r}-button:not(${n}-btn-primary)`]:{borderInlineStartColor:e.colorPrimaryHover}}},[`${t}-affix-wrapper`]:{borderRadius:0},[`${t}-lg`]:{lineHeight:e.calc(e.lineHeightLG).sub(2e-4).equal({unit:!1})},[`> ${t}-group`]:{[`> ${t}-group-addon:last-child`]:{insetInlineStart:-1,padding:0,border:0,[`${r}-button`]:{marginInlineEnd:-1,paddingTop:0,paddingBottom:0,borderStartStartRadius:0,borderStartEndRadius:e.borderRadius,borderEndEndRadius:e.borderRadius,borderEndStartRadius:0,boxShadow:"none"},[`${r}-button:not(${n}-btn-primary)`]:{color:e.colorTextDescription,"&:hover":{color:e.colorPrimaryHover},"&:active":{color:e.colorPrimaryActive},[`&${n}-btn-loading::before`]:{insetInlineStart:0,insetInlineEnd:0,insetBlockStart:0,insetBlockEnd:0}}}},[`${r}-button`]:{height:e.controlHeight,"&:hover, &:focus":{zIndex:1}},[`&-large ${r}-button`]:{height:e.controlHeightLG},[`&-small ${r}-button`]:{height:e.controlHeightSM},"&-rtl":{direction:"rtl"},[`&${t}-compact-item`]:{[`&:not(${t}-compact-last-item)`]:{[`${t}-group-addon`]:{[`${t}-search-button`]:{marginInlineEnd:e.calc(e.lineWidth).mul(-1).equal(),borderRadius:0}}},[`&:not(${t}-compact-first-item)`]:{[`${t},${t}-affix-wrapper`]:{borderRadius:0}},[`> ${t}-group-addon ${t}-search-button, + > ${t}, + ${t}-affix-wrapper`]:{"&:hover,&:focus,&:active":{zIndex:2}},[`> ${t}-affix-wrapper-focused`]:{zIndex:2}}}}},Kz=e=>{const{componentCls:t,paddingLG:n}=e,r=`${t}-textarea`;return{[r]:{position:"relative","&-show-count":{[`> ${t}`]:{height:"100%"},[`${t}-data-count`]:{position:"absolute",bottom:e.calc(e.fontSize).mul(e.lineHeight).mul(-1).equal(),insetInlineEnd:0,color:e.colorTextDescription,whiteSpace:"nowrap",pointerEvents:"none"}},"&-allow-clear":{[`> ${t}`]:{paddingInlineEnd:n}},[`&-affix-wrapper${r}-has-feedback`]:{[`${t}`]:{paddingInlineEnd:n}},[`&-affix-wrapper${t}-affix-wrapper`]:{padding:0,[`> textarea${t}`]:{fontSize:"inherit",border:"none",outline:"none",background:"transparent","&:focus":{boxShadow:"none !important"}},[`${t}-suffix`]:{margin:0,"> *:not(:last-child)":{marginInline:0},[`${t}-clear-icon`]:{position:"absolute",insetInlineEnd:e.paddingXS,insetBlockStart:e.paddingXS},[`${r}-suffix`]:{position:"absolute",top:0,insetInlineEnd:e.paddingInline,bottom:0,zIndex:1,display:"inline-flex",alignItems:"center",margin:"auto",pointerEvents:"none"}}}}}},qz=e=>{const{componentCls:t}=e;return{[`${t}-out-of-range`]:{[`&, & input, & textarea, ${t}-show-count-suffix, ${t}-data-count`]:{color:e.colorError}}}},Im=vn("Input",e=>{const t=$t(e,K2(e));return[Wz(t),Kz(t),Uz(t),Yz(t),Gz(t),qz(t),tf(t)]},q2),bv=(e,t)=>{const{componentCls:n,selectHeight:r,fontHeight:o,lineWidth:i,calc:a}=e,l=t?`${n}-${t}`:"",s=e.calc(o).add(2).equal(),c=()=>a(r).sub(s).sub(a(i).mul(2)),u=e.max(c().div(2).equal(),0),d=e.max(c().sub(u).equal(),0);return[pm(e,t),{[`${n}-multiple${l}`]:{paddingTop:u,paddingBottom:d,paddingInlineStart:u}}]},Xz=e=>{const{componentCls:t,calc:n,lineWidth:r}=e,o=$t(e,{fontHeight:e.fontSize,selectHeight:e.controlHeightSM,multipleSelectItemHeight:e.controlHeightXS,borderRadius:e.borderRadiusSM,borderRadiusSM:e.borderRadiusXS}),i=$t(e,{fontHeight:n(e.multipleItemHeightLG).sub(n(r).mul(2).equal()).equal(),fontSize:e.fontSizeLG,selectHeight:e.controlHeightLG,multipleSelectItemHeight:e.multipleItemHeightLG,borderRadius:e.borderRadiusLG,borderRadiusSM:e.borderRadius});return[bv(o,"small"),bv(e),bv(i,"large"),pm(e),{[`${t}${t}-multiple`]:{width:"100%",[`${t}-selector`]:{flex:"auto",padding:0,"&:after":{margin:0}},[`${t}-selection-item`]:{marginBlock:0},[`${t}-multiple-input`]:{width:0,height:0,border:0,visibility:"hidden",position:"absolute",zIndex:-1}}}]},Qz=Xz,Zz=e=>{const{pickerCellCls:t,pickerCellInnerCls:n,cellHeight:r,borderRadiusSM:o,motionDurationMid:i,cellHoverBg:a,lineWidth:l,lineType:s,colorPrimary:c,cellActiveWithRangeBg:u,colorTextLightSolid:d,colorTextDisabled:v,cellBgDisabled:h,colorFillSecondary:g}=e;return{"&::before":{position:"absolute",top:"50%",insetInlineStart:0,insetInlineEnd:0,zIndex:1,height:r,transform:"translateY(-50%)",content:'""'},[n]:{position:"relative",zIndex:2,display:"inline-block",minWidth:r,height:r,lineHeight:X(r),borderRadius:o,transition:`background ${i}`},[`&:hover:not(${t}-in-view), + &:hover:not(${t}-selected):not(${t}-range-start):not(${t}-range-end)`]:{[n]:{background:a}},[`&-in-view${t}-today ${n}`]:{"&::before":{position:"absolute",top:0,insetInlineEnd:0,bottom:0,insetInlineStart:0,zIndex:1,border:`${X(l)} ${s} ${c}`,borderRadius:o,content:'""'}},[`&-in-view${t}-in-range, + &-in-view${t}-range-start, + &-in-view${t}-range-end`]:{position:"relative",[`&:not(${t}-disabled):before`]:{background:u}},[`&-in-view${t}-selected, + &-in-view${t}-range-start, + &-in-view${t}-range-end`]:{[`&:not(${t}-disabled) ${n}`]:{color:d,background:c},[`&${t}-disabled ${n}`]:{background:g}},[`&-in-view${t}-range-start:not(${t}-disabled):before`]:{insetInlineStart:"50%"},[`&-in-view${t}-range-end:not(${t}-disabled):before`]:{insetInlineEnd:"50%"},[`&-in-view${t}-range-start:not(${t}-range-end) ${n}`]:{borderStartStartRadius:o,borderEndStartRadius:o,borderStartEndRadius:0,borderEndEndRadius:0},[`&-in-view${t}-range-end:not(${t}-range-start) ${n}`]:{borderStartStartRadius:0,borderEndStartRadius:0,borderStartEndRadius:o,borderEndEndRadius:o},"&-disabled":{color:v,pointerEvents:"none",[n]:{background:"transparent"},"&::before":{background:h}},[`&-disabled${t}-today ${n}::before`]:{borderColor:v}}},i$=e=>{const{componentCls:t,pickerCellCls:n,pickerCellInnerCls:r,pickerYearMonthCellWidth:o,pickerControlIconSize:i,cellWidth:a,paddingSM:l,paddingXS:s,paddingXXS:c,colorBgContainer:u,lineWidth:d,lineType:v,borderRadiusLG:h,colorPrimary:g,colorTextHeading:p,colorSplit:b,pickerControlIconBorderWidth:m,colorIcon:y,textHeight:S,motionDurationMid:x,colorIconHover:$,fontWeightStrong:E,cellHeight:w,pickerCellPaddingVertical:R,colorTextDisabled:P,colorText:N,fontSize:I,motionDurationSlow:z,withoutTimeCellHeight:F,pickerQuarterPanelContentHeight:T,borderRadiusSM:D,colorTextLightSolid:_,cellHoverBg:O,timeColumnHeight:M,timeColumnWidth:L,timeCellHeight:A,controlItemBgActive:B,marginXXS:k,pickerDatePanelPaddingHorizontal:j,pickerControlIconMargin:H}=e,W=e.calc(a).mul(7).add(e.calc(j).mul(2)).equal();return{[t]:{"&-panel":{display:"inline-flex",flexDirection:"column",textAlign:"center",background:u,borderRadius:h,outline:"none","&-focused":{borderColor:g},"&-rtl":{direction:"rtl",[`${t}-prev-icon, + ${t}-super-prev-icon`]:{transform:"rotate(45deg)"},[`${t}-next-icon, + ${t}-super-next-icon`]:{transform:"rotate(-135deg)"}}},[`&-decade-panel, + &-year-panel, + &-quarter-panel, + &-month-panel, + &-week-panel, + &-date-panel, + &-time-panel`]:{display:"flex",flexDirection:"column",width:W},"&-header":{display:"flex",padding:`0 ${X(s)}`,color:p,borderBottom:`${X(d)} ${v} ${b}`,"> *":{flex:"none"},button:{padding:0,color:y,lineHeight:X(S),background:"transparent",border:0,cursor:"pointer",transition:`color ${x}`,fontSize:"inherit"},"> button":{minWidth:"1.6em",fontSize:I,"&:hover":{color:$},"&:disabled":{opacity:.25,pointerEvents:"none"}},"&-view":{flex:"auto",fontWeight:E,lineHeight:X(S),button:{color:"inherit",fontWeight:"inherit",verticalAlign:"top","&:not(:first-child)":{marginInlineStart:s},"&:hover":{color:g}}}},[`&-prev-icon, + &-next-icon, + &-super-prev-icon, + &-super-next-icon`]:{position:"relative",display:"inline-block",width:i,height:i,"&::before":{position:"absolute",top:0,insetInlineStart:0,display:"inline-block",width:i,height:i,border:"0 solid currentcolor",borderBlockStartWidth:m,borderBlockEndWidth:0,borderInlineStartWidth:m,borderInlineEndWidth:0,content:'""'}},[`&-super-prev-icon, + &-super-next-icon`]:{"&::after":{position:"absolute",top:H,insetInlineStart:H,display:"inline-block",width:i,height:i,border:"0 solid currentcolor",borderBlockStartWidth:m,borderBlockEndWidth:0,borderInlineStartWidth:m,borderInlineEndWidth:0,content:'""'}},[`&-prev-icon, + &-super-prev-icon`]:{transform:"rotate(-45deg)"},[`&-next-icon, + &-super-next-icon`]:{transform:"rotate(135deg)"},"&-content":{width:"100%",tableLayout:"fixed",borderCollapse:"collapse","th, td":{position:"relative",minWidth:w,fontWeight:"normal"},th:{height:e.calc(w).add(e.calc(R).mul(2)).equal(),color:N,verticalAlign:"middle"}},"&-cell":Object.assign({padding:`${X(R)} 0`,color:P,cursor:"pointer","&-in-view":{color:N}},Zz(e)),[`&-decade-panel, + &-year-panel, + &-quarter-panel, + &-month-panel`]:{[`${t}-content`]:{height:e.calc(F).mul(4).equal()},[r]:{padding:`0 ${X(s)}`}},"&-quarter-panel":{[`${t}-content`]:{height:T}},"&-decade-panel":{[r]:{padding:`0 ${X(e.calc(s).div(2).equal())}`},[`${t}-cell::before`]:{display:"none"}},[`&-year-panel, + &-quarter-panel, + &-month-panel`]:{[`${t}-body`]:{padding:`0 ${X(s)}`},[r]:{width:o}},"&-date-panel":{[`${t}-body`]:{padding:`${X(s)} ${X(j)}`},[`${t}-content th`]:{boxSizing:"border-box",padding:0}},"&-week-panel":{[`${t}-cell`]:{[`&:hover ${r}, + &-selected ${r}, + ${r}`]:{background:"transparent !important"}},"&-row":{td:{"&:before":{transition:`background ${x}`},"&:first-child:before":{borderStartStartRadius:D,borderEndStartRadius:D},"&:last-child:before":{borderStartEndRadius:D,borderEndEndRadius:D}},["&:hover td"]:{"&:before":{background:O}},[`&-range-start td, + &-range-end td, + &-selected td`]:{[`&${n}`]:{"&:before":{background:g},[`&${t}-cell-week`]:{color:new Mt(_).setAlpha(.5).toHexString()},[r]:{color:_}}},["&-range-hover td:before"]:{background:B}}},["&-week-panel, &-date-panel-show-week"]:{[`${t}-body`]:{padding:`${X(s)} ${X(l)}`},[`${t}-content th`]:{width:"auto"}},"&-datetime-panel":{display:"flex",[`${t}-time-panel`]:{borderInlineStart:`${X(d)} ${v} ${b}`},[`${t}-date-panel, + ${t}-time-panel`]:{transition:`opacity ${z}`},"&-active":{[`${t}-date-panel, + ${t}-time-panel`]:{opacity:.3,"&-active":{opacity:1}}}},"&-time-panel":{width:"auto",minWidth:"auto",direction:"ltr",[`${t}-content`]:{display:"flex",flex:"auto",height:M},"&-column":{flex:"1 0 auto",width:L,margin:`${X(c)} 0`,padding:0,overflowY:"hidden",textAlign:"start",listStyle:"none",transition:`background ${x}`,overflowX:"hidden","&::-webkit-scrollbar":{width:8,backgroundColor:"transparent"},"&::-webkit-scrollbar-thumb":{backgroundColor:e.colorTextTertiary,borderRadius:4},"&":{scrollbarWidth:"thin",scrollbarColor:`${e.colorTextTertiary} transparent`},"&::after":{display:"block",height:e.calc("100%").sub(A).equal(),content:'""'},"&:not(:first-child)":{borderInlineStart:`${X(d)} ${v} ${b}`},"&-active":{background:new Mt(B).setAlpha(.2).toHexString()},"&:hover":{overflowY:"auto"},"> li":{margin:0,padding:0,[`&${t}-time-panel-cell`]:{marginInline:k,[`${t}-time-panel-cell-inner`]:{display:"block",width:e.calc(L).sub(e.calc(k).mul(2)).equal(),height:A,margin:0,paddingBlock:0,paddingInlineEnd:0,paddingInlineStart:e.calc(L).sub(A).div(2).equal(),color:N,lineHeight:X(A),borderRadius:D,cursor:"pointer",transition:`background ${x}`,"&:hover":{background:O}},"&-selected":{[`${t}-time-panel-cell-inner`]:{background:B}},"&-disabled":{[`${t}-time-panel-cell-inner`]:{color:P,background:"transparent",cursor:"not-allowed"}}}}}}}}},Jz=e=>{const{componentCls:t,textHeight:n,lineWidth:r,paddingSM:o,antCls:i,colorPrimary:a,cellActiveWithRangeBg:l,colorPrimaryBorder:s,lineType:c,colorSplit:u}=e;return{[`${t}-dropdown`]:{[`${t}-footer`]:{borderTop:`${X(r)} ${c} ${u}`,"&-extra":{padding:`0 ${X(o)}`,lineHeight:X(e.calc(n).sub(e.calc(r).mul(2)).equal()),textAlign:"start","&:not(:last-child)":{borderBottom:`${X(r)} ${c} ${u}`}}},[`${t}-panels + ${t}-footer ${t}-ranges`]:{justifyContent:"space-between"},[`${t}-ranges`]:{marginBlock:0,paddingInline:X(o),overflow:"hidden",textAlign:"start",listStyle:"none",display:"flex",justifyContent:"center",alignItems:"center","> li":{lineHeight:X(e.calc(n).sub(e.calc(r).mul(2)).equal()),display:"inline-block"},[`${t}-now-btn-disabled`]:{pointerEvents:"none",color:e.colorTextDisabled},[`${t}-preset > ${i}-tag-blue`]:{color:a,background:l,borderColor:s,cursor:"pointer"},[`${t}-ok`]:{paddingBlock:e.calc(r).mul(2).equal(),marginInlineStart:"auto"}}}}},eF=Jz,a$=e=>{const{componentCls:t,controlHeightLG:n,paddingXXS:r,padding:o}=e;return{pickerCellCls:`${t}-cell`,pickerCellInnerCls:`${t}-cell-inner`,pickerYearMonthCellWidth:e.calc(n).mul(1.5).equal(),pickerQuarterPanelContentHeight:e.calc(n).mul(1.4).equal(),pickerCellPaddingVertical:e.calc(r).add(e.calc(r).div(2)).equal(),pickerCellBorderGap:2,pickerControlIconSize:7,pickerControlIconMargin:4,pickerControlIconBorderWidth:1.5,pickerDatePanelPaddingHorizontal:e.calc(o).add(e.calc(r).div(2)).equal()}},l$=e=>{const{colorBgContainerDisabled:t,controlHeightSM:n,controlHeightLG:r}=e;return{cellHoverBg:e.controlItemBgHover,cellActiveWithRangeBg:e.controlItemBgActive,cellHoverWithRangeBg:new Mt(e.colorPrimary).lighten(35).toHexString(),cellRangeBorderColor:new Mt(e.colorPrimary).lighten(20).toHexString(),cellBgDisabled:t,timeColumnWidth:r*1.4,timeColumnHeight:28*8,timeCellHeight:28,cellWidth:n*1.5,cellHeight:n,textHeight:r,withoutTimeCellHeight:r*1.65,multipleItemBg:e.colorFillSecondary,multipleItemBorderColor:"transparent",multipleItemHeight:n,multipleItemHeightLG:e.controlHeight,multipleSelectorBgDisabled:t,multipleItemColorDisabled:e.colorTextDisabled,multipleItemBorderColorDisabled:"transparent"}},tF=e=>Object.assign(Object.assign(Object.assign(Object.assign({},q2(e)),l$(e)),hm(e)),{presetsWidth:120,presetsMaxWidth:200,zIndexPopup:e.zIndexPopupBase+50}),nF=e=>{const{componentCls:t}=e;return{[t]:[Object.assign(Object.assign(Object.assign({},Q2(e)),e$(e)),Z2(e)),{"&-outlined":{[`&${t}-multiple ${t}-selection-item`]:{background:e.multipleItemBg,border:`${X(e.lineWidth)} ${e.lineType} ${e.multipleItemBorderColor}`}},"&-filled":{[`&${t}-multiple ${t}-selection-item`]:{background:e.colorBgContainer,border:`${X(e.lineWidth)} ${e.lineType} ${e.colorSplit}`}},"&-borderless":{[`&${t}-multiple ${t}-selection-item`]:{background:e.multipleItemBg,border:`${X(e.lineWidth)} ${e.lineType} ${e.multipleItemBorderColor}`}}}]}},rF=nF,Sv=(e,t,n,r)=>{const o=e.calc(n).add(2).equal(),i=e.max(e.calc(t).sub(o).div(2).equal(),0),a=e.max(e.calc(t).sub(o).sub(i).equal(),0);return{padding:`${X(i)} ${X(r)} ${X(a)}`}},oF=e=>{const{componentCls:t,colorError:n,colorWarning:r}=e;return{[`${t}:not(${t}-disabled):not([disabled])`]:{[`&${t}-status-error`]:{[`${t}-active-bar`]:{background:n}},[`&${t}-status-warning`]:{[`${t}-active-bar`]:{background:r}}}}},iF=e=>{const{componentCls:t,antCls:n,controlHeight:r,paddingInline:o,lineWidth:i,lineType:a,colorBorder:l,borderRadius:s,motionDurationMid:c,colorTextDisabled:u,colorTextPlaceholder:d,controlHeightLG:v,fontSizeLG:h,controlHeightSM:g,paddingInlineSM:p,paddingXS:b,marginXS:m,colorTextDescription:y,lineWidthBold:S,colorPrimary:x,motionDurationSlow:$,zIndexPopup:E,paddingXXS:w,sizePopupArrow:R,colorBgElevated:P,borderRadiusLG:N,boxShadowSecondary:I,borderRadiusSM:z,colorSplit:F,cellHoverBg:T,presetsWidth:D,presetsMaxWidth:_,boxShadowPopoverArrow:O,fontHeight:M,fontHeightLG:L,lineHeightLG:A}=e;return[{[t]:Object.assign(Object.assign(Object.assign({},Qt(e)),Sv(e,r,M,o)),{position:"relative",display:"inline-flex",alignItems:"center",lineHeight:1,borderRadius:s,transition:`border ${c}, box-shadow ${c}, background ${c}`,[`${t}-input`]:{position:"relative",display:"inline-flex",alignItems:"center",width:"100%","> input":Object.assign(Object.assign({position:"relative",display:"inline-block",width:"100%",color:"inherit",fontSize:e.fontSize,lineHeight:e.lineHeight,transition:`all ${c}`},t$(d)),{flex:"auto",minWidth:1,height:"auto",padding:0,background:"transparent",border:0,fontFamily:"inherit","&:focus":{boxShadow:"none",outline:0},"&[disabled]":{background:"transparent",color:u,cursor:"not-allowed"}}),"&-placeholder":{"> input":{color:d}}},"&-large":Object.assign(Object.assign({},Sv(e,v,L,o)),{[`${t}-input > input`]:{fontSize:h,lineHeight:A}}),"&-small":Object.assign({},Sv(e,g,M,p)),[`${t}-suffix`]:{display:"flex",flex:"none",alignSelf:"center",marginInlineStart:e.calc(b).div(2).equal(),color:u,lineHeight:1,pointerEvents:"none",transition:`opacity ${c}, color ${c}`,"> *":{verticalAlign:"top","&:not(:last-child)":{marginInlineEnd:m}}},[`${t}-clear`]:{position:"absolute",top:"50%",insetInlineEnd:0,color:u,lineHeight:1,transform:"translateY(-50%)",cursor:"pointer",opacity:0,transition:`opacity ${c}, color ${c}`,"> *":{verticalAlign:"top"},"&:hover":{color:y}},"&:hover":{[`${t}-clear`]:{opacity:1},[`${t}-suffix:not(:last-child)`]:{opacity:0}},[`${t}-separator`]:{position:"relative",display:"inline-block",width:"1em",height:h,color:u,fontSize:h,verticalAlign:"top",cursor:"default",[`${t}-focused &`]:{color:y},[`${t}-range-separator &`]:{[`${t}-disabled &`]:{cursor:"not-allowed"}}},"&-range":{position:"relative",display:"inline-flex",[`${t}-active-bar`]:{bottom:e.calc(i).mul(-1).equal(),height:S,background:x,opacity:0,transition:`all ${$} ease-out`,pointerEvents:"none"},[`&${t}-focused`]:{[`${t}-active-bar`]:{opacity:1}},[`${t}-range-separator`]:{alignItems:"center",padding:`0 ${X(b)}`,lineHeight:1}},"&-range, &-multiple":{[`${t}-clear`]:{insetInlineEnd:o},[`&${t}-small`]:{[`${t}-clear`]:{insetInlineEnd:p}}},"&-dropdown":Object.assign(Object.assign(Object.assign({},Qt(e)),i$(e)),{pointerEvents:"none",position:"absolute",top:-9999,left:{_skip_check_:!0,value:-9999},zIndex:E,[`&${t}-dropdown-hidden`]:{display:"none"},[`&${t}-dropdown-placement-bottomLeft`]:{[`${t}-range-arrow`]:{top:0,display:"block",transform:"translateY(-100%)"}},[`&${t}-dropdown-placement-topLeft`]:{[`${t}-range-arrow`]:{bottom:0,display:"block",transform:"translateY(100%) rotate(180deg)"}},[`&${n}-slide-up-enter${n}-slide-up-enter-active${t}-dropdown-placement-topLeft, + &${n}-slide-up-enter${n}-slide-up-enter-active${t}-dropdown-placement-topRight, + &${n}-slide-up-appear${n}-slide-up-appear-active${t}-dropdown-placement-topLeft, + &${n}-slide-up-appear${n}-slide-up-appear-active${t}-dropdown-placement-topRight`]:{animationName:om},[`&${n}-slide-up-enter${n}-slide-up-enter-active${t}-dropdown-placement-bottomLeft, + &${n}-slide-up-enter${n}-slide-up-enter-active${t}-dropdown-placement-bottomRight, + &${n}-slide-up-appear${n}-slide-up-appear-active${t}-dropdown-placement-bottomLeft, + &${n}-slide-up-appear${n}-slide-up-appear-active${t}-dropdown-placement-bottomRight`]:{animationName:nm},[`&${n}-slide-up-leave${n}-slide-up-leave-active${t}-dropdown-placement-topLeft, + &${n}-slide-up-leave${n}-slide-up-leave-active${t}-dropdown-placement-topRight`]:{animationName:im},[`&${n}-slide-up-leave${n}-slide-up-leave-active${t}-dropdown-placement-bottomLeft, + &${n}-slide-up-leave${n}-slide-up-leave-active${t}-dropdown-placement-bottomRight`]:{animationName:rm},[`${t}-panel > ${t}-time-panel`]:{paddingTop:w},[`${t}-range-wrapper`]:{display:"flex",position:"relative"},[`${t}-range-arrow`]:Object.assign(Object.assign({position:"absolute",zIndex:1,display:"none",paddingInline:e.calc(o).mul(1.5).equal(),boxSizing:"content-box",transition:`left ${$} ease-out`},l2(e,P,O)),{"&:before":{insetInlineStart:e.calc(o).mul(1.5).equal()}}),[`${t}-panel-container`]:{overflow:"hidden",verticalAlign:"top",background:P,borderRadius:N,boxShadow:I,transition:`margin ${$}`,display:"inline-block",pointerEvents:"auto",[`${t}-panel-layout`]:{display:"flex",flexWrap:"nowrap",alignItems:"stretch"},[`${t}-presets`]:{display:"flex",flexDirection:"column",minWidth:D,maxWidth:_,ul:{height:0,flex:"auto",listStyle:"none",overflow:"auto",margin:0,padding:b,borderInlineEnd:`${X(i)} ${a} ${F}`,li:Object.assign(Object.assign({},ei),{borderRadius:z,paddingInline:b,paddingBlock:e.calc(g).sub(M).div(2).equal(),cursor:"pointer",transition:`all ${$}`,"+ li":{marginTop:m},"&:hover":{background:T}})}},[`${t}-panels`]:{display:"inline-flex",flexWrap:"nowrap",direction:"ltr","&:last-child":{[`${t}-panel`]:{borderWidth:0}}},[`${t}-panel`]:{verticalAlign:"top",background:"transparent",borderRadius:0,borderWidth:0,[`${t}-content, + table`]:{textAlign:"center"},"&-focused":{borderColor:l}}}}),"&-dropdown-range":{padding:`${X(e.calc(R).mul(2).div(3).equal())} 0`,"&-hidden":{display:"none"}},"&-rtl":{direction:"rtl",[`${t}-separator`]:{transform:"rotate(180deg)"},[`${t}-footer`]:{"&-extra":{direction:"rtl"}}}})},Xa(e,"slide-up"),Xa(e,"slide-down"),Zu(e,"move-up"),Zu(e,"move-down")]};vn("DatePicker",e=>{const t=$t(K2(e),a$(e),{inputPaddingHorizontalBase:e.calc(e.paddingSM).sub(1).equal(),multipleSelectItemHeight:e.multipleItemHeight,selectHeight:e.controlHeight});return[eF(t),iF(t),rF(t),oF(t),Qz(t),tf(e,{focusElCls:`${e.componentCls}-focused`})]},tF);const aF=e=>{const{calendarCls:t,componentCls:n,fullBg:r,fullPanelBg:o,itemActiveBg:i}=e;return{[t]:Object.assign(Object.assign(Object.assign({},i$(e)),Qt(e)),{background:r,"&-rtl":{direction:"rtl"},[`${t}-header`]:{display:"flex",justifyContent:"flex-end",padding:`${X(e.paddingSM)} 0`,[`${t}-year-select`]:{minWidth:e.yearControlWidth},[`${t}-month-select`]:{minWidth:e.monthControlWidth,marginInlineStart:e.marginXS},[`${t}-mode-switch`]:{marginInlineStart:e.marginXS}}}),[`${t} ${n}-panel`]:{background:o,border:0,borderTop:`${X(e.lineWidth)} ${e.lineType} ${e.colorSplit}`,borderRadius:0,[`${n}-month-panel, ${n}-date-panel`]:{width:"auto"},[`${n}-body`]:{padding:`${X(e.paddingXS)} 0`},[`${n}-content`]:{width:"100%"}},[`${t}-mini`]:{borderRadius:e.borderRadiusLG,[`${t}-header`]:{paddingInlineEnd:e.paddingXS,paddingInlineStart:e.paddingXS},[`${n}-panel`]:{borderRadius:`0 0 ${X(e.borderRadiusLG)} ${X(e.borderRadiusLG)}`},[`${n}-content`]:{height:e.miniContentHeight,th:{height:"auto",padding:0,lineHeight:`${X(e.weekHeight)}`}},[`${n}-cell::before`]:{pointerEvents:"none"}},[`${t}${t}-full`]:{[`${n}-panel`]:{display:"block",width:"100%",textAlign:"end",background:r,border:0,[`${n}-body`]:{"th, td":{padding:0},th:{height:"auto",paddingInlineEnd:e.paddingSM,paddingBottom:e.paddingXXS,lineHeight:`${X(e.weekHeight)}`}}},[`${n}-cell`]:{"&::before":{display:"none"},"&:hover":{[`${t}-date`]:{background:e.controlItemBgHover}},[`${t}-date-today::before`]:{display:"none"},[`&-in-view${n}-cell-selected`]:{[`${t}-date, ${t}-date-today`]:{background:i}},"&-selected, &-selected:hover":{[`${t}-date, ${t}-date-today`]:{[`${t}-date-value`]:{color:e.colorPrimary}}}},[`${t}-date`]:{display:"block",width:"auto",height:"auto",margin:`0 ${X(e.calc(e.marginXS).div(2).equal())}`,padding:`${X(e.calc(e.paddingXS).div(2).equal())} ${X(e.paddingXS)} 0`,border:0,borderTop:`${X(e.lineWidthBold)} ${e.lineType} ${e.colorSplit}`,borderRadius:0,transition:`background ${e.motionDurationSlow}`,"&-value":{lineHeight:`${X(e.dateValueHeight)}`,transition:`color ${e.motionDurationSlow}`},"&-content":{position:"static",width:"auto",height:e.dateContentHeight,overflowY:"auto",color:e.colorText,lineHeight:e.lineHeight,textAlign:"start"},"&-today":{borderColor:e.colorPrimary,[`${t}-date-value`]:{color:e.colorText}}}},[`@media only screen and (max-width: ${X(e.screenXS)}) `]:{[`${t}`]:{[`${t}-header`]:{display:"block",[`${t}-year-select`]:{width:"50%"},[`${t}-month-select`]:{width:`calc(50% - ${X(e.paddingXS)})`},[`${t}-mode-switch`]:{width:"100%",marginTop:e.marginXS,marginInlineStart:0,"> label":{width:"50%",textAlign:"center"}}}}}}},lF=e=>Object.assign({fullBg:e.colorBgContainer,fullPanelBg:e.colorBgContainer,itemActiveBg:e.controlItemBgActive,yearControlWidth:80,monthControlWidth:70,miniContentHeight:256},l$(e)),sF=vn("Calendar",e=>{const t=`${e.componentCls}-calendar`,n=$t(e,a$(e),{calendarCls:t,pickerCellInnerCls:`${e.componentCls}-cell-inner`,dateValueHeight:e.controlHeightSM,weekHeight:e.calc(e.controlHeightSM).mul(.75).equal(),dateContentHeight:e.calc(e.calc(e.fontHeightSM).add(e.marginXS)).mul(3).add(e.calc(e.lineWidth).mul(2)).equal()});return[aF(n)]},lF);function s$(e){function t(i,a){return i&&a&&e.getYear(i)===e.getYear(a)}function n(i,a){return t(i,a)&&e.getMonth(i)===e.getMonth(a)}function r(i,a){return n(i,a)&&e.getDate(i)===e.getDate(a)}return i=>{const{prefixCls:a,className:l,rootClassName:s,style:c,dateFullCellRender:u,dateCellRender:d,monthFullCellRender:v,monthCellRender:h,cellRender:g,fullCellRender:p,headerRender:b,value:m,defaultValue:y,disabledDate:S,mode:x,validRange:$,fullscreen:E=!0,onChange:w,onPanelChange:R,onSelect:P}=i,{getPrefixCls:N,direction:I,calendar:z}=f.exports.useContext(ot),F=N("picker",a),T=`${F}-calendar`,[D,_,O]=sF(F,T),M=e.getNow(),[L,A]=kt(()=>m||e.getNow(),{defaultValue:y,value:m}),[B,k]=kt("month",{value:x}),j=f.exports.useMemo(()=>B==="year"?"month":"date",[B]),H=f.exports.useCallback(J=>($?e.isAfter($[0],J)||e.isAfter(J,$[1]):!1)||!!(S!=null&&S(J)),[S,$]),W=(J,re)=>{R==null||R(J,re)},Y=J=>{A(J),r(J,L)||((j==="date"&&!n(J,L)||j==="month"&&!t(J,L))&&W(J,B),w==null||w(J))},K=J=>{k(J),W(L,J)},q=(J,re)=>{Y(J),P==null||P(J,{source:re})},ee=()=>{const{locale:J}=i,re=Object.assign(Object.assign({},Kp),J);return re.lang=Object.assign(Object.assign({},re.lang),(J||{}).lang),re},Z=f.exports.useCallback((J,re)=>p?p(J,re):u?u(J):ie("div",{className:te(`${F}-cell-inner`,`${T}-date`,{[`${T}-date-today`]:r(M,J)}),children:[C("div",{className:`${T}-date-value`,children:String(e.getDate(J)).padStart(2,"0")}),C("div",{className:`${T}-date-content`,children:g?g(J,re):d&&d(J)})]}),[u,d,g,p]),Q=f.exports.useCallback((J,re)=>{if(p)return p(J,re);if(v)return v(J);const fe=re.locale.shortMonths||e.locale.getShortMonths(re.locale.locale);return ie("div",{className:te(`${F}-cell-inner`,`${T}-date`,{[`${T}-date-today`]:n(M,J)}),children:[C("div",{className:`${T}-date-value`,children:fe[e.getMonth(J)]}),C("div",{className:`${T}-date-content`,children:g?g(J,re):h&&h(J)})]})},[v,h,g,p]),[ne]=Wx("Calendar",ee),ae=(J,re)=>{if(re.type==="date")return Z(J,re);if(re.type==="month")return Q(J,Object.assign(Object.assign({},re),{locale:ne==null?void 0:ne.lang}))};return D(ie("div",{className:te(T,{[`${T}-full`]:E,[`${T}-mini`]:!E,[`${T}-rtl`]:I==="rtl"},z==null?void 0:z.className,l,s,_,O),style:Object.assign(Object.assign({},z==null?void 0:z.style),c),children:[b?b({value:L,type:B,onChange:J=>{q(J,"customize")},onTypeChange:K}):C(Fz,{prefixCls:T,value:L,generateConfig:e,mode:B,fullscreen:E,locale:ne==null?void 0:ne.lang,validRange:$,onChange:q,onModeChange:K}),C(yz,{value:L,prefixCls:F,locale:ne==null?void 0:ne.lang,generateConfig:e,cellRender:ae,onSelect:J=>{q(J,j)},mode:j,picker:j,disabledDate:H,hideHeader:!0})]}))}}const c$=s$(VL);c$.generateCalendar=s$;const cF=c$,uF=e=>{const{prefixCls:t,className:n,style:r,size:o,shape:i}=e,a=te({[`${t}-lg`]:o==="large",[`${t}-sm`]:o==="small"}),l=te({[`${t}-circle`]:i==="circle",[`${t}-square`]:i==="square",[`${t}-round`]:i==="round"}),s=f.exports.useMemo(()=>typeof o=="number"?{width:o,height:o,lineHeight:`${o}px`}:{},[o]);return C("span",{className:te(t,a,l,n),style:Object.assign(Object.assign({},s),r)})},vf=uF,dF=new Ct("ant-skeleton-loading",{"0%":{backgroundPosition:"100% 50%"},"100%":{backgroundPosition:"0 50%"}}),pf=e=>({height:e,lineHeight:X(e)}),Da=e=>Object.assign({width:e},pf(e)),fF=e=>({background:e.skeletonLoadingBackground,backgroundSize:"400% 100%",animationName:dF,animationDuration:e.skeletonLoadingMotionDuration,animationTimingFunction:"ease",animationIterationCount:"infinite"}),Cv=(e,t)=>Object.assign({width:t(e).mul(5).equal(),minWidth:t(e).mul(5).equal()},pf(e)),vF=e=>{const{skeletonAvatarCls:t,gradientFromColor:n,controlHeight:r,controlHeightLG:o,controlHeightSM:i}=e;return{[`${t}`]:Object.assign({display:"inline-block",verticalAlign:"top",background:n},Da(r)),[`${t}${t}-circle`]:{borderRadius:"50%"},[`${t}${t}-lg`]:Object.assign({},Da(o)),[`${t}${t}-sm`]:Object.assign({},Da(i))}},pF=e=>{const{controlHeight:t,borderRadiusSM:n,skeletonInputCls:r,controlHeightLG:o,controlHeightSM:i,gradientFromColor:a,calc:l}=e;return{[`${r}`]:Object.assign({display:"inline-block",verticalAlign:"top",background:a,borderRadius:n},Cv(t,l)),[`${r}-lg`]:Object.assign({},Cv(o,l)),[`${r}-sm`]:Object.assign({},Cv(i,l))}},qb=e=>Object.assign({width:e},pf(e)),gF=e=>{const{skeletonImageCls:t,imageSizeBase:n,gradientFromColor:r,borderRadiusSM:o,calc:i}=e;return{[`${t}`]:Object.assign(Object.assign({display:"flex",alignItems:"center",justifyContent:"center",verticalAlign:"top",background:r,borderRadius:o},qb(i(n).mul(2).equal())),{[`${t}-path`]:{fill:"#bfbfbf"},[`${t}-svg`]:Object.assign(Object.assign({},qb(n)),{maxWidth:i(n).mul(4).equal(),maxHeight:i(n).mul(4).equal()}),[`${t}-svg${t}-svg-circle`]:{borderRadius:"50%"}}),[`${t}${t}-circle`]:{borderRadius:"50%"}}},xv=(e,t,n)=>{const{skeletonButtonCls:r}=e;return{[`${n}${r}-circle`]:{width:t,minWidth:t,borderRadius:"50%"},[`${n}${r}-round`]:{borderRadius:t}}},wv=(e,t)=>Object.assign({width:t(e).mul(2).equal(),minWidth:t(e).mul(2).equal()},pf(e)),hF=e=>{const{borderRadiusSM:t,skeletonButtonCls:n,controlHeight:r,controlHeightLG:o,controlHeightSM:i,gradientFromColor:a,calc:l}=e;return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({[`${n}`]:Object.assign({display:"inline-block",verticalAlign:"top",background:a,borderRadius:t,width:l(r).mul(2).equal(),minWidth:l(r).mul(2).equal()},wv(r,l))},xv(e,r,n)),{[`${n}-lg`]:Object.assign({},wv(o,l))}),xv(e,o,`${n}-lg`)),{[`${n}-sm`]:Object.assign({},wv(i,l))}),xv(e,i,`${n}-sm`))},mF=e=>{const{componentCls:t,skeletonAvatarCls:n,skeletonTitleCls:r,skeletonParagraphCls:o,skeletonButtonCls:i,skeletonInputCls:a,skeletonImageCls:l,controlHeight:s,controlHeightLG:c,controlHeightSM:u,gradientFromColor:d,padding:v,marginSM:h,borderRadius:g,titleHeight:p,blockRadius:b,paragraphLiHeight:m,controlHeightXS:y,paragraphMarginTop:S}=e;return{[`${t}`]:{display:"table",width:"100%",[`${t}-header`]:{display:"table-cell",paddingInlineEnd:v,verticalAlign:"top",[`${n}`]:Object.assign({display:"inline-block",verticalAlign:"top",background:d},Da(s)),[`${n}-circle`]:{borderRadius:"50%"},[`${n}-lg`]:Object.assign({},Da(c)),[`${n}-sm`]:Object.assign({},Da(u))},[`${t}-content`]:{display:"table-cell",width:"100%",verticalAlign:"top",[`${r}`]:{width:"100%",height:p,background:d,borderRadius:b,[`+ ${o}`]:{marginBlockStart:u}},[`${o}`]:{padding:0,"> li":{width:"100%",height:m,listStyle:"none",background:d,borderRadius:b,"+ li":{marginBlockStart:y}}},[`${o}> li:last-child:not(:first-child):not(:nth-child(2))`]:{width:"61%"}},[`&-round ${t}-content`]:{[`${r}, ${o} > li`]:{borderRadius:g}}},[`${t}-with-avatar ${t}-content`]:{[`${r}`]:{marginBlockStart:h,[`+ ${o}`]:{marginBlockStart:S}}},[`${t}${t}-element`]:Object.assign(Object.assign(Object.assign(Object.assign({display:"inline-block",width:"auto"},hF(e)),vF(e)),pF(e)),gF(e)),[`${t}${t}-block`]:{width:"100%",[`${i}`]:{width:"100%"},[`${a}`]:{width:"100%"}},[`${t}${t}-active`]:{[` + ${r}, + ${o} > li, + ${n}, + ${i}, + ${a}, + ${l} + `]:Object.assign({},fF(e))}}},yF=e=>{const{colorFillContent:t,colorFill:n}=e,r=t,o=n;return{color:r,colorGradientEnd:o,gradientFromColor:r,gradientToColor:o,titleHeight:e.controlHeight/2,blockRadius:e.borderRadiusSM,paragraphMarginTop:e.marginLG+e.marginXXS,paragraphLiHeight:e.controlHeight/2}},ll=vn("Skeleton",e=>{const{componentCls:t,calc:n}=e,r=$t(e,{skeletonAvatarCls:`${t}-avatar`,skeletonTitleCls:`${t}-title`,skeletonParagraphCls:`${t}-paragraph`,skeletonButtonCls:`${t}-button`,skeletonInputCls:`${t}-input`,skeletonImageCls:`${t}-image`,imageSizeBase:n(e.controlHeight).mul(1.5).equal(),borderRadius:100,skeletonLoadingBackground:`linear-gradient(90deg, ${e.gradientFromColor} 25%, ${e.gradientToColor} 37%, ${e.gradientFromColor} 63%)`,skeletonLoadingMotionDuration:"1.4s"});return[mF(r)]},yF,{deprecatedTokens:[["color","gradientFromColor"],["colorGradientEnd","gradientToColor"]]}),bF=e=>{const{prefixCls:t,className:n,rootClassName:r,active:o,shape:i="circle",size:a="default"}=e,{getPrefixCls:l}=f.exports.useContext(ot),s=l("skeleton",t),[c,u,d]=ll(s),v=lr(e,["prefixCls","className"]),h=te(s,`${s}-element`,{[`${s}-active`]:o},n,r,u,d);return c(C("div",{className:h,children:C(vf,{...Object.assign({prefixCls:`${s}-avatar`,shape:i,size:a},v)})}))},SF=bF,CF=e=>{const{prefixCls:t,className:n,rootClassName:r,active:o,block:i=!1,size:a="default"}=e,{getPrefixCls:l}=f.exports.useContext(ot),s=l("skeleton",t),[c,u,d]=ll(s),v=lr(e,["prefixCls"]),h=te(s,`${s}-element`,{[`${s}-active`]:o,[`${s}-block`]:i},n,r,u,d);return c(C("div",{className:h,children:C(vf,{...Object.assign({prefixCls:`${s}-button`,size:a},v)})}))},xF=CF,wF="M365.714286 329.142857q0 45.714286-32.036571 77.677714t-77.677714 32.036571-77.677714-32.036571-32.036571-77.677714 32.036571-77.677714 77.677714-32.036571 77.677714 32.036571 32.036571 77.677714zM950.857143 548.571429l0 256-804.571429 0 0-109.714286 182.857143-182.857143 91.428571 91.428571 292.571429-292.571429zM1005.714286 146.285714l-914.285714 0q-7.460571 0-12.873143 5.412571t-5.412571 12.873143l0 694.857143q0 7.460571 5.412571 12.873143t12.873143 5.412571l914.285714 0q7.460571 0 12.873143-5.412571t5.412571-12.873143l0-694.857143q0-7.460571-5.412571-12.873143t-12.873143-5.412571zM1097.142857 164.571429l0 694.857143q0 37.741714-26.843429 64.585143t-64.585143 26.843429l-914.285714 0q-37.741714 0-64.585143-26.843429t-26.843429-64.585143l0-694.857143q0-37.741714 26.843429-64.585143t64.585143-26.843429l914.285714 0q37.741714 0 64.585143 26.843429t26.843429 64.585143z",$F=e=>{const{prefixCls:t,className:n,rootClassName:r,style:o,active:i}=e,{getPrefixCls:a}=f.exports.useContext(ot),l=a("skeleton",t),[s,c,u]=ll(l),d=te(l,`${l}-element`,{[`${l}-active`]:i},n,r,c,u);return s(C("div",{className:d,children:C("div",{className:te(`${l}-image`,n),style:o,children:C("svg",{viewBox:"0 0 1098 1024",xmlns:"http://www.w3.org/2000/svg",className:`${l}-image-svg`,children:C("path",{d:wF,className:`${l}-image-path`})})})}))},EF=$F,MF=e=>{const{prefixCls:t,className:n,rootClassName:r,active:o,block:i,size:a="default"}=e,{getPrefixCls:l}=f.exports.useContext(ot),s=l("skeleton",t),[c,u,d]=ll(s),v=lr(e,["prefixCls"]),h=te(s,`${s}-element`,{[`${s}-active`]:o,[`${s}-block`]:i},n,r,u,d);return c(C("div",{className:h,children:C(vf,{...Object.assign({prefixCls:`${s}-input`,size:a},v)})}))},OF=MF,RF=e=>{const{prefixCls:t,className:n,rootClassName:r,style:o,active:i,children:a}=e,{getPrefixCls:l}=f.exports.useContext(ot),s=l("skeleton",t),[c,u,d]=ll(s),v=te(s,`${s}-element`,{[`${s}-active`]:i},u,n,r,d),h=a!=null?a:C(UI,{});return c(C("div",{className:v,children:C("div",{className:te(`${s}-image`,n),style:o,children:h})}))},IF=RF,PF=e=>{const t=l=>{const{width:s,rows:c=2}=e;if(Array.isArray(s))return s[l];if(c-1===l)return s},{prefixCls:n,className:r,style:o,rows:i}=e,a=Oe(Array(i)).map((l,s)=>C("li",{style:{width:t(s)}},s));return C("ul",{className:te(n,r),style:o,children:a})},TF=PF,NF=e=>{let{prefixCls:t,className:n,width:r,style:o}=e;return C("h3",{className:te(t,n),style:Object.assign({width:r},o)})},_F=NF;function $v(e){return e&&typeof e=="object"?e:{}}function AF(e,t){return e&&!t?{size:"large",shape:"square"}:{size:"large",shape:"circle"}}function DF(e,t){return!e&&t?{width:"38%"}:e&&t?{width:"50%"}:{}}function LF(e,t){const n={};return(!e||!t)&&(n.width="61%"),!e&&t?n.rows=3:n.rows=2,n}const sl=e=>{const{prefixCls:t,loading:n,className:r,rootClassName:o,style:i,children:a,avatar:l=!1,title:s=!0,paragraph:c=!0,active:u,round:d}=e,{getPrefixCls:v,direction:h,skeleton:g}=f.exports.useContext(ot),p=v("skeleton",t),[b,m,y]=ll(p);if(n||!("loading"in e)){const S=!!l,x=!!s,$=!!c;let E;if(S){const P=Object.assign(Object.assign({prefixCls:`${p}-avatar`},AF(x,$)),$v(l));E=C("div",{className:`${p}-header`,children:C(vf,{...Object.assign({},P)})})}let w;if(x||$){let P;if(x){const I=Object.assign(Object.assign({prefixCls:`${p}-title`},DF(S,$)),$v(s));P=C(_F,{...Object.assign({},I)})}let N;if($){const I=Object.assign(Object.assign({prefixCls:`${p}-paragraph`},LF(S,x)),$v(c));N=C(TF,{...Object.assign({},I)})}w=ie("div",{className:`${p}-content`,children:[P,N]})}const R=te(p,{[`${p}-with-avatar`]:S,[`${p}-active`]:u,[`${p}-rtl`]:h==="rtl",[`${p}-round`]:d},g==null?void 0:g.className,r,o,m,y);return b(ie("div",{className:R,style:Object.assign(Object.assign({},g==null?void 0:g.style),i),children:[E,w]}))}return typeof a<"u"?a:null};sl.Button=xF;sl.Avatar=SF;sl.Input=OF;sl.Image=EF;sl.Node=IF;const zF=sl,gf=f.exports.createContext(null);var FF=function(t){var n=t.activeTabOffset,r=t.horizontal,o=t.rtl,i=t.indicator,a=i===void 0?{}:i,l=a.size,s=a.align,c=s===void 0?"center":s,u=f.exports.useState(),d=G(u,2),v=d[0],h=d[1],g=f.exports.useRef(),p=lt.useCallback(function(m){return typeof l=="function"?l(m):typeof l=="number"?l:m},[l]);function b(){St.cancel(g.current)}return f.exports.useEffect(function(){var m={};if(n)if(r){m.width=p(n.width);var y=o?"right":"left";c==="start"&&(m[y]=n[y]),c==="center"&&(m[y]=n[y]+n.width/2,m.transform=o?"translateX(50%)":"translateX(-50%)"),c==="end"&&(m[y]=n[y]+n.width,m.transform="translateX(-100%)")}else m.height=p(n.height),c==="start"&&(m.top=n.top),c==="center"&&(m.top=n.top+n.height/2,m.transform="translateY(-50%)"),c==="end"&&(m.top=n.top+n.height,m.transform="translateY(-100%)");return b(),g.current=St(function(){h(m)}),b},[n,r,o,c,p]),{style:v}},Xb={width:0,height:0,left:0,top:0};function kF(e,t,n){return f.exports.useMemo(function(){for(var r,o=new Map,i=t.get((r=e[0])===null||r===void 0?void 0:r.key)||Xb,a=i.left+i.width,l=0;lT?(z=N,E.current="x"):(z=I,E.current="y"),t(-z,-z)&&P.preventDefault()}var R=f.exports.useRef(null);R.current={onTouchStart:S,onTouchMove:x,onTouchEnd:$,onWheel:w},f.exports.useEffect(function(){function P(F){R.current.onTouchStart(F)}function N(F){R.current.onTouchMove(F)}function I(F){R.current.onTouchEnd(F)}function z(F){R.current.onWheel(F)}return document.addEventListener("touchmove",N,{passive:!1}),document.addEventListener("touchend",I,{passive:!1}),e.current.addEventListener("touchstart",P,{passive:!1}),e.current.addEventListener("wheel",z),function(){document.removeEventListener("touchmove",N),document.removeEventListener("touchend",I)}},[])}function u$(e){var t=f.exports.useState(0),n=G(t,2),r=n[0],o=n[1],i=f.exports.useRef(0),a=f.exports.useRef();return a.current=e,Hp(function(){var l;(l=a.current)===null||l===void 0||l.call(a)},[r]),function(){i.current===r&&(i.current+=1,o(i.current))}}function HF(e){var t=f.exports.useRef([]),n=f.exports.useState({}),r=G(n,2),o=r[1],i=f.exports.useRef(typeof e=="function"?e():e),a=u$(function(){var s=i.current;t.current.forEach(function(c){s=c(s)}),t.current=[],i.current=s,o({})});function l(s){t.current.push(s),a()}return[i.current,l]}var e1={width:0,height:0,left:0,top:0,right:0};function WF(e,t,n,r,o,i,a){var l=a.tabs,s=a.tabPosition,c=a.rtl,u,d,v;return["top","bottom"].includes(s)?(u="width",d=c?"right":"left",v=Math.abs(n)):(u="height",d="top",v=-n),f.exports.useMemo(function(){if(!l.length)return[0,0];for(var h=l.length,g=h,p=0;pv+t){g=p-1;break}}for(var m=0,y=h-1;y>=0;y-=1){var S=e.get(l[y].key)||e1;if(S[d]=g?[0,0]:[m,g]},[e,t,r,o,i,v,s,l.map(function(h){return h.key}).join("_"),c])}function t1(e){var t;return e instanceof Map?(t={},e.forEach(function(n,r){t[r]=n})):t=e,JSON.stringify(t)}var VF="TABS_DQ";function d$(e){return String(e).replace(/"/g,VF)}function f$(e,t,n,r){return!(!n||r||e===!1||e===void 0&&(t===!1||t===null))}var v$=f.exports.forwardRef(function(e,t){var n=e.prefixCls,r=e.editable,o=e.locale,i=e.style;return!r||r.showAdd===!1?null:C("button",{ref:t,type:"button",className:"".concat(n,"-nav-add"),style:i,"aria-label":(o==null?void 0:o.addAriaLabel)||"Add tab",onClick:function(l){r.onEdit("add",{event:l})},children:r.addIcon||"+"})}),n1=f.exports.forwardRef(function(e,t){var n=e.position,r=e.prefixCls,o=e.extra;if(!o)return null;var i,a={};return Qe(o)==="object"&&!f.exports.isValidElement(o)?a=o:a.right=o,n==="right"&&(i=a.right),n==="left"&&(i=a.left),i?C("div",{className:"".concat(r,"-extra-content"),ref:t,children:i}):null}),UF=f.exports.forwardRef(function(e,t){var n=e.prefixCls,r=e.id,o=e.tabs,i=e.locale,a=e.mobile,l=e.moreIcon,s=l===void 0?"More":l,c=e.moreTransitionName,u=e.style,d=e.className,v=e.editable,h=e.tabBarGutter,g=e.rtl,p=e.removeAriaLabel,b=e.onTabClick,m=e.getPopupContainer,y=e.popupClassName,S=f.exports.useState(!1),x=G(S,2),$=x[0],E=x[1],w=f.exports.useState(null),R=G(w,2),P=R[0],N=R[1],I="".concat(r,"-more-popup"),z="".concat(n,"-dropdown"),F=P!==null?"".concat(I,"-").concat(P):null,T=i==null?void 0:i.dropdownAriaLabel;function D(k,j){k.preventDefault(),k.stopPropagation(),v.onEdit("remove",{key:j,event:k})}var _=C(Qs,{onClick:function(j){var H=j.key,W=j.domEvent;b(H,W),E(!1)},prefixCls:"".concat(z,"-menu"),id:I,tabIndex:-1,role:"listbox","aria-activedescendant":F,selectedKeys:[P],"aria-label":T!==void 0?T:"expanded dropdown",children:o.map(function(k){var j=k.closable,H=k.disabled,W=k.closeIcon,Y=k.key,K=k.label,q=f$(j,W,v,H);return ie(cf,{id:"".concat(I,"-").concat(Y),role:"option","aria-controls":r&&"".concat(r,"-panel-").concat(Y),disabled:H,children:[C("span",{children:K}),q&&C("button",{type:"button","aria-label":p||"remove",tabIndex:0,className:"".concat(z,"-menu-item-remove"),onClick:function(Z){Z.stopPropagation(),D(Z,Y)},children:W||v.removeIcon||"\xD7"})]},Y)})});function O(k){for(var j=o.filter(function(q){return!q.disabled}),H=j.findIndex(function(q){return q.key===P})||0,W=j.length,Y=0;YVe?"left":"right"})}),F=G(z,2),T=F[0],D=F[1],_=Qb(0,function(We,Ve){!I&&p&&p({direction:We>Ve?"top":"bottom"})}),O=G(_,2),M=O[0],L=O[1],A=f.exports.useState([0,0]),B=G(A,2),k=B[0],j=B[1],H=f.exports.useState([0,0]),W=G(H,2),Y=W[0],K=W[1],q=f.exports.useState([0,0]),ee=G(q,2),Z=ee[0],Q=ee[1],ne=f.exports.useState([0,0]),ae=G(ne,2),J=ae[0],re=ae[1],fe=HF(new Map),ve=G(fe,2),pe=ve[0],oe=ve[1],se=kF(S,pe,Y[0]),le=Fc(k,I),Ce=Fc(Y,I),ce=Fc(Z,I),de=Fc(J,I),xe=lege?ge:We}var Se=f.exports.useRef(null),st=f.exports.useState(),nt=G(st,2),Ne=nt[0],Ee=nt[1];function _e(){Ee(Date.now())}function Be(){Se.current&&clearTimeout(Se.current)}jF(w,function(We,Ve){function vt(Ie,ze){Ie(function(Ke){var at=Pe(Ke+ze);return at})}return xe?(I?vt(D,We):vt(L,Ve),Be(),_e(),!0):!1}),f.exports.useEffect(function(){return Be(),Ne&&(Se.current=setTimeout(function(){Ee(0)},100)),Be},[Ne]);var qe=WF(se,he,I?T:M,Ce,ce,de,U(U({},e),{},{tabs:S})),it=G(qe,2),ft=it[0],ut=it[1],Ue=hn(function(){var We=arguments.length>0&&arguments[0]!==void 0?arguments[0]:a,Ve=se.get(We)||{width:0,height:0,left:0,right:0,top:0};if(I){var vt=T;l?Ve.rightT+he&&(vt=Ve.right+Ve.width-he):Ve.left<-T?vt=-Ve.left:Ve.left+Ve.width>-T+he&&(vt=-(Ve.left+Ve.width-he)),L(0),D(Pe(vt))}else{var Ie=M;Ve.top<-M?Ie=-Ve.top:Ve.top+Ve.height>-M+he&&(Ie=-(Ve.top+Ve.height-he)),D(0),L(Pe(Ie))}}),He={};d==="top"||d==="bottom"?He[l?"marginRight":"marginLeft"]=v:He.marginTop=v;var Xe=S.map(function(We,Ve){var vt=We.key;return C(GF,{id:o,prefixCls:y,tab:We,style:Ve===0?void 0:He,closable:We.closable,editable:c,active:vt===a,renderWrapper:h,removeAriaLabel:u==null?void 0:u.removeAriaLabel,onClick:function(ze){g(vt,ze)},onFocus:function(){Ue(vt),_e(),w.current&&(l||(w.current.scrollLeft=0),w.current.scrollTop=0)}},vt)}),Le=function(){return oe(function(){var Ve,vt=new Map,Ie=(Ve=R.current)===null||Ve===void 0?void 0:Ve.getBoundingClientRect();return S.forEach(function(ze){var Ke,at=ze.key,Gt=(Ke=R.current)===null||Ke===void 0?void 0:Ke.querySelector('[data-node-key="'.concat(d$(at),'"]'));if(Gt){var At=KF(Gt,Ie),Zt=G(At,4),Jt=Zt[0],kn=Zt[1],qn=Zt[2],pn=Zt[3];vt.set(at,{width:Jt,height:kn,left:qn,top:pn})}}),vt})};f.exports.useEffect(function(){Le()},[S.map(function(We){return We.key}).join("_")]);var Re=u$(function(){var We=ra(x),Ve=ra($),vt=ra(E);j([We[0]-Ve[0]-vt[0],We[1]-Ve[1]-vt[1]]);var Ie=ra(N);Q(Ie);var ze=ra(P);re(ze);var Ke=ra(R);K([Ke[0]-Ie[0],Ke[1]-Ie[1]]),Le()}),be=S.slice(0,ft),Ae=S.slice(ut+1),Me=[].concat(Oe(be),Oe(Ae)),$e=se.get(a),Te=FF({activeTabOffset:$e,horizontal:I,indicator:b,rtl:l}),ye=Te.style;f.exports.useEffect(function(){Ue()},[a,we,ge,t1($e),t1(se),I]),f.exports.useEffect(function(){Re()},[l]);var Ge=!!Me.length,Ze="".concat(y,"-nav-wrap"),et,ht,mt,ct;return I?l?(ht=T>0,et=T!==ge):(et=T<0,ht=T!==we):(mt=M<0,ct=M!==we),C(mr,{onResize:Re,children:ie("div",{ref:Fi(t,x),role:"tablist",className:te("".concat(y,"-nav"),n),style:r,onKeyDown:function(){_e()},children:[C(n1,{ref:$,position:"left",extra:s,prefixCls:y}),C(mr,{onResize:Re,children:C("div",{className:te(Ze,V(V(V(V({},"".concat(Ze,"-ping-left"),et),"".concat(Ze,"-ping-right"),ht),"".concat(Ze,"-ping-top"),mt),"".concat(Ze,"-ping-bottom"),ct)),ref:w,children:C(mr,{onResize:Re,children:ie("div",{ref:R,className:"".concat(y,"-nav-list"),style:{transform:"translate(".concat(T,"px, ").concat(M,"px)"),transition:Ne?"none":void 0},children:[Xe,C(v$,{ref:N,prefixCls:y,locale:u,editable:c,style:U(U({},Xe.length===0?void 0:He),{},{visibility:Ge?"hidden":null})}),C("div",{className:te("".concat(y,"-ink-bar"),V({},"".concat(y,"-ink-bar-animated"),i.inkBar)),style:ye})]})})})}),C(YF,{...e,removeAriaLabel:u==null?void 0:u.removeAriaLabel,ref:P,prefixCls:y,tabs:Me,className:!Ge&&ke,tabMoving:!!Ne}),C(n1,{ref:E,position:"right",extra:s,prefixCls:y})]})})}),p$=f.exports.forwardRef(function(e,t){var n=e.prefixCls,r=e.className,o=e.style,i=e.id,a=e.active,l=e.tabKey,s=e.children;return C("div",{id:i&&"".concat(i,"-panel-").concat(l),role:"tabpanel",tabIndex:a?0:-1,"aria-labelledby":i&&"".concat(i,"-tab-").concat(l),"aria-hidden":!a,style:o,className:te(n,a&&"".concat(n,"-active"),r),ref:t,children:s})}),qF=["renderTabBar"],XF=["label","key"],QF=function(t){var n=t.renderTabBar,r=Je(t,qF),o=f.exports.useContext(gf),i=o.tabs;if(n){var a=U(U({},r),{},{panes:i.map(function(l){var s=l.label,c=l.key,u=Je(l,XF);return C(p$,{tab:s,tabKey:c,...u},c)})});return n(a,r1)}return C(r1,{...r})},ZF=["key","forceRender","style","className","destroyInactiveTabPane"],JF=function(t){var n=t.id,r=t.activeKey,o=t.animated,i=t.tabPosition,a=t.destroyInactiveTabPane,l=f.exports.useContext(gf),s=l.prefixCls,c=l.tabs,u=o.tabPane,d="".concat(s,"-tabpane");return C("div",{className:te("".concat(s,"-content-holder")),children:C("div",{className:te("".concat(s,"-content"),"".concat(s,"-content-").concat(i),V({},"".concat(s,"-content-animated"),u)),children:c.map(function(v){var h=v.key,g=v.forceRender,p=v.style,b=v.className,m=v.destroyInactiveTabPane,y=Je(v,ZF),S=h===r;return C(to,{visible:S,forceRender:g,removeOnLeave:!!(a||m),leavedClassName:"".concat(d,"-hidden"),...o.tabPaneMotion,children:function(x,$){var E=x.style,w=x.className;return C(p$,{...y,prefixCls:d,id:n,tabKey:h,animated:u,active:S,style:U(U({},p),E),className:te(b,w),ref:$})}},h)})})})};function ek(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{inkBar:!0,tabPane:!1},t;return e===!1?t={inkBar:!1,tabPane:!1}:e===!0?t={inkBar:!0,tabPane:!1}:t=U({inkBar:!0},Qe(e)==="object"?e:{}),t.tabPaneMotion&&t.tabPane===void 0&&(t.tabPane=!0),!t.tabPaneMotion&&t.tabPane&&(t.tabPane=!1),t}var tk=["id","prefixCls","className","items","direction","activeKey","defaultActiveKey","editable","animated","tabPosition","tabBarGutter","tabBarStyle","tabBarExtraContent","locale","moreIcon","moreTransitionName","destroyInactiveTabPane","renderTabBar","onChange","onTabClick","onTabScroll","getPopupContainer","popupClassName","indicator"],o1=0,nk=f.exports.forwardRef(function(e,t){var n=e.id,r=e.prefixCls,o=r===void 0?"rc-tabs":r,i=e.className,a=e.items,l=e.direction,s=e.activeKey,c=e.defaultActiveKey,u=e.editable,d=e.animated,v=e.tabPosition,h=v===void 0?"top":v,g=e.tabBarGutter,p=e.tabBarStyle,b=e.tabBarExtraContent,m=e.locale,y=e.moreIcon,S=e.moreTransitionName,x=e.destroyInactiveTabPane,$=e.renderTabBar,E=e.onChange,w=e.onTabClick,R=e.onTabScroll,P=e.getPopupContainer,N=e.popupClassName,I=e.indicator,z=Je(e,tk),F=f.exports.useMemo(function(){return(a||[]).filter(function(re){return re&&Qe(re)==="object"&&"key"in re})},[a]),T=l==="rtl",D=ek(d),_=f.exports.useState(!1),O=G(_,2),M=O[0],L=O[1];f.exports.useEffect(function(){L(am())},[]);var A=kt(function(){var re;return(re=F[0])===null||re===void 0?void 0:re.key},{value:s,defaultValue:c}),B=G(A,2),k=B[0],j=B[1],H=f.exports.useState(function(){return F.findIndex(function(re){return re.key===k})}),W=G(H,2),Y=W[0],K=W[1];f.exports.useEffect(function(){var re=F.findIndex(function(ve){return ve.key===k});if(re===-1){var fe;re=Math.max(0,Math.min(Y,F.length-1)),j((fe=F[re])===null||fe===void 0?void 0:fe.key)}K(re)},[F.map(function(re){return re.key}).join("_"),k,Y]);var q=kt(null,{value:n}),ee=G(q,2),Z=ee[0],Q=ee[1];f.exports.useEffect(function(){n||(Q("rc-tabs-".concat(o1)),o1+=1)},[]);function ne(re,fe){w==null||w(re,fe);var ve=re!==k;j(re),ve&&(E==null||E(re))}var ae={id:Z,activeKey:k,animated:D,tabPosition:h,rtl:T,mobile:M},J=U(U({},ae),{},{editable:u,locale:m,moreIcon:y,moreTransitionName:S,tabBarGutter:g,onTabClick:ne,onTabScroll:R,extra:b,style:p,panes:null,getPopupContainer:P,popupClassName:N,indicator:I});return C(gf.Provider,{value:{tabs:F,prefixCls:o},children:ie("div",{ref:t,id:n,className:te(o,"".concat(o,"-").concat(h),V(V(V({},"".concat(o,"-mobile"),M),"".concat(o,"-editable"),u),"".concat(o,"-rtl"),T),i),...z,children:[C(QF,{...J,renderTabBar:$}),C(JF,{destroyInactiveTabPane:x,...ae,animated:D})]})})});const rk={motionAppear:!1,motionEnter:!0,motionLeave:!0};function ok(e){let t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{inkBar:!0,tabPane:!1},n;return t===!1?n={inkBar:!1,tabPane:!1}:t===!0?n={inkBar:!0,tabPane:!0}:n=Object.assign({inkBar:!0},typeof t=="object"?t:{}),n.tabPane&&(n.tabPaneMotion=Object.assign(Object.assign({},rk),{motionName:ni(e,"switch")})),n}var ik=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);ot)}function lk(e,t){if(e)return e;const n=Qo(t).map(r=>{if(f.exports.isValidElement(r)){const{key:o,props:i}=r,a=i||{},{tab:l}=a,s=ik(a,["tab"]);return Object.assign(Object.assign({key:String(o)},s),{label:l})}return null});return ak(n)}const sk=e=>{const{componentCls:t,motionDurationSlow:n}=e;return[{[t]:{[`${t}-switch`]:{"&-appear, &-enter":{transition:"none","&-start":{opacity:0},"&-active":{opacity:1,transition:`opacity ${n}`}},"&-leave":{position:"absolute",transition:"none",inset:0,"&-start":{opacity:1},"&-active":{opacity:0,transition:`opacity ${n}`}}}}},[Xa(e,"slide-up"),Xa(e,"slide-down")]]},ck=sk,uk=e=>{const{componentCls:t,tabsCardPadding:n,cardBg:r,cardGutter:o,colorBorderSecondary:i,itemSelectedColor:a}=e;return{[`${t}-card`]:{[`> ${t}-nav, > div > ${t}-nav`]:{[`${t}-tab`]:{margin:0,padding:n,background:r,border:`${X(e.lineWidth)} ${e.lineType} ${i}`,transition:`all ${e.motionDurationSlow} ${e.motionEaseInOut}`},[`${t}-tab-active`]:{color:a,background:e.colorBgContainer},[`${t}-ink-bar`]:{visibility:"hidden"}},[`&${t}-top, &${t}-bottom`]:{[`> ${t}-nav, > div > ${t}-nav`]:{[`${t}-tab + ${t}-tab`]:{marginLeft:{_skip_check_:!0,value:X(o)}}}},[`&${t}-top`]:{[`> ${t}-nav, > div > ${t}-nav`]:{[`${t}-tab`]:{borderRadius:`${X(e.borderRadiusLG)} ${X(e.borderRadiusLG)} 0 0`},[`${t}-tab-active`]:{borderBottomColor:e.colorBgContainer}}},[`&${t}-bottom`]:{[`> ${t}-nav, > div > ${t}-nav`]:{[`${t}-tab`]:{borderRadius:`0 0 ${X(e.borderRadiusLG)} ${X(e.borderRadiusLG)}`},[`${t}-tab-active`]:{borderTopColor:e.colorBgContainer}}},[`&${t}-left, &${t}-right`]:{[`> ${t}-nav, > div > ${t}-nav`]:{[`${t}-tab + ${t}-tab`]:{marginTop:X(o)}}},[`&${t}-left`]:{[`> ${t}-nav, > div > ${t}-nav`]:{[`${t}-tab`]:{borderRadius:{_skip_check_:!0,value:`${X(e.borderRadiusLG)} 0 0 ${X(e.borderRadiusLG)}`}},[`${t}-tab-active`]:{borderRightColor:{_skip_check_:!0,value:e.colorBgContainer}}}},[`&${t}-right`]:{[`> ${t}-nav, > div > ${t}-nav`]:{[`${t}-tab`]:{borderRadius:{_skip_check_:!0,value:`0 ${X(e.borderRadiusLG)} ${X(e.borderRadiusLG)} 0`}},[`${t}-tab-active`]:{borderLeftColor:{_skip_check_:!0,value:e.colorBgContainer}}}}}}},dk=e=>{const{componentCls:t,itemHoverColor:n,dropdownEdgeChildVerticalPadding:r}=e;return{[`${t}-dropdown`]:Object.assign(Object.assign({},Qt(e)),{position:"absolute",top:-9999,left:{_skip_check_:!0,value:-9999},zIndex:e.zIndexPopup,display:"block","&-hidden":{display:"none"},[`${t}-dropdown-menu`]:{maxHeight:e.tabsDropdownHeight,margin:0,padding:`${X(r)} 0`,overflowX:"hidden",overflowY:"auto",textAlign:{_skip_check_:!0,value:"left"},listStyleType:"none",backgroundColor:e.colorBgContainer,backgroundClip:"padding-box",borderRadius:e.borderRadiusLG,outline:"none",boxShadow:e.boxShadowSecondary,"&-item":Object.assign(Object.assign({},ei),{display:"flex",alignItems:"center",minWidth:e.tabsDropdownWidth,margin:0,padding:`${X(e.paddingXXS)} ${X(e.paddingSM)}`,color:e.colorText,fontWeight:"normal",fontSize:e.fontSize,lineHeight:e.lineHeight,cursor:"pointer",transition:`all ${e.motionDurationSlow}`,"> span":{flex:1,whiteSpace:"nowrap"},"&-remove":{flex:"none",marginLeft:{_skip_check_:!0,value:e.marginSM},color:e.colorTextDescription,fontSize:e.fontSizeSM,background:"transparent",border:0,cursor:"pointer","&:hover":{color:n}},"&:hover":{background:e.controlItemBgHover},"&-disabled":{"&, &:hover":{color:e.colorTextDisabled,background:"transparent",cursor:"not-allowed"}}})}})}},fk=e=>{const{componentCls:t,margin:n,colorBorderSecondary:r,horizontalMargin:o,verticalItemPadding:i,verticalItemMargin:a,calc:l}=e;return{[`${t}-top, ${t}-bottom`]:{flexDirection:"column",[`> ${t}-nav, > div > ${t}-nav`]:{margin:o,"&::before":{position:"absolute",right:{_skip_check_:!0,value:0},left:{_skip_check_:!0,value:0},borderBottom:`${X(e.lineWidth)} ${e.lineType} ${r}`,content:"''"},[`${t}-ink-bar`]:{height:e.lineWidthBold,"&-animated":{transition:`width ${e.motionDurationSlow}, left ${e.motionDurationSlow}, + right ${e.motionDurationSlow}`}},[`${t}-nav-wrap`]:{"&::before, &::after":{top:0,bottom:0,width:e.controlHeight},"&::before":{left:{_skip_check_:!0,value:0},boxShadow:e.boxShadowTabsOverflowLeft},"&::after":{right:{_skip_check_:!0,value:0},boxShadow:e.boxShadowTabsOverflowRight},[`&${t}-nav-wrap-ping-left::before`]:{opacity:1},[`&${t}-nav-wrap-ping-right::after`]:{opacity:1}}}},[`${t}-top`]:{[`> ${t}-nav, + > div > ${t}-nav`]:{"&::before":{bottom:0},[`${t}-ink-bar`]:{bottom:0}}},[`${t}-bottom`]:{[`> ${t}-nav, > div > ${t}-nav`]:{order:1,marginTop:n,marginBottom:0,"&::before":{top:0},[`${t}-ink-bar`]:{top:0}},[`> ${t}-content-holder, > div > ${t}-content-holder`]:{order:0}},[`${t}-left, ${t}-right`]:{[`> ${t}-nav, > div > ${t}-nav`]:{flexDirection:"column",minWidth:l(e.controlHeight).mul(1.25).equal(),[`${t}-tab`]:{padding:i,textAlign:"center"},[`${t}-tab + ${t}-tab`]:{margin:a},[`${t}-nav-wrap`]:{flexDirection:"column","&::before, &::after":{right:{_skip_check_:!0,value:0},left:{_skip_check_:!0,value:0},height:e.controlHeight},"&::before":{top:0,boxShadow:e.boxShadowTabsOverflowTop},"&::after":{bottom:0,boxShadow:e.boxShadowTabsOverflowBottom},[`&${t}-nav-wrap-ping-top::before`]:{opacity:1},[`&${t}-nav-wrap-ping-bottom::after`]:{opacity:1}},[`${t}-ink-bar`]:{width:e.lineWidthBold,"&-animated":{transition:`height ${e.motionDurationSlow}, top ${e.motionDurationSlow}`}},[`${t}-nav-list, ${t}-nav-operations`]:{flex:"1 0 auto",flexDirection:"column"}}},[`${t}-left`]:{[`> ${t}-nav, > div > ${t}-nav`]:{[`${t}-ink-bar`]:{right:{_skip_check_:!0,value:0}}},[`> ${t}-content-holder, > div > ${t}-content-holder`]:{marginLeft:{_skip_check_:!0,value:X(l(e.lineWidth).mul(-1).equal())},borderLeft:{_skip_check_:!0,value:`${X(e.lineWidth)} ${e.lineType} ${e.colorBorder}`},[`> ${t}-content > ${t}-tabpane`]:{paddingLeft:{_skip_check_:!0,value:e.paddingLG}}}},[`${t}-right`]:{[`> ${t}-nav, > div > ${t}-nav`]:{order:1,[`${t}-ink-bar`]:{left:{_skip_check_:!0,value:0}}},[`> ${t}-content-holder, > div > ${t}-content-holder`]:{order:0,marginRight:{_skip_check_:!0,value:l(e.lineWidth).mul(-1).equal()},borderRight:{_skip_check_:!0,value:`${X(e.lineWidth)} ${e.lineType} ${e.colorBorder}`},[`> ${t}-content > ${t}-tabpane`]:{paddingRight:{_skip_check_:!0,value:e.paddingLG}}}}}},vk=e=>{const{componentCls:t,cardPaddingSM:n,cardPaddingLG:r,horizontalItemPaddingSM:o,horizontalItemPaddingLG:i}=e;return{[t]:{"&-small":{[`> ${t}-nav`]:{[`${t}-tab`]:{padding:o,fontSize:e.titleFontSizeSM}}},"&-large":{[`> ${t}-nav`]:{[`${t}-tab`]:{padding:i,fontSize:e.titleFontSizeLG}}}},[`${t}-card`]:{[`&${t}-small`]:{[`> ${t}-nav`]:{[`${t}-tab`]:{padding:n}},[`&${t}-bottom`]:{[`> ${t}-nav ${t}-tab`]:{borderRadius:`0 0 ${X(e.borderRadius)} ${X(e.borderRadius)}`}},[`&${t}-top`]:{[`> ${t}-nav ${t}-tab`]:{borderRadius:`${X(e.borderRadius)} ${X(e.borderRadius)} 0 0`}},[`&${t}-right`]:{[`> ${t}-nav ${t}-tab`]:{borderRadius:{_skip_check_:!0,value:`0 ${X(e.borderRadius)} ${X(e.borderRadius)} 0`}}},[`&${t}-left`]:{[`> ${t}-nav ${t}-tab`]:{borderRadius:{_skip_check_:!0,value:`${X(e.borderRadius)} 0 0 ${X(e.borderRadius)}`}}}},[`&${t}-large`]:{[`> ${t}-nav`]:{[`${t}-tab`]:{padding:r}}}}}},pk=e=>{const{componentCls:t,itemActiveColor:n,itemHoverColor:r,iconCls:o,tabsHorizontalItemMargin:i,horizontalItemPadding:a,itemSelectedColor:l,itemColor:s}=e,c=`${t}-tab`;return{[c]:{position:"relative",WebkitTouchCallout:"none",WebkitTapHighlightColor:"transparent",display:"inline-flex",alignItems:"center",padding:a,fontSize:e.titleFontSize,background:"transparent",border:0,outline:"none",cursor:"pointer",color:s,"&-btn, &-remove":Object.assign({"&:focus:not(:focus-visible), &:active":{color:n}},Xd(e)),"&-btn":{outline:"none",transition:"all 0.3s",[`${c}-icon:not(:last-child)`]:{marginInlineEnd:e.marginSM}},"&-remove":{flex:"none",marginRight:{_skip_check_:!0,value:e.calc(e.marginXXS).mul(-1).equal()},marginLeft:{_skip_check_:!0,value:e.marginXS},color:e.colorTextDescription,fontSize:e.fontSizeSM,background:"transparent",border:"none",outline:"none",cursor:"pointer",transition:`all ${e.motionDurationSlow}`,"&:hover":{color:e.colorTextHeading}},"&:hover":{color:r},[`&${c}-active ${c}-btn`]:{color:l,textShadow:e.tabsActiveTextShadow},[`&${c}-disabled`]:{color:e.colorTextDisabled,cursor:"not-allowed"},[`&${c}-disabled ${c}-btn, &${c}-disabled ${t}-remove`]:{"&:focus, &:active":{color:e.colorTextDisabled}},[`& ${c}-remove ${o}`]:{margin:0},[`${o}:not(:last-child)`]:{marginRight:{_skip_check_:!0,value:e.marginSM}}},[`${c} + ${c}`]:{margin:{_skip_check_:!0,value:i}}}},gk=e=>{const{componentCls:t,tabsHorizontalItemMarginRTL:n,iconCls:r,cardGutter:o,calc:i}=e;return{[`${t}-rtl`]:{direction:"rtl",[`${t}-nav`]:{[`${t}-tab`]:{margin:{_skip_check_:!0,value:n},[`${t}-tab:last-of-type`]:{marginLeft:{_skip_check_:!0,value:0}},[r]:{marginRight:{_skip_check_:!0,value:0},marginLeft:{_skip_check_:!0,value:X(e.marginSM)}},[`${t}-tab-remove`]:{marginRight:{_skip_check_:!0,value:X(e.marginXS)},marginLeft:{_skip_check_:!0,value:X(i(e.marginXXS).mul(-1).equal())},[r]:{margin:0}}}},[`&${t}-left`]:{[`> ${t}-nav`]:{order:1},[`> ${t}-content-holder`]:{order:0}},[`&${t}-right`]:{[`> ${t}-nav`]:{order:0},[`> ${t}-content-holder`]:{order:1}},[`&${t}-card${t}-top, &${t}-card${t}-bottom`]:{[`> ${t}-nav, > div > ${t}-nav`]:{[`${t}-tab + ${t}-tab`]:{marginRight:{_skip_check_:!0,value:o},marginLeft:{_skip_check_:!0,value:0}}}}},[`${t}-dropdown-rtl`]:{direction:"rtl"},[`${t}-menu-item`]:{[`${t}-dropdown-rtl`]:{textAlign:{_skip_check_:!0,value:"right"}}}}},hk=e=>{const{componentCls:t,tabsCardPadding:n,cardHeight:r,cardGutter:o,itemHoverColor:i,itemActiveColor:a,colorBorderSecondary:l}=e;return{[t]:Object.assign(Object.assign(Object.assign(Object.assign({},Qt(e)),{display:"flex",[`> ${t}-nav, > div > ${t}-nav`]:{position:"relative",display:"flex",flex:"none",alignItems:"center",[`${t}-nav-wrap`]:{position:"relative",display:"flex",flex:"auto",alignSelf:"stretch",overflow:"hidden",whiteSpace:"nowrap",transform:"translate(0)","&::before, &::after":{position:"absolute",zIndex:1,opacity:0,transition:`opacity ${e.motionDurationSlow}`,content:"''",pointerEvents:"none"}},[`${t}-nav-list`]:{position:"relative",display:"flex",transition:`opacity ${e.motionDurationSlow}`},[`${t}-nav-operations`]:{display:"flex",alignSelf:"stretch"},[`${t}-nav-operations-hidden`]:{position:"absolute",visibility:"hidden",pointerEvents:"none"},[`${t}-nav-more`]:{position:"relative",padding:n,background:"transparent",border:0,color:e.colorText,"&::after":{position:"absolute",right:{_skip_check_:!0,value:0},bottom:0,left:{_skip_check_:!0,value:0},height:e.calc(e.controlHeightLG).div(8).equal(),transform:"translateY(100%)",content:"''"}},[`${t}-nav-add`]:Object.assign({minWidth:r,minHeight:r,marginLeft:{_skip_check_:!0,value:o},padding:`0 ${X(e.paddingXS)}`,background:"transparent",border:`${X(e.lineWidth)} ${e.lineType} ${l}`,borderRadius:`${X(e.borderRadiusLG)} ${X(e.borderRadiusLG)} 0 0`,outline:"none",cursor:"pointer",color:e.colorText,transition:`all ${e.motionDurationSlow} ${e.motionEaseInOut}`,"&:hover":{color:i},"&:active, &:focus:not(:focus-visible)":{color:a}},Xd(e))},[`${t}-extra-content`]:{flex:"none"},[`${t}-ink-bar`]:{position:"absolute",background:e.inkBarColor,pointerEvents:"none"}}),pk(e)),{[`${t}-content`]:{position:"relative",width:"100%"},[`${t}-content-holder`]:{flex:"auto",minWidth:0,minHeight:0},[`${t}-tabpane`]:{outline:"none","&-hidden":{display:"none"}}}),[`${t}-centered`]:{[`> ${t}-nav, > div > ${t}-nav`]:{[`${t}-nav-wrap`]:{[`&:not([class*='${t}-nav-wrap-ping'])`]:{justifyContent:"center"}}}}}},mk=e=>{const t=e.controlHeightLG;return{zIndexPopup:e.zIndexPopupBase+50,cardBg:e.colorFillAlter,cardHeight:t,cardPadding:`${(t-Math.round(e.fontSize*e.lineHeight))/2-e.lineWidth}px ${e.padding}px`,cardPaddingSM:`${e.paddingXXS*1.5}px ${e.padding}px`,cardPaddingLG:`${e.paddingXS}px ${e.padding}px ${e.paddingXXS*1.5}px`,titleFontSize:e.fontSize,titleFontSizeLG:e.fontSizeLG,titleFontSizeSM:e.fontSize,inkBarColor:e.colorPrimary,horizontalMargin:`0 0 ${e.margin}px 0`,horizontalItemGutter:32,horizontalItemMargin:"",horizontalItemMarginRTL:"",horizontalItemPadding:`${e.paddingSM}px 0`,horizontalItemPaddingSM:`${e.paddingXS}px 0`,horizontalItemPaddingLG:`${e.padding}px 0`,verticalItemPadding:`${e.paddingXS}px ${e.paddingLG}px`,verticalItemMargin:`${e.margin}px 0 0 0`,itemColor:e.colorText,itemSelectedColor:e.colorPrimary,itemHoverColor:e.colorPrimaryHover,itemActiveColor:e.colorPrimaryActive,cardGutter:e.marginXXS/2}},yk=vn("Tabs",e=>{const t=$t(e,{tabsCardPadding:e.cardPadding,dropdownEdgeChildVerticalPadding:e.paddingXXS,tabsActiveTextShadow:"0 0 0.25px currentcolor",tabsDropdownHeight:200,tabsDropdownWidth:120,tabsHorizontalItemMargin:`0 0 0 ${X(e.horizontalItemGutter)}`,tabsHorizontalItemMarginRTL:`0 0 0 ${X(e.horizontalItemGutter)}`});return[vk(t),gk(t),fk(t),dk(t),uk(t),hk(t),ck(t)]},mk),bk=()=>null,Sk=bk;var Ck=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{var t,n,r,o,i,a,l;const{type:s,className:c,rootClassName:u,size:d,onEdit:v,hideAdd:h,centered:g,addIcon:p,moreIcon:b,popupClassName:m,children:y,items:S,animated:x,style:$,indicatorSize:E,indicator:w}=e,R=Ck(e,["type","className","rootClassName","size","onEdit","hideAdd","centered","addIcon","moreIcon","popupClassName","children","items","animated","style","indicatorSize","indicator"]),{prefixCls:P}=R,{direction:N,tabs:I,getPrefixCls:z,getPopupContainer:F}=f.exports.useContext(ot),T=z("tabs",P),D=no(T),[_,O,M]=yk(T,D);let L;s==="editable-card"&&(L={onEdit:(Y,K)=>{let{key:q,event:ee}=K;v==null||v(Y==="add"?ee:q,Y)},removeIcon:C(eo,{}),addIcon:(p!=null?p:I==null?void 0:I.addIcon)||C(BP,{}),showAdd:h!==!0});const A=z(),B=So(d),k=lk(S,y),j=ok(T,x),H=Object.assign(Object.assign({},I==null?void 0:I.style),$),W={align:(t=w==null?void 0:w.align)!==null&&t!==void 0?t:(n=I==null?void 0:I.indicator)===null||n===void 0?void 0:n.align,size:(a=(o=(r=w==null?void 0:w.size)!==null&&r!==void 0?r:E)!==null&&o!==void 0?o:(i=I==null?void 0:I.indicator)===null||i===void 0?void 0:i.size)!==null&&a!==void 0?a:I==null?void 0:I.indicatorSize};return _(C(nk,{...Object.assign({direction:N,getPopupContainer:F,moreTransitionName:`${A}-slide-up`},R,{items:k,className:te({[`${T}-${B}`]:B,[`${T}-card`]:["card","editable-card"].includes(s),[`${T}-editable-card`]:s==="editable-card",[`${T}-centered`]:g},I==null?void 0:I.className,c,u,O,M,D),popupClassName:te(m,O,M,D),style:H,editable:L,moreIcon:(l=b!=null?b:I==null?void 0:I.moreIcon)!==null&&l!==void 0?l:C(JI,{}),prefixCls:T,animated:j,indicator:W})}))};g$.TabPane=Sk;const xk=g$;var wk=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{var{prefixCls:t,className:n,hoverable:r=!0}=e,o=wk(e,["prefixCls","className","hoverable"]);const{getPrefixCls:i}=f.exports.useContext(ot),a=i("card",t),l=te(`${a}-grid`,n,{[`${a}-grid-hoverable`]:r});return C("div",{...Object.assign({},o,{className:l})})},h$=$k,Ek=e=>{const{antCls:t,componentCls:n,headerHeight:r,cardPaddingBase:o,tabsMarginBottom:i}=e;return Object.assign(Object.assign({display:"flex",justifyContent:"center",flexDirection:"column",minHeight:r,marginBottom:-1,padding:`0 ${X(o)}`,color:e.colorTextHeading,fontWeight:e.fontWeightStrong,fontSize:e.headerFontSize,background:e.headerBg,borderBottom:`${X(e.lineWidth)} ${e.lineType} ${e.colorBorderSecondary}`,borderRadius:`${X(e.borderRadiusLG)} ${X(e.borderRadiusLG)} 0 0`},Us()),{"&-wrapper":{width:"100%",display:"flex",alignItems:"center"},"&-title":Object.assign(Object.assign({display:"inline-block",flex:1},ei),{[` + > ${n}-typography, + > ${n}-typography-edit-content + `]:{insetInlineStart:0,marginTop:0,marginBottom:0}}),[`${t}-tabs-top`]:{clear:"both",marginBottom:i,color:e.colorText,fontWeight:"normal",fontSize:e.fontSize,"&-bar":{borderBottom:`${X(e.lineWidth)} ${e.lineType} ${e.colorBorderSecondary}`}}})},Mk=e=>{const{cardPaddingBase:t,colorBorderSecondary:n,cardShadow:r,lineWidth:o}=e;return{width:"33.33%",padding:t,border:0,borderRadius:0,boxShadow:` + ${X(o)} 0 0 0 ${n}, + 0 ${X(o)} 0 0 ${n}, + ${X(o)} ${X(o)} 0 0 ${n}, + ${X(o)} 0 0 0 ${n} inset, + 0 ${X(o)} 0 0 ${n} inset; + `,transition:`all ${e.motionDurationMid}`,"&-hoverable:hover":{position:"relative",zIndex:1,boxShadow:r}}},Ok=e=>{const{componentCls:t,iconCls:n,actionsLiMargin:r,cardActionsIconSize:o,colorBorderSecondary:i,actionsBg:a}=e;return Object.assign(Object.assign({margin:0,padding:0,listStyle:"none",background:a,borderTop:`${X(e.lineWidth)} ${e.lineType} ${i}`,display:"flex",borderRadius:`0 0 ${X(e.borderRadiusLG)} ${X(e.borderRadiusLG)}`},Us()),{"& > li":{margin:r,color:e.colorTextDescription,textAlign:"center","> span":{position:"relative",display:"block",minWidth:e.calc(e.cardActionsIconSize).mul(2).equal(),fontSize:e.fontSize,lineHeight:e.lineHeight,cursor:"pointer","&:hover":{color:e.colorPrimary,transition:`color ${e.motionDurationMid}`},[`a:not(${t}-btn), > ${n}`]:{display:"inline-block",width:"100%",color:e.colorTextDescription,lineHeight:X(e.fontHeight),transition:`color ${e.motionDurationMid}`,"&:hover":{color:e.colorPrimary}},[`> ${n}`]:{fontSize:o,lineHeight:X(e.calc(o).mul(e.lineHeight).equal())}},"&:not(:last-child)":{borderInlineEnd:`${X(e.lineWidth)} ${e.lineType} ${i}`}}})},Rk=e=>Object.assign(Object.assign({margin:`${X(e.calc(e.marginXXS).mul(-1).equal())} 0`,display:"flex"},Us()),{"&-avatar":{paddingInlineEnd:e.padding},"&-detail":{overflow:"hidden",flex:1,"> div:not(:last-child)":{marginBottom:e.marginXS}},"&-title":Object.assign({color:e.colorTextHeading,fontWeight:e.fontWeightStrong,fontSize:e.fontSizeLG},ei),"&-description":{color:e.colorTextDescription}}),Ik=e=>{const{componentCls:t,cardPaddingBase:n,colorFillAlter:r}=e;return{[`${t}-head`]:{padding:`0 ${X(n)}`,background:r,"&-title":{fontSize:e.fontSize}},[`${t}-body`]:{padding:`${X(e.padding)} ${X(n)}`}}},Pk=e=>{const{componentCls:t}=e;return{overflow:"hidden",[`${t}-body`]:{userSelect:"none"}}},Tk=e=>{const{antCls:t,componentCls:n,cardShadow:r,cardHeadPadding:o,colorBorderSecondary:i,boxShadowTertiary:a,cardPaddingBase:l,extraColor:s}=e;return{[n]:Object.assign(Object.assign({},Qt(e)),{position:"relative",background:e.colorBgContainer,borderRadius:e.borderRadiusLG,[`&:not(${n}-bordered)`]:{boxShadow:a},[`${n}-head`]:Ek(e),[`${n}-extra`]:{marginInlineStart:"auto",color:s,fontWeight:"normal",fontSize:e.fontSize},[`${n}-body`]:Object.assign({padding:l,borderRadius:` 0 0 ${X(e.borderRadiusLG)} ${X(e.borderRadiusLG)}`},Us()),[`${n}-grid`]:Mk(e),[`${n}-cover`]:{"> *":{display:"block",width:"100%"},[`img, img + ${t}-image-mask`]:{borderRadius:`${X(e.borderRadiusLG)} ${X(e.borderRadiusLG)} 0 0`}},[`${n}-actions`]:Ok(e),[`${n}-meta`]:Rk(e)}),[`${n}-bordered`]:{border:`${X(e.lineWidth)} ${e.lineType} ${i}`,[`${n}-cover`]:{marginTop:-1,marginInlineStart:-1,marginInlineEnd:-1}},[`${n}-hoverable`]:{cursor:"pointer",transition:`box-shadow ${e.motionDurationMid}, border-color ${e.motionDurationMid}`,"&:hover":{borderColor:"transparent",boxShadow:r}},[`${n}-contain-grid`]:{borderRadius:`${X(e.borderRadiusLG)} ${X(e.borderRadiusLG)} 0 0 `,[`${n}-body`]:{display:"flex",flexWrap:"wrap"},[`&:not(${n}-loading) ${n}-body`]:{marginBlockStart:e.calc(e.lineWidth).mul(-1).equal(),marginInlineStart:e.calc(e.lineWidth).mul(-1).equal(),padding:0}},[`${n}-contain-tabs`]:{[`> ${n}-head`]:{minHeight:0,[`${n}-head-title, ${n}-extra`]:{paddingTop:o}}},[`${n}-type-inner`]:Ik(e),[`${n}-loading`]:Pk(e),[`${n}-rtl`]:{direction:"rtl"}}},Nk=e=>{const{componentCls:t,cardPaddingSM:n,headerHeightSM:r,headerFontSizeSM:o}=e;return{[`${t}-small`]:{[`> ${t}-head`]:{minHeight:r,padding:`0 ${X(n)}`,fontSize:o,[`> ${t}-head-wrapper`]:{[`> ${t}-extra`]:{fontSize:e.fontSize}}},[`> ${t}-body`]:{padding:n}},[`${t}-small${t}-contain-tabs`]:{[`> ${t}-head`]:{[`${t}-head-title, ${t}-extra`]:{paddingTop:0,display:"flex",alignItems:"center"}}}}},_k=e=>({headerBg:"transparent",headerFontSize:e.fontSizeLG,headerFontSizeSM:e.fontSize,headerHeight:e.fontSizeLG*e.lineHeightLG+e.padding*2,headerHeightSM:e.fontSize*e.lineHeight+e.paddingXS*2,actionsBg:e.colorBgContainer,actionsLiMargin:`${e.paddingSM}px 0`,tabsMarginBottom:-e.padding-e.lineWidth,extraColor:e.colorText}),Ak=vn("Card",e=>{const t=$t(e,{cardShadow:e.boxShadowCard,cardHeadPadding:e.padding,cardPaddingBase:e.paddingLG,cardActionsIconSize:e.fontSize,cardPaddingSM:12});return[Tk(t),Nk(t)]},_k);var i1=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{const{actionClasses:t,actions:n=[],actionStyle:r}=e;return C("ul",{className:t,style:r,children:n.map((o,i)=>{const a=`action-${i}`;return C("li",{style:{width:`${100/n.length}%`},children:C("span",{children:o})},a)})})},Lk=f.exports.forwardRef((e,t)=>{const{prefixCls:n,className:r,rootClassName:o,style:i,extra:a,headStyle:l={},bodyStyle:s={},title:c,loading:u,bordered:d=!0,size:v,type:h,cover:g,actions:p,tabList:b,children:m,activeTabKey:y,defaultActiveTabKey:S,tabBarExtraContent:x,hoverable:$,tabProps:E={},classNames:w,styles:R}=e,P=i1(e,["prefixCls","className","rootClassName","style","extra","headStyle","bodyStyle","title","loading","bordered","size","type","cover","actions","tabList","children","activeTabKey","defaultActiveTabKey","tabBarExtraContent","hoverable","tabProps","classNames","styles"]),{getPrefixCls:N,direction:I,card:z}=f.exports.useContext(ot),F=pe=>{var oe;(oe=e.onTabChange)===null||oe===void 0||oe.call(e,pe)},T=pe=>{var oe;return te((oe=z==null?void 0:z.classNames)===null||oe===void 0?void 0:oe[pe],w==null?void 0:w[pe])},D=pe=>{var oe;return Object.assign(Object.assign({},(oe=z==null?void 0:z.styles)===null||oe===void 0?void 0:oe[pe]),R==null?void 0:R[pe])},_=f.exports.useMemo(()=>{let pe=!1;return f.exports.Children.forEach(m,oe=>{oe&&oe.type&&oe.type===h$&&(pe=!0)}),pe},[m]),O=N("card",n),[M,L,A]=Ak(O),B=C(zF,{loading:!0,active:!0,paragraph:{rows:4},title:!1,children:m}),k=y!==void 0,j=Object.assign(Object.assign({},E),{[k?"activeKey":"defaultActiveKey"]:k?y:S,tabBarExtraContent:x});let H;const W=So(v),K=b?C(xk,{...Object.assign({size:!W||W==="default"?"large":W},j,{className:`${O}-head-tabs`,onChange:F,items:b.map(pe=>{var{tab:oe}=pe,se=i1(pe,["tab"]);return Object.assign({label:oe},se)})})}):null;if(c||a||K){const pe=te(`${O}-head`,T("header")),oe=te(`${O}-head-title`,T("title")),se=te(`${O}-extra`,T("extra")),le=Object.assign(Object.assign({},l),D("header"));H=ie("div",{className:pe,style:le,children:[ie("div",{className:`${O}-head-wrapper`,children:[c&&C("div",{className:oe,style:D("title"),children:c}),a&&C("div",{className:se,style:D("extra"),children:a})]}),K]})}const q=te(`${O}-cover`,T("cover")),ee=g?C("div",{className:q,style:D("cover"),children:g}):null,Z=te(`${O}-body`,T("body")),Q=Object.assign(Object.assign({},s),D("body")),ne=C("div",{className:Z,style:Q,children:u?B:m}),ae=te(`${O}-actions`,T("actions")),J=p&&p.length?C(Dk,{actionClasses:ae,actionStyle:D("actions"),actions:p}):null,re=lr(P,["onTabChange"]),fe=te(O,z==null?void 0:z.className,{[`${O}-loading`]:u,[`${O}-bordered`]:d,[`${O}-hoverable`]:$,[`${O}-contain-grid`]:_,[`${O}-contain-tabs`]:b&&b.length,[`${O}-${W}`]:W,[`${O}-type-${h}`]:!!h,[`${O}-rtl`]:I==="rtl"},r,o,L,A),ve=Object.assign(Object.assign({},z==null?void 0:z.style),i);return M(ie("div",{...Object.assign({ref:t},re,{className:fe,style:ve}),children:[H,ee,ne,J]}))}),zk=Lk;var Fk=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{const{prefixCls:t,className:n,avatar:r,title:o,description:i}=e,a=Fk(e,["prefixCls","className","avatar","title","description"]),{getPrefixCls:l}=f.exports.useContext(ot),s=l("card",t),c=te(`${s}-meta`,n),u=r?C("div",{className:`${s}-meta-avatar`,children:r}):null,d=o?C("div",{className:`${s}-meta-title`,children:o}):null,v=i?C("div",{className:`${s}-meta-description`,children:i}):null,h=d||v?ie("div",{className:`${s}-meta-detail`,children:[d,v]}):null;return ie("div",{...Object.assign({},a,{className:c}),children:[u,h]})},Bk=kk,Pm=zk;Pm.Grid=h$;Pm.Meta=Bk;const m$=Pm;function jk(e,t,n){var r=n||{},o=r.noTrailing,i=o===void 0?!1:o,a=r.noLeading,l=a===void 0?!1:a,s=r.debounceMode,c=s===void 0?void 0:s,u,d=!1,v=0;function h(){u&&clearTimeout(u)}function g(b){var m=b||{},y=m.upcomingOnly,S=y===void 0?!1:y;h(),d=!S}function p(){for(var b=arguments.length,m=new Array(b),y=0;ye?l?(v=Date.now(),i||(u=setTimeout(c?E:$,e))):$():i!==!0&&(u=setTimeout(c?E:$,c===void 0?e-x:e))}return p.cancel=g,p}function Hk(e,t,n){var r=n||{},o=r.atBegin,i=o===void 0?!1:o;return jk(e,t,{debounceMode:i!==!1})}function Wk(e){return!!(e.addonBefore||e.addonAfter)}function Vk(e){return!!(e.prefix||e.suffix||e.allowClear)}function od(e,t,n,r){if(!!n){var o=t;if(t.type==="click"){var i=e.cloneNode(!0);o=Object.create(t,{target:{value:i},currentTarget:{value:i}}),i.value="",n(o);return}if(e.type!=="file"&&r!==void 0){var a=e.cloneNode(!0);o=Object.create(t,{target:{value:a},currentTarget:{value:a}}),a.value=r,n(o);return}n(o)}}function Uk(e,t){if(!!e){e.focus(t);var n=t||{},r=n.cursor;if(r){var o=e.value.length;switch(r){case"start":e.setSelectionRange(0,0);break;case"end":e.setSelectionRange(o,o);break;default:e.setSelectionRange(0,o)}}}}var y$=function(t){var n,r,o=t.inputElement,i=t.children,a=t.prefixCls,l=t.prefix,s=t.suffix,c=t.addonBefore,u=t.addonAfter,d=t.className,v=t.style,h=t.disabled,g=t.readOnly,p=t.focused,b=t.triggerFocus,m=t.allowClear,y=t.value,S=t.handleReset,x=t.hidden,$=t.classes,E=t.classNames,w=t.dataAttrs,R=t.styles,P=t.components,N=i!=null?i:o,I=(P==null?void 0:P.affixWrapper)||"span",z=(P==null?void 0:P.groupWrapper)||"span",F=(P==null?void 0:P.wrapper)||"span",T=(P==null?void 0:P.groupAddon)||"span",D=f.exports.useRef(null),_=function(J){var re;(re=D.current)!==null&&re!==void 0&&re.contains(J.target)&&(b==null||b())},O=Vk(t),M=f.exports.cloneElement(N,{value:y,className:te(N.props.className,!O&&(E==null?void 0:E.variant))||null});if(O){var L,A=null;if(m){var B,k=!h&&!g&&y,j="".concat(a,"-clear-icon"),H=Qe(m)==="object"&&m!==null&&m!==void 0&&m.clearIcon?m.clearIcon:"\u2716";A=C("span",{onClick:S,onMouseDown:function(J){return J.preventDefault()},className:te(j,(B={},V(B,"".concat(j,"-hidden"),!k),V(B,"".concat(j,"-has-suffix"),!!s),B)),role:"button",tabIndex:-1,children:H})}var W="".concat(a,"-affix-wrapper"),Y=te(W,(L={},V(L,"".concat(a,"-disabled"),h),V(L,"".concat(W,"-disabled"),h),V(L,"".concat(W,"-focused"),p),V(L,"".concat(W,"-readonly"),g),V(L,"".concat(W,"-input-with-clear-btn"),s&&m&&y),L),$==null?void 0:$.affixWrapper,E==null?void 0:E.affixWrapper,E==null?void 0:E.variant),K=(s||m)&&ie("span",{className:te("".concat(a,"-suffix"),E==null?void 0:E.suffix),style:R==null?void 0:R.suffix,children:[A,s]});M=ie(I,{className:Y,style:R==null?void 0:R.affixWrapper,onClick:_,...w==null?void 0:w.affixWrapper,ref:D,children:[l&&C("span",{className:te("".concat(a,"-prefix"),E==null?void 0:E.prefix),style:R==null?void 0:R.prefix,children:l}),M,K]})}if(Wk(t)){var q="".concat(a,"-group"),ee="".concat(q,"-addon"),Z="".concat(q,"-wrapper"),Q=te("".concat(a,"-wrapper"),q,$==null?void 0:$.wrapper,E==null?void 0:E.wrapper),ne=te(Z,V({},"".concat(Z,"-disabled"),h),$==null?void 0:$.group,E==null?void 0:E.groupWrapper);M=C(z,{className:ne,children:ie(F,{className:Q,children:[c&&C(T,{className:ee,children:c}),M,u&&C(T,{className:ee,children:u})]})})}return lt.cloneElement(M,{className:te((n=M.props)===null||n===void 0?void 0:n.className,d)||null,style:U(U({},(r=M.props)===null||r===void 0?void 0:r.style),v),hidden:x})},Yk=["show"];function b$(e,t){return f.exports.useMemo(function(){var n={};t&&(n.show=Qe(t)==="object"&&t.formatter?t.formatter:!!t),n=U(U({},n),e);var r=n,o=r.show,i=Je(r,Yk);return U(U({},i),{},{show:!!o,showFormatter:typeof o=="function"?o:void 0,strategy:i.strategy||function(a){return a.length}})},[e,t])}var Gk=["autoComplete","onChange","onFocus","onBlur","onPressEnter","onKeyDown","prefixCls","disabled","htmlSize","className","maxLength","suffix","showCount","count","type","classes","classNames","styles","onCompositionStart","onCompositionEnd"],Kk=f.exports.forwardRef(function(e,t){var n=e.autoComplete,r=e.onChange,o=e.onFocus,i=e.onBlur,a=e.onPressEnter,l=e.onKeyDown,s=e.prefixCls,c=s===void 0?"rc-input":s,u=e.disabled,d=e.htmlSize,v=e.className,h=e.maxLength,g=e.suffix,p=e.showCount,b=e.count,m=e.type,y=m===void 0?"text":m,S=e.classes,x=e.classNames,$=e.styles,E=e.onCompositionStart,w=e.onCompositionEnd,R=Je(e,Gk),P=f.exports.useState(!1),N=G(P,2),I=N[0],z=N[1],F=f.exports.useRef(!1),T=f.exports.useRef(null),D=function(se){T.current&&Uk(T.current,se)},_=kt(e.defaultValue,{value:e.value}),O=G(_,2),M=O[0],L=O[1],A=M==null?"":String(M),B=f.exports.useState(null),k=G(B,2),j=k[0],H=k[1],W=b$(b,p),Y=W.max||h,K=W.strategy(A),q=!!Y&&K>Y;f.exports.useImperativeHandle(t,function(){return{focus:D,blur:function(){var se;(se=T.current)===null||se===void 0||se.blur()},setSelectionRange:function(se,le,Ce){var ce;(ce=T.current)===null||ce===void 0||ce.setSelectionRange(se,le,Ce)},select:function(){var se;(se=T.current)===null||se===void 0||se.select()},input:T.current}}),f.exports.useEffect(function(){z(function(oe){return oe&&u?!1:oe})},[u]);var ee=function(se,le,Ce){var ce=le;if(!F.current&&W.exceedFormatter&&W.max&&W.strategy(le)>W.max){if(ce=W.exceedFormatter(le,{max:W.max}),le!==ce){var de,xe;H([((de=T.current)===null||de===void 0?void 0:de.selectionStart)||0,((xe=T.current)===null||xe===void 0?void 0:xe.selectionEnd)||0])}}else if(Ce.source==="compositionEnd")return;L(ce),T.current&&od(T.current,se,r,ce)};f.exports.useEffect(function(){if(j){var oe;(oe=T.current)===null||oe===void 0||oe.setSelectionRange.apply(oe,Oe(j))}},[j]);var Z=function(se){ee(se,se.target.value,{source:"change"})},Q=function(se){F.current=!1,ee(se,se.currentTarget.value,{source:"compositionEnd"}),w==null||w(se)},ne=function(se){a&&se.key==="Enter"&&a(se),l==null||l(se)},ae=function(se){z(!0),o==null||o(se)},J=function(se){z(!1),i==null||i(se)},re=function(se){L(""),D(),T.current&&od(T.current,se,r)},fe=q&&"".concat(c,"-out-of-range"),ve=function(){var se=lr(e,["prefixCls","onPressEnter","addonBefore","addonAfter","prefix","suffix","allowClear","defaultValue","showCount","count","classes","htmlSize","styles","classNames"]);return C("input",{autoComplete:n,...se,onChange:Z,onFocus:ae,onBlur:J,onKeyDown:ne,className:te(c,V({},"".concat(c,"-disabled"),u),x==null?void 0:x.input),style:$==null?void 0:$.input,ref:T,size:d,type:y,onCompositionStart:function(Ce){F.current=!0,E==null||E(Ce)},onCompositionEnd:Q})},pe=function(){var se=Number(Y)>0;if(g||W.show){var le=W.showFormatter?W.showFormatter({value:A,count:K,maxLength:Y}):"".concat(K).concat(se?" / ".concat(Y):"");return ie(Tt,{children:[W.show&&C("span",{className:te("".concat(c,"-show-count-suffix"),V({},"".concat(c,"-show-count-has-suffix"),!!g),x==null?void 0:x.count),style:U({},$==null?void 0:$.count),children:le}),g]})}return null};return C(y$,{...R,prefixCls:c,className:te(v,fe),handleReset:re,value:A,focused:I,triggerFocus:D,suffix:pe(),disabled:u,classes:S,classNames:x,styles:$,children:ve()})});const qk=e=>{const{getPrefixCls:t,direction:n}=f.exports.useContext(ot),{prefixCls:r,className:o}=e,i=t("input-group",r),a=t("input"),[l,s]=Im(a),c=te(i,{[`${i}-lg`]:e.size==="large",[`${i}-sm`]:e.size==="small",[`${i}-compact`]:e.compact,[`${i}-rtl`]:n==="rtl"},s,o),u=f.exports.useContext(Jr),d=f.exports.useMemo(()=>Object.assign(Object.assign({},u),{isFormItemInput:!1}),[u]);return l(C("span",{className:c,style:e.style,onMouseEnter:e.onMouseEnter,onMouseLeave:e.onMouseLeave,onFocus:e.onFocus,onBlur:e.onBlur,children:C(Jr.Provider,{value:d,children:e.children})}))},Xk=qk;function S$(e,t){const n=f.exports.useRef([]),r=()=>{n.current.push(setTimeout(()=>{var o,i,a,l;((o=e.current)===null||o===void 0?void 0:o.input)&&((i=e.current)===null||i===void 0?void 0:i.input.getAttribute("type"))==="password"&&((a=e.current)===null||a===void 0?void 0:a.input.hasAttribute("value"))&&((l=e.current)===null||l===void 0||l.input.removeAttribute("value"))}))};return f.exports.useEffect(()=>(t&&r(),()=>n.current.forEach(o=>{o&&clearTimeout(o)})),[]),r}function Qk(e){return!!(e.prefix||e.suffix||e.allowClear||e.showCount)}const Zk=e=>{let t;return typeof e=="object"&&(e==null?void 0:e.clearIcon)?t=e:e&&(t={clearIcon:C(Nd,{})}),t},Jk=Zk;var e7=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{var n;const{prefixCls:r,bordered:o=!0,status:i,size:a,disabled:l,onBlur:s,onFocus:c,suffix:u,allowClear:d,addonAfter:v,addonBefore:h,className:g,style:p,styles:b,rootClassName:m,onChange:y,classNames:S,variant:x}=e,$=e7(e,["prefixCls","bordered","status","size","disabled","onBlur","onFocus","suffix","allowClear","addonAfter","addonBefore","className","style","styles","rootClassName","onChange","classNames","variant"]),{getPrefixCls:E,direction:w,input:R}=lt.useContext(ot),P=E("input",r),N=f.exports.useRef(null),I=no(P),[z,F,T]=Im(P,I),{compactSize:D,compactItemClassnames:_}=ef(P,w),O=So(ae=>{var J;return(J=a!=null?a:D)!==null&&J!==void 0?J:ae}),M=lt.useContext(rl),L=l!=null?l:M,{status:A,hasFeedback:B,feedbackIcon:k}=f.exports.useContext(Jr),j=dm(A,i),H=Qk(e)||!!B;f.exports.useRef(H);const W=S$(N,!0),Y=ae=>{W(),s==null||s(ae)},K=ae=>{W(),c==null||c(ae)},q=ae=>{W(),y==null||y(ae)},ee=(B||u)&&ie(Tt,{children:[u,B&&k]}),Z=Jk(d),[Q,ne]=vm(x,o);return z(C(Kk,{...Object.assign({ref:xr(t,N),prefixCls:P,autoComplete:R==null?void 0:R.autoComplete},$,{disabled:L,onBlur:Y,onFocus:K,style:Object.assign(Object.assign({},R==null?void 0:R.style),p),styles:Object.assign(Object.assign({},R==null?void 0:R.styles),b),suffix:ee,allowClear:Z,className:te(g,m,T,I,_,R==null?void 0:R.className),onChange:q,addonAfter:v&&C(ig,{children:C(db,{override:!0,status:!0,children:v})}),addonBefore:h&&C(ig,{children:C(db,{override:!0,status:!0,children:h})}),classNames:Object.assign(Object.assign(Object.assign({},S),R==null?void 0:R.classNames),{input:te({[`${P}-sm`]:O==="small",[`${P}-lg`]:O==="large",[`${P}-rtl`]:w==="rtl"},S==null?void 0:S.input,(n=R==null?void 0:R.classNames)===null||n===void 0?void 0:n.input,F),variant:te({[`${P}-${Q}`]:ne},ed(P,j)),affixWrapper:te({[`${P}-affix-wrapper-sm`]:O==="small",[`${P}-affix-wrapper-lg`]:O==="large",[`${P}-affix-wrapper-rtl`]:w==="rtl"},F),wrapper:te({[`${P}-group-rtl`]:w==="rtl"},F),groupWrapper:te({[`${P}-group-wrapper-sm`]:O==="small",[`${P}-group-wrapper-lg`]:O==="large",[`${P}-group-wrapper-rtl`]:w==="rtl",[`${P}-group-wrapper-${Q}`]:ne},ed(`${P}-group-wrapper`,j,B),F)})})}))}),Tm=n7;var r7=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);oe?C(sx,{}):C(rP,{}),i7={click:"onClick",hover:"onMouseOver"},a7=f.exports.forwardRef((e,t)=>{const{visibilityToggle:n=!0}=e,r=typeof n=="object"&&n.visible!==void 0,[o,i]=f.exports.useState(()=>r?n.visible:!1),a=f.exports.useRef(null);f.exports.useEffect(()=>{r&&i(n.visible)},[r,n]);const l=S$(a),s=()=>{const{disabled:$}=e;$||(o&&l(),i(E=>{var w;const R=!E;return typeof n=="object"&&((w=n.onVisibleChange)===null||w===void 0||w.call(n,R)),R}))},c=$=>{const{action:E="click",iconRender:w=o7}=e,R=i7[E]||"",P=w(o),N={[R]:s,className:`${$}-icon`,key:"passwordIcon",onMouseDown:I=>{I.preventDefault()},onMouseUp:I=>{I.preventDefault()}};return f.exports.cloneElement(f.exports.isValidElement(P)?P:C("span",{children:P}),N)},{className:u,prefixCls:d,inputPrefixCls:v,size:h}=e,g=r7(e,["className","prefixCls","inputPrefixCls","size"]),{getPrefixCls:p}=f.exports.useContext(ot),b=p("input",v),m=p("input-password",d),y=n&&c(m),S=te(m,u,{[`${m}-${h}`]:!!h}),x=Object.assign(Object.assign({},lr(g,["suffix","iconRender","visibilityToggle"])),{type:o?"text":"password",className:S,prefixCls:b,suffix:y});return h&&(x.size=h),C(Tm,{...Object.assign({ref:xr(t,a)},x)})}),l7=a7;var s7=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{const{prefixCls:n,inputPrefixCls:r,className:o,size:i,suffix:a,enterButton:l=!1,addonAfter:s,loading:c,disabled:u,onSearch:d,onChange:v,onCompositionStart:h,onCompositionEnd:g}=e,p=s7(e,["prefixCls","inputPrefixCls","className","size","suffix","enterButton","addonAfter","loading","disabled","onSearch","onChange","onCompositionStart","onCompositionEnd"]),{getPrefixCls:b,direction:m}=f.exports.useContext(ot),y=f.exports.useRef(!1),S=b("input-search",n),x=b("input",r),{compactSize:$}=ef(S,m),E=So(A=>{var B;return(B=i!=null?i:$)!==null&&B!==void 0?B:A}),w=f.exports.useRef(null),R=A=>{A&&A.target&&A.type==="click"&&d&&d(A.target.value,A,{source:"clear"}),v&&v(A)},P=A=>{var B;document.activeElement===((B=w.current)===null||B===void 0?void 0:B.input)&&A.preventDefault()},N=A=>{var B,k;d&&d((k=(B=w.current)===null||B===void 0?void 0:B.input)===null||k===void 0?void 0:k.value,A,{source:"input"})},I=A=>{y.current||c||N(A)},z=typeof l=="boolean"?C(_d,{}):null,F=`${S}-button`;let T;const D=l||{},_=D.type&&D.type.__ANT_BUTTON===!0;_||D.type==="button"?T=ti(D,Object.assign({onMouseDown:P,onClick:A=>{var B,k;(k=(B=D==null?void 0:D.props)===null||B===void 0?void 0:B.onClick)===null||k===void 0||k.call(B,A),N(A)},key:"enterButton"},_?{className:F,size:E}:{})):T=C(Xu,{className:F,type:l?"primary":void 0,size:E,disabled:u,onMouseDown:P,onClick:N,loading:c,icon:z,children:l},"enterButton"),s&&(T=[T,ti(s,{key:"addonAfter"})]);const O=te(S,{[`${S}-rtl`]:m==="rtl",[`${S}-${E}`]:!!E,[`${S}-with-button`]:!!l},o),M=A=>{y.current=!0,h==null||h(A)},L=A=>{y.current=!1,g==null||g(A)};return C(Tm,{...Object.assign({ref:xr(w,t),onPressEnter:I},p,{size:E,onCompositionStart:M,onCompositionEnd:L,prefixCls:x,addonAfter:T,suffix:a,onChange:R,className:O,disabled:u})})}),u7=c7;var d7=` + min-height:0 !important; + max-height:none !important; + height:0 !important; + visibility:hidden !important; + overflow:hidden !important; + position:absolute !important; + z-index:-1000 !important; + top:0 !important; + right:0 !important; + pointer-events: none !important; +`,f7=["letter-spacing","line-height","padding-top","padding-bottom","font-family","font-weight","font-size","font-variant","text-rendering","text-transform","width","text-indent","padding-left","padding-right","border-width","box-sizing","word-break","white-space"],Ev={},dr;function v7(e){var t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1,n=e.getAttribute("id")||e.getAttribute("data-reactid")||e.getAttribute("name");if(t&&Ev[n])return Ev[n];var r=window.getComputedStyle(e),o=r.getPropertyValue("box-sizing")||r.getPropertyValue("-moz-box-sizing")||r.getPropertyValue("-webkit-box-sizing"),i=parseFloat(r.getPropertyValue("padding-bottom"))+parseFloat(r.getPropertyValue("padding-top")),a=parseFloat(r.getPropertyValue("border-bottom-width"))+parseFloat(r.getPropertyValue("border-top-width")),l=f7.map(function(c){return"".concat(c,":").concat(r.getPropertyValue(c))}).join(";"),s={sizingStyle:l,paddingSize:i,borderSize:a,boxSizing:o};return t&&n&&(Ev[n]=s),s}function p7(e){var t=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1,n=arguments.length>2&&arguments[2]!==void 0?arguments[2]:null,r=arguments.length>3&&arguments[3]!==void 0?arguments[3]:null;dr||(dr=document.createElement("textarea"),dr.setAttribute("tab-index","-1"),dr.setAttribute("aria-hidden","true"),document.body.appendChild(dr)),e.getAttribute("wrap")?dr.setAttribute("wrap",e.getAttribute("wrap")):dr.removeAttribute("wrap");var o=v7(e,t),i=o.paddingSize,a=o.borderSize,l=o.boxSizing,s=o.sizingStyle;dr.setAttribute("style","".concat(s,";").concat(d7)),dr.value=e.value||e.placeholder||"";var c=void 0,u=void 0,d,v=dr.scrollHeight;if(l==="border-box"?v+=a:l==="content-box"&&(v-=i),n!==null||r!==null){dr.value=" ";var h=dr.scrollHeight-i;n!==null&&(c=h*n,l==="border-box"&&(c=c+i+a),v=Math.max(c,v)),r!==null&&(u=h*r,l==="border-box"&&(u=u+i+a),d=v>u?"":"hidden",v=Math.min(u,v))}var g={height:v,overflowY:d,resize:"none"};return c&&(g.minHeight=c),u&&(g.maxHeight=u),g}var g7=["prefixCls","onPressEnter","defaultValue","value","autoSize","onResize","className","style","disabled","onChange","onInternalAutoSize"],Mv=0,Ov=1,Rv=2,h7=f.exports.forwardRef(function(e,t){var n=e,r=n.prefixCls;n.onPressEnter;var o=n.defaultValue,i=n.value,a=n.autoSize,l=n.onResize,s=n.className,c=n.style,u=n.disabled,d=n.onChange;n.onInternalAutoSize;var v=Je(n,g7),h=kt(o,{value:i,postState:function(H){return H!=null?H:""}}),g=G(h,2),p=g[0],b=g[1],m=function(H){b(H.target.value),d==null||d(H)},y=f.exports.useRef();f.exports.useImperativeHandle(t,function(){return{textArea:y.current}});var S=f.exports.useMemo(function(){return a&&Qe(a)==="object"?[a.minRows,a.maxRows]:[]},[a]),x=G(S,2),$=x[0],E=x[1],w=!!a,R=function(){try{if(document.activeElement===y.current){var H=y.current,W=H.selectionStart,Y=H.selectionEnd,K=H.scrollTop;y.current.setSelectionRange(W,Y),y.current.scrollTop=K}}catch{}},P=f.exports.useState(Rv),N=G(P,2),I=N[0],z=N[1],F=f.exports.useState(),T=G(F,2),D=T[0],_=T[1],O=function(){z(Mv)};Nt(function(){w&&O()},[i,$,E,w]),Nt(function(){if(I===Mv)z(Ov);else if(I===Ov){var j=p7(y.current,!1,$,E);z(Rv),_(j)}else R()},[I]);var M=f.exports.useRef(),L=function(){St.cancel(M.current)},A=function(H){I===Rv&&(l==null||l(H),a&&(L(),M.current=St(function(){O()})))};f.exports.useEffect(function(){return L},[]);var B=w?D:null,k=U(U({},c),B);return(I===Mv||I===Ov)&&(k.overflowY="hidden",k.overflowX="hidden"),C(mr,{onResize:A,disabled:!(a||l),children:C("textarea",{...v,ref:y,style:k,className:te(r,s,V({},"".concat(r,"-disabled"),u)),disabled:u,value:p,onChange:m})})}),m7=["defaultValue","value","onFocus","onBlur","onChange","allowClear","maxLength","onCompositionStart","onCompositionEnd","suffix","prefixCls","showCount","count","className","style","disabled","hidden","classNames","styles","onResize"],y7=lt.forwardRef(function(e,t){var n,r,o=e.defaultValue,i=e.value,a=e.onFocus,l=e.onBlur,s=e.onChange,c=e.allowClear,u=e.maxLength,d=e.onCompositionStart,v=e.onCompositionEnd,h=e.suffix,g=e.prefixCls,p=g===void 0?"rc-textarea":g,b=e.showCount,m=e.count,y=e.className,S=e.style,x=e.disabled,$=e.hidden,E=e.classNames,w=e.styles,R=e.onResize,P=Je(e,m7),N=kt(o,{value:i,defaultValue:o}),I=G(N,2),z=I[0],F=I[1],T=z==null?"":String(z),D=lt.useState(!1),_=G(D,2),O=_[0],M=_[1],L=lt.useRef(!1),A=lt.useState(null),B=G(A,2),k=B[0],j=B[1],H=f.exports.useRef(null),W=function(){var ge;return(ge=H.current)===null||ge===void 0?void 0:ge.textArea},Y=function(){W().focus()};f.exports.useImperativeHandle(t,function(){return{resizableTextArea:H.current,focus:Y,blur:function(){W().blur()}}}),f.exports.useEffect(function(){M(function(we){return!x&&we})},[x]);var K=lt.useState(null),q=G(K,2),ee=q[0],Z=q[1];lt.useEffect(function(){if(ee){var we;(we=W()).setSelectionRange.apply(we,Oe(ee))}},[ee]);var Q=b$(m,b),ne=(n=Q.max)!==null&&n!==void 0?n:u,ae=Number(ne)>0,J=Q.strategy(T),re=!!ne&&J>ne,fe=function(ge,Pe){var Se=Pe;!L.current&&Q.exceedFormatter&&Q.max&&Q.strategy(Pe)>Q.max&&(Se=Q.exceedFormatter(Pe,{max:Q.max}),Pe!==Se&&Z([W().selectionStart||0,W().selectionEnd||0])),F(Se),od(ge.currentTarget,ge,s,Se)},ve=function(ge){L.current=!0,d==null||d(ge)},pe=function(ge){L.current=!1,fe(ge,ge.currentTarget.value),v==null||v(ge)},oe=function(ge){fe(ge,ge.target.value)},se=function(ge){var Pe=P.onPressEnter,Se=P.onKeyDown;ge.key==="Enter"&&Pe&&Pe(ge),Se==null||Se(ge)},le=function(ge){M(!0),a==null||a(ge)},Ce=function(ge){M(!1),l==null||l(ge)},ce=function(ge){F(""),Y(),od(W(),ge,s)},de=h,xe;Q.show&&(Q.showFormatter?xe=Q.showFormatter({value:T,count:J,maxLength:ne}):xe="".concat(J).concat(ae?" / ".concat(ne):""),de=ie(Tt,{children:[de,C("span",{className:te("".concat(p,"-data-count"),E==null?void 0:E.count),style:w==null?void 0:w.count,children:xe})]}));var he=function(ge){var Pe;R==null||R(ge),(Pe=W())!==null&&Pe!==void 0&&Pe.style.height&&j(!0)},ke=!P.autoSize&&!b&&!c;return C(y$,{value:T,allowClear:c,handleReset:ce,suffix:de,prefixCls:p,classNames:U(U({},E),{},{affixWrapper:te(E==null?void 0:E.affixWrapper,(r={},V(r,"".concat(p,"-show-count"),b),V(r,"".concat(p,"-textarea-allow-clear"),c),r))}),disabled:x,focused:O,className:te(y,re&&"".concat(p,"-out-of-range")),style:U(U({},S),k&&!ke?{height:"auto"}:{}),dataAttrs:{affixWrapper:{"data-count":typeof xe=="string"?xe:void 0}},hidden:$,children:C(h7,{...P,maxLength:u,onKeyDown:se,onChange:oe,onFocus:le,onBlur:Ce,onCompositionStart:ve,onCompositionEnd:pe,className:te(E==null?void 0:E.textarea),style:U(U({},w==null?void 0:w.textarea),{},{resize:S==null?void 0:S.resize}),disabled:x,prefixCls:p,onResize:he,ref:H})})}),b7=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{var n;const{prefixCls:r,bordered:o=!0,size:i,disabled:a,status:l,allowClear:s,classNames:c,rootClassName:u,className:d,variant:v}=e,h=b7(e,["prefixCls","bordered","size","disabled","status","allowClear","classNames","rootClassName","className","variant"]),{getPrefixCls:g,direction:p}=f.exports.useContext(ot),b=So(i),m=f.exports.useContext(rl),y=a!=null?a:m,{status:S,hasFeedback:x,feedbackIcon:$}=f.exports.useContext(Jr),E=dm(S,l),w=f.exports.useRef(null);f.exports.useImperativeHandle(t,()=>{var _;return{resizableTextArea:(_=w.current)===null||_===void 0?void 0:_.resizableTextArea,focus:O=>{var M,L;t7((L=(M=w.current)===null||M===void 0?void 0:M.resizableTextArea)===null||L===void 0?void 0:L.textArea,O)},blur:()=>{var O;return(O=w.current)===null||O===void 0?void 0:O.blur()}}});const R=g("input",r);let P;typeof s=="object"&&(s==null?void 0:s.clearIcon)?P=s:s&&(P={clearIcon:C(Nd,{})});const N=no(R),[I,z,F]=Im(R,N),[T,D]=vm(v,o);return I(C(y7,{...Object.assign({},h,{disabled:y,allowClear:P,className:te(F,N,d,u),classNames:Object.assign(Object.assign({},c),{textarea:te({[`${R}-sm`]:b==="small",[`${R}-lg`]:b==="large"},z,c==null?void 0:c.textarea),variant:te({[`${R}-${T}`]:D},ed(R,E)),affixWrapper:te(`${R}-textarea-affix-wrapper`,{[`${R}-affix-wrapper-rtl`]:p==="rtl",[`${R}-affix-wrapper-sm`]:b==="small",[`${R}-affix-wrapper-lg`]:b==="large",[`${R}-textarea-show-count`]:e.showCount||((n=e.count)===null||n===void 0?void 0:n.show)},z)}),prefixCls:R,suffix:x&&C("span",{className:`${R}-textarea-suffix`,children:$}),ref:w})}))}),C7=S7,Js=Tm;Js.Group=Xk;Js.Search=u7;Js.TextArea=C7;Js.Password=l7;const C$=Js;function x$(){var e=document.documentElement.clientWidth,t=window.innerHeight||document.documentElement.clientHeight;return{width:e,height:t}}function x7(e){var t=e.getBoundingClientRect(),n=document.documentElement;return{left:t.left+(window.pageXOffset||n.scrollLeft)-(n.clientLeft||document.body.clientLeft||0),top:t.top+(window.pageYOffset||n.scrollTop)-(n.clientTop||document.body.clientTop||0)}}var Pg=["crossOrigin","decoding","draggable","loading","referrerPolicy","sizes","srcSet","useMap","alt"],ec=f.exports.createContext(null),a1=0;function w7(e,t){var n=f.exports.useState(function(){return a1+=1,String(a1)}),r=G(n,1),o=r[0],i=f.exports.useContext(ec),a={data:t,canPreview:e};return f.exports.useEffect(function(){if(i)return i.register(o,a)},[]),f.exports.useEffect(function(){i&&i.register(o,a)},[e,t]),o}function $7(e){return new Promise(function(t){var n=document.createElement("img");n.onerror=function(){return t(!1)},n.onload=function(){return t(!0)},n.src=e})}function w$(e){var t=e.src,n=e.isCustomPlaceholder,r=e.fallback,o=f.exports.useState(n?"loading":"normal"),i=G(o,2),a=i[0],l=i[1],s=f.exports.useRef(!1),c=a==="error";f.exports.useEffect(function(){var h=!0;return $7(t).then(function(g){!g&&h&&l("error")}),function(){h=!1}},[t]),f.exports.useEffect(function(){n&&!s.current?l("loading"):c&&l("normal")},[t]);var u=function(){l("normal")},d=function(g){s.current=!1,a==="loading"&&g!==null&&g!==void 0&&g.complete&&(g.naturalWidth||g.naturalHeight)&&(s.current=!0,u())},v=c&&r?{src:r}:{onLoad:u,src:t};return[d,v,a]}function $a(e,t,n,r){var o=zu.unstable_batchedUpdates?function(a){zu.unstable_batchedUpdates(n,a)}:n;return e!=null&&e.addEventListener&&e.addEventListener(t,o,r),{remove:function(){e!=null&&e.removeEventListener&&e.removeEventListener(t,o,r)}}}var kc={x:0,y:0,rotate:0,scale:1,flipX:!1,flipY:!1};function E7(e,t,n,r){var o=f.exports.useRef(null),i=f.exports.useRef([]),a=f.exports.useState(kc),l=G(a,2),s=l[0],c=l[1],u=function(g){c(kc),r&&!Vs(kc,s)&&r({transform:kc,action:g})},d=function(g,p){o.current===null&&(i.current=[],o.current=St(function(){c(function(b){var m=b;return i.current.forEach(function(y){m=U(U({},m),y)}),o.current=null,r==null||r({transform:m,action:p}),m})})),i.current.push(U(U({},s),g))},v=function(g,p,b,m,y){var S=e.current,x=S.width,$=S.height,E=S.offsetWidth,w=S.offsetHeight,R=S.offsetLeft,P=S.offsetTop,N=g,I=s.scale*g;I>n?(I=n,N=n/s.scale):Ir){if(t>0)return V({},e,i);if(t<0&&or)return V({},e,t<0?i:-i);return{}}function $$(e,t,n,r){var o=x$(),i=o.width,a=o.height,l=null;return e<=i&&t<=a?l={x:0,y:0}:(e>i||t>a)&&(l=U(U({},l1("x",n,e,i)),l1("y",r,t,a))),l}var Ea=1,M7=1;function O7(e,t,n,r,o,i,a){var l=o.rotate,s=o.scale,c=o.x,u=o.y,d=f.exports.useState(!1),v=G(d,2),h=v[0],g=v[1],p=f.exports.useRef({diffX:0,diffY:0,transformX:0,transformY:0}),b=function($){!t||$.button!==0||($.preventDefault(),$.stopPropagation(),p.current={diffX:$.pageX-c,diffY:$.pageY-u,transformX:c,transformY:u},g(!0))},m=function($){n&&h&&i({x:$.pageX-p.current.diffX,y:$.pageY-p.current.diffY},"move")},y=function(){if(n&&h){g(!1);var $=p.current,E=$.transformX,w=$.transformY,R=c!==E&&u!==w;if(!R)return;var P=e.current.offsetWidth*s,N=e.current.offsetHeight*s,I=e.current.getBoundingClientRect(),z=I.left,F=I.top,T=l%180!==0,D=$$(T?N:P,T?P:N,z,F);D&&i(U({},D),"dragRebound")}},S=function($){if(!(!n||$.deltaY==0)){var E=Math.abs($.deltaY/100),w=Math.min(E,M7),R=Ea+w*r;$.deltaY>0&&(R=Ea/R),a(R,"wheel",$.clientX,$.clientY)}};return f.exports.useEffect(function(){var x,$,E,w;if(t){E=$a(window,"mouseup",y,!1),w=$a(window,"mousemove",m,!1);try{window.top!==window.self&&(x=$a(window.top,"mouseup",y,!1),$=$a(window.top,"mousemove",m,!1))}catch{}}return function(){var R,P,N,I;(R=E)===null||R===void 0||R.remove(),(P=w)===null||P===void 0||P.remove(),(N=x)===null||N===void 0||N.remove(),(I=$)===null||I===void 0||I.remove()}},[n,h,c,u,l,t]),{isMoving:h,onMouseDown:b,onMouseMove:m,onMouseUp:y,onWheel:S}}function id(e,t){var n=e.x-t.x,r=e.y-t.y;return Math.hypot(n,r)}function R7(e,t,n,r){var o=id(e,n),i=id(t,r);if(o===0&&i===0)return[e.x,e.y];var a=o/(o+i),l=e.x+a*(t.x-e.x),s=e.y+a*(t.y-e.y);return[l,s]}function I7(e,t,n,r,o,i,a){var l=o.rotate,s=o.scale,c=o.x,u=o.y,d=f.exports.useState(!1),v=G(d,2),h=v[0],g=v[1],p=f.exports.useRef({point1:{x:0,y:0},point2:{x:0,y:0},eventType:"none"}),b=function($){p.current=U(U({},p.current),$)},m=function($){if(!!t){$.stopPropagation(),g(!0);var E=$.touches,w=E===void 0?[]:E;w.length>1?b({point1:{x:w[0].clientX,y:w[0].clientY},point2:{x:w[1].clientX,y:w[1].clientY},eventType:"touchZoom"}):b({point1:{x:w[0].clientX-c,y:w[0].clientY-u},eventType:"move"})}},y=function($){var E=$.touches,w=E===void 0?[]:E,R=p.current,P=R.point1,N=R.point2,I=R.eventType;if(w.length>1&&I==="touchZoom"){var z={x:w[0].clientX,y:w[0].clientY},F={x:w[1].clientX,y:w[1].clientY},T=R7(P,N,z,F),D=G(T,2),_=D[0],O=D[1],M=id(z,F)/id(P,N);a(M,"touchZoom",_,O,!0),b({point1:z,point2:F,eventType:"touchZoom"})}else I==="move"&&(i({x:w[0].clientX-P.x,y:w[0].clientY-P.y},"move"),b({eventType:"move"}))},S=function(){if(!!n){if(h&&g(!1),b({eventType:"none"}),r>s)return i({x:0,y:0,scale:r},"touchZoom");var $=e.current.offsetWidth*s,E=e.current.offsetHeight*s,w=e.current.getBoundingClientRect(),R=w.left,P=w.top,N=l%180!==0,I=$$(N?E:$,N?$:E,R,P);I&&i(U({},I),"dragRebound")}};return f.exports.useEffect(function(){var x;return n&&t&&(x=$a(window,"touchmove",function($){return $.preventDefault()},{passive:!1})),function(){var $;($=x)===null||$===void 0||$.remove()}},[n,t]),{isTouching:h,onTouchStart:m,onTouchMove:y,onTouchEnd:S}}var P7=function(t){var n=t.visible,r=t.maskTransitionName,o=t.getContainer,i=t.prefixCls,a=t.rootClassName,l=t.icons,s=t.countRender,c=t.showSwitch,u=t.showProgress,d=t.current,v=t.transform,h=t.count,g=t.scale,p=t.minScale,b=t.maxScale,m=t.closeIcon,y=t.onSwitchLeft,S=t.onSwitchRight,x=t.onClose,$=t.onZoomIn,E=t.onZoomOut,w=t.onRotateRight,R=t.onRotateLeft,P=t.onFlipX,N=t.onFlipY,I=t.toolbarRender,z=t.zIndex,F=f.exports.useContext(ec),T=l.rotateLeft,D=l.rotateRight,_=l.zoomIn,O=l.zoomOut,M=l.close,L=l.left,A=l.right,B=l.flipX,k=l.flipY,j="".concat(i,"-operations-operation");f.exports.useEffect(function(){var K=function(ee){ee.keyCode===ue.ESC&&x()};return n&&window.addEventListener("keydown",K),function(){window.removeEventListener("keydown",K)}},[n]);var H=[{icon:k,onClick:N,type:"flipY"},{icon:B,onClick:P,type:"flipX"},{icon:T,onClick:R,type:"rotateLeft"},{icon:D,onClick:w,type:"rotateRight"},{icon:O,onClick:E,type:"zoomOut",disabled:g<=p},{icon:_,onClick:$,type:"zoomIn",disabled:g===b}],W=H.map(function(K){var q,ee=K.icon,Z=K.onClick,Q=K.type,ne=K.disabled;return C("div",{className:te(j,(q={},V(q,"".concat(i,"-operations-operation-").concat(Q),!0),V(q,"".concat(i,"-operations-operation-disabled"),!!ne),q)),onClick:Z,children:ee},Q)}),Y=C("div",{className:"".concat(i,"-operations"),children:W});return C(to,{visible:n,motionName:r,children:function(K){var q=K.className,ee=K.style;return C(nf,{open:!0,getContainer:o!=null?o:document.body,children:ie("div",{className:te("".concat(i,"-operations-wrapper"),q,a),style:U(U({},ee),{},{zIndex:z}),children:[m===null?null:C("button",{className:"".concat(i,"-close"),onClick:x,children:m||M}),c&&ie(Tt,{children:[C("div",{className:te("".concat(i,"-switch-left"),V({},"".concat(i,"-switch-left-disabled"),d===0)),onClick:y,children:L}),C("div",{className:te("".concat(i,"-switch-right"),V({},"".concat(i,"-switch-right-disabled"),d===h-1)),onClick:S,children:A})]}),ie("div",{className:"".concat(i,"-footer"),children:[u&&C("div",{className:"".concat(i,"-progress"),children:s?s(d+1,h):"".concat(d+1," / ").concat(h)}),I?I(Y,U({icons:{flipYIcon:W[0],flipXIcon:W[1],rotateLeftIcon:W[2],rotateRightIcon:W[3],zoomOutIcon:W[4],zoomInIcon:W[5]},actions:{onFlipY:N,onFlipX:P,onRotateLeft:R,onRotateRight:w,onZoomOut:E,onZoomIn:$},transform:v},F?{current:d,total:h}:{})):Y]})]})})}})},T7=["fallback","src","imgRef"],N7=["prefixCls","src","alt","fallback","movable","onClose","visible","icons","rootClassName","closeIcon","getContainer","current","count","countRender","scaleStep","minScale","maxScale","transitionName","maskTransitionName","imageRender","imgCommonProps","toolbarRender","onTransform","onChange"],_7=function(t){var n=t.fallback,r=t.src,o=t.imgRef,i=Je(t,T7),a=w$({src:r,fallback:n}),l=G(a,2),s=l[0],c=l[1];return C("img",{ref:function(d){o.current=d,s(d)},...i,...c})},E$=function(t){var n=t.prefixCls,r=t.src,o=t.alt,i=t.fallback,a=t.movable,l=a===void 0?!0:a,s=t.onClose,c=t.visible,u=t.icons,d=u===void 0?{}:u,v=t.rootClassName,h=t.closeIcon,g=t.getContainer,p=t.current,b=p===void 0?0:p,m=t.count,y=m===void 0?1:m,S=t.countRender,x=t.scaleStep,$=x===void 0?.5:x,E=t.minScale,w=E===void 0?1:E,R=t.maxScale,P=R===void 0?50:R,N=t.transitionName,I=N===void 0?"zoom":N,z=t.maskTransitionName,F=z===void 0?"fade":z,T=t.imageRender,D=t.imgCommonProps,_=t.toolbarRender,O=t.onTransform,M=t.onChange,L=Je(t,N7),A=f.exports.useRef(),B=f.exports.useContext(ec),k=B&&y>1,j=B&&y>=1,H=f.exports.useState(!0),W=G(H,2),Y=W[0],K=W[1],q=E7(A,w,P,O),ee=q.transform,Z=q.resetTransform,Q=q.updateTransform,ne=q.dispatchZoomChange,ae=O7(A,l,c,$,ee,Q,ne),J=ae.isMoving,re=ae.onMouseDown,fe=ae.onWheel,ve=I7(A,l,c,w,ee,Q,ne),pe=ve.isTouching,oe=ve.onTouchStart,se=ve.onTouchMove,le=ve.onTouchEnd,Ce=ee.rotate,ce=ee.scale,de=te(V({},"".concat(n,"-moving"),J));f.exports.useEffect(function(){Y||K(!0)},[Y]);var xe=function(){Z("close")},he=function(){ne(Ea+$,"zoomIn")},ke=function(){ne(Ea/(Ea+$),"zoomOut")},we=function(){Q({rotate:Ce+90},"rotateRight")},ge=function(){Q({rotate:Ce-90},"rotateLeft")},Pe=function(){Q({flipX:!ee.flipX},"flipX")},Se=function(){Q({flipY:!ee.flipY},"flipY")},st=function(qe){qe==null||qe.preventDefault(),qe==null||qe.stopPropagation(),b>0&&(K(!1),Z("prev"),M==null||M(b-1,b))},nt=function(qe){qe==null||qe.preventDefault(),qe==null||qe.stopPropagation(),b({position:e||"absolute",inset:0}),B7=e=>{const{iconCls:t,motionDurationSlow:n,paddingXXS:r,marginXXS:o,prefixCls:i,colorTextLightSolid:a}=e;return{position:"absolute",inset:0,display:"flex",alignItems:"center",justifyContent:"center",color:a,background:new Mt("#000").setAlpha(.5).toRgbString(),cursor:"pointer",opacity:0,transition:`opacity ${n}`,[`.${i}-mask-info`]:Object.assign(Object.assign({},ei),{padding:`0 ${X(r)}`,[t]:{marginInlineEnd:o,svg:{verticalAlign:"baseline"}}})}},j7=e=>{const{previewCls:t,modalMaskBg:n,paddingSM:r,marginXL:o,margin:i,paddingLG:a,previewOperationColorDisabled:l,previewOperationHoverColor:s,motionDurationSlow:c,iconCls:u,colorTextLightSolid:d}=e,v=new Mt(n).setAlpha(.1),h=v.clone().setAlpha(.2);return{[`${t}-footer`]:{position:"fixed",bottom:o,left:{_skip_check_:!0,value:0},width:"100%",display:"flex",flexDirection:"column",alignItems:"center",color:e.previewOperationColor},[`${t}-progress`]:{marginBottom:i},[`${t}-close`]:{position:"fixed",top:o,right:{_skip_check_:!0,value:o},display:"flex",color:d,backgroundColor:v.toRgbString(),borderRadius:"50%",padding:r,outline:0,border:0,cursor:"pointer",transition:`all ${c}`,"&:hover":{backgroundColor:h.toRgbString()},[`& > ${u}`]:{fontSize:e.previewOperationSize}},[`${t}-operations`]:{display:"flex",alignItems:"center",padding:`0 ${X(a)}`,backgroundColor:v.toRgbString(),borderRadius:100,"&-operation":{marginInlineStart:r,padding:r,cursor:"pointer",transition:`all ${c}`,userSelect:"none",[`&:not(${t}-operations-operation-disabled):hover > ${u}`]:{color:s},"&-disabled":{color:l,cursor:"not-allowed"},"&:first-of-type":{marginInlineStart:0},[`& > ${u}`]:{fontSize:e.previewOperationSize}}}}},H7=e=>{const{modalMaskBg:t,iconCls:n,previewOperationColorDisabled:r,previewCls:o,zIndexPopup:i,motionDurationSlow:a}=e,l=new Mt(t).setAlpha(.1),s=l.clone().setAlpha(.2);return{[`${o}-switch-left, ${o}-switch-right`]:{position:"fixed",insetBlockStart:"50%",zIndex:e.calc(i).add(1).equal({unit:!1}),display:"flex",alignItems:"center",justifyContent:"center",width:e.imagePreviewSwitchSize,height:e.imagePreviewSwitchSize,marginTop:e.calc(e.imagePreviewSwitchSize).mul(-1).div(2).equal(),color:e.previewOperationColor,background:l.toRgbString(),borderRadius:"50%",transform:"translateY(-50%)",cursor:"pointer",transition:`all ${a}`,userSelect:"none","&:hover":{background:s.toRgbString()},["&-disabled"]:{"&, &:hover":{color:r,background:"transparent",cursor:"not-allowed",[`> ${n}`]:{cursor:"not-allowed"}}},[`> ${n}`]:{fontSize:e.previewOperationSize}},[`${o}-switch-left`]:{insetInlineStart:e.marginSM},[`${o}-switch-right`]:{insetInlineEnd:e.marginSM}}},W7=e=>{const{motionEaseOut:t,previewCls:n,motionDurationSlow:r,componentCls:o}=e;return[{[`${o}-preview-root`]:{[n]:{height:"100%",textAlign:"center",pointerEvents:"none"},[`${n}-body`]:Object.assign(Object.assign({},Tg()),{overflow:"hidden"}),[`${n}-img`]:{maxWidth:"100%",maxHeight:"70%",verticalAlign:"middle",transform:"scale3d(1, 1, 1)",cursor:"grab",transition:`transform ${r} ${t} 0s`,userSelect:"none","&-wrapper":Object.assign(Object.assign({},Tg()),{transition:`transform ${r} ${t} 0s`,display:"flex",justifyContent:"center",alignItems:"center","& > *":{pointerEvents:"auto"},"&::before":{display:"inline-block",width:1,height:"50%",marginInlineEnd:-1,content:'""'}})},[`${n}-moving`]:{[`${n}-preview-img`]:{cursor:"grabbing","&-wrapper":{transitionDuration:"0s"}}}}},{[`${o}-preview-root`]:{[`${n}-wrap`]:{zIndex:e.zIndexPopup}}},{[`${o}-preview-operations-wrapper`]:{position:"fixed",zIndex:e.calc(e.zIndexPopup).add(1).equal({unit:!1})},"&":[j7(e),H7(e)]}]},V7=e=>{const{componentCls:t}=e;return{[t]:{position:"relative",display:"inline-block",[`${t}-img`]:{width:"100%",height:"auto",verticalAlign:"middle"},[`${t}-img-placeholder`]:{backgroundColor:e.colorBgContainerDisabled,backgroundImage:"url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMTQuNSAyLjVoLTEzQS41LjUgMCAwIDAgMSAzdjEwYS41LjUgMCAwIDAgLjUuNWgxM2EuNS41IDAgMCAwIC41LS41VjNhLjUuNSAwIDAgMC0uNS0uNXpNNS4yODEgNC43NWExIDEgMCAwIDEgMCAyIDEgMSAwIDAgMSAwLTJ6bTguMDMgNi44M2EuMTI3LjEyNyAwIDAgMS0uMDgxLjAzSDIuNzY5YS4xMjUuMTI1IDAgMCAxLS4wOTYtLjIwN2wyLjY2MS0zLjE1NmEuMTI2LjEyNiAwIDAgMSAuMTc3LS4wMTZsLjAxNi4wMTZMNy4wOCAxMC4wOWwyLjQ3LTIuOTNhLjEyNi4xMjYgMCAwIDEgLjE3Ny0uMDE2bC4wMTUuMDE2IDMuNTg4IDQuMjQ0YS4xMjcuMTI3IDAgMCAxLS4wMi4xNzV6IiBmaWxsPSIjOEM4QzhDIiBmaWxsLXJ1bGU9Im5vbnplcm8iLz48L3N2Zz4=')",backgroundRepeat:"no-repeat",backgroundPosition:"center center",backgroundSize:"30%"},[`${t}-mask`]:Object.assign({},B7(e)),[`${t}-mask:hover`]:{opacity:1},[`${t}-placeholder`]:Object.assign({},Tg())}}},U7=e=>{const{previewCls:t}=e;return{[`${t}-root`]:of(e,"zoom"),["&"]:zw(e,!0)}},Y7=e=>({zIndexPopup:e.zIndexPopupBase+80,previewOperationColor:new Mt(e.colorTextLightSolid).setAlpha(.65).toRgbString(),previewOperationHoverColor:new Mt(e.colorTextLightSolid).setAlpha(.85).toRgbString(),previewOperationColorDisabled:new Mt(e.colorTextLightSolid).setAlpha(.25).toRgbString(),previewOperationSize:e.fontSizeIcon*1.5}),M$=vn("Image",e=>{const t=`${e.componentCls}-preview`,n=$t(e,{previewCls:t,modalMaskBg:new Mt("#000").setAlpha(.45).toRgbString(),imagePreviewSwitchSize:e.controlHeightLG});return[V7(n),W7(n),Fw($t(n,{componentCls:t})),U7(n)]},Y7);var G7=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{var{previewPrefixCls:t,preview:n}=e,r=G7(e,["previewPrefixCls","preview"]);const{getPrefixCls:o}=f.exports.useContext(ot),i=o("image",t),a=`${i}-preview`,l=o(),s=no(i),[c,u,d]=M$(i,s),[v]=Qd("ImagePreview",typeof n=="object"?n.zIndex:void 0),h=f.exports.useMemo(()=>{var g;if(n===!1)return n;const p=typeof n=="object"?n:{},b=te(u,d,s,(g=p.rootClassName)!==null&&g!==void 0?g:"");return Object.assign(Object.assign({},p),{transitionName:ni(l,"zoom",p.transitionName),maskTransitionName:ni(l,"fade",p.maskTransitionName),rootClassName:b,zIndex:v})},[n]);return c(C(hf.PreviewGroup,{...Object.assign({preview:h,previewPrefixCls:a,icons:O$},r)}))},q7=K7;var s1=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{var t;const{prefixCls:n,preview:r,className:o,rootClassName:i,style:a}=e,l=s1(e,["prefixCls","preview","className","rootClassName","style"]),{getPrefixCls:s,locale:c=Jo,getPopupContainer:u,image:d}=f.exports.useContext(ot),v=s("image",n),h=s(),g=c.Image||Jo.Image,p=no(v),[b,m,y]=M$(v,p),S=te(i,m,y,p),x=te(o,m,d==null?void 0:d.className),[$]=Qd("ImagePreview",typeof r=="object"?r.zIndex:void 0),E=f.exports.useMemo(()=>{var R;if(r===!1)return r;const P=typeof r=="object"?r:{},{getContainer:N,closeIcon:I}=P,z=s1(P,["getContainer","closeIcon"]);return Object.assign(Object.assign({mask:ie("div",{className:`${v}-mask-info`,children:[C(sx,{}),g==null?void 0:g.preview]}),icons:O$},z),{getContainer:N!=null?N:u,transitionName:ni(h,"zoom",P.transitionName),maskTransitionName:ni(h,"fade",P.maskTransitionName),zIndex:$,closeIcon:I!=null?I:(R=d==null?void 0:d.preview)===null||R===void 0?void 0:R.closeIcon})},[r,g,(t=d==null?void 0:d.preview)===null||t===void 0?void 0:t.closeIcon]),w=Object.assign(Object.assign({},d==null?void 0:d.style),a);return b(C(hf,{...Object.assign({prefixCls:v,preview:E,rootClassName:S,className:x,style:w},l)}))};R$.PreviewGroup=q7;const cu=R$,X7=new Ct("antSpinMove",{to:{opacity:1}}),Q7=new Ct("antRotate",{to:{transform:"rotate(405deg)"}}),Z7=e=>{const{componentCls:t,calc:n}=e;return{[`${t}`]:Object.assign(Object.assign({},Qt(e)),{position:"absolute",display:"none",color:e.colorPrimary,fontSize:0,textAlign:"center",verticalAlign:"middle",opacity:0,transition:`transform ${e.motionDurationSlow} ${e.motionEaseInOutCirc}`,"&-spinning":{position:"static",display:"inline-block",opacity:1},[`${t}-text`]:{fontSize:e.fontSize,paddingTop:n(n(e.dotSize).sub(e.fontSize)).div(2).add(2).equal()},"&-fullscreen":{position:"fixed",width:"100vw",height:"100vh",backgroundColor:e.colorBgMask,zIndex:e.zIndexPopupBase,inset:0,display:"flex",alignItems:"center",flexDirection:"column",justifyContent:"center",opacity:0,visibility:"hidden",transition:`all ${e.motionDurationMid}`,"&-show":{opacity:1,visibility:"visible"},[`${t}-dot ${t}-dot-item`]:{backgroundColor:e.colorWhite},[`${t}-text`]:{color:e.colorTextLightSolid}},"&-nested-loading":{position:"relative",[`> div > ${t}`]:{position:"absolute",top:0,insetInlineStart:0,zIndex:4,display:"block",width:"100%",height:"100%",maxHeight:e.contentHeight,[`${t}-dot`]:{position:"absolute",top:"50%",insetInlineStart:"50%",margin:n(e.dotSize).mul(-1).div(2).equal()},[`${t}-text`]:{position:"absolute",top:"50%",width:"100%",textShadow:`0 1px 2px ${e.colorBgContainer}`},[`&${t}-show-text ${t}-dot`]:{marginTop:n(e.dotSize).div(2).mul(-1).sub(10).equal()},"&-sm":{[`${t}-dot`]:{margin:n(e.dotSizeSM).mul(-1).div(2).equal()},[`${t}-text`]:{paddingTop:n(n(e.dotSizeSM).sub(e.fontSize)).div(2).add(2).equal()},[`&${t}-show-text ${t}-dot`]:{marginTop:n(e.dotSizeSM).div(2).mul(-1).sub(10).equal()}},"&-lg":{[`${t}-dot`]:{margin:n(e.dotSizeLG).mul(-1).div(2).equal()},[`${t}-text`]:{paddingTop:n(n(e.dotSizeLG).sub(e.fontSize)).div(2).add(2).equal()},[`&${t}-show-text ${t}-dot`]:{marginTop:n(e.dotSizeLG).div(2).mul(-1).sub(10).equal()}}},[`${t}-container`]:{position:"relative",transition:`opacity ${e.motionDurationSlow}`,"&::after":{position:"absolute",top:0,insetInlineEnd:0,bottom:0,insetInlineStart:0,zIndex:10,width:"100%",height:"100%",background:e.colorBgContainer,opacity:0,transition:`all ${e.motionDurationSlow}`,content:'""',pointerEvents:"none"}},[`${t}-blur`]:{clear:"both",opacity:.5,userSelect:"none",pointerEvents:"none",["&::after"]:{opacity:.4,pointerEvents:"auto"}}},["&-tip"]:{color:e.spinDotDefault},[`${t}-dot`]:{position:"relative",display:"inline-block",fontSize:e.dotSize,width:"1em",height:"1em","&-item":{position:"absolute",display:"block",width:n(e.dotSize).sub(n(e.marginXXS).div(2)).div(2).equal(),height:n(e.dotSize).sub(n(e.marginXXS).div(2)).div(2).equal(),backgroundColor:e.colorPrimary,borderRadius:"100%",transform:"scale(0.75)",transformOrigin:"50% 50%",opacity:.3,animationName:X7,animationDuration:"1s",animationIterationCount:"infinite",animationTimingFunction:"linear",animationDirection:"alternate","&:nth-child(1)":{top:0,insetInlineStart:0,animationDelay:"0s"},"&:nth-child(2)":{top:0,insetInlineEnd:0,animationDelay:"0.4s"},"&:nth-child(3)":{insetInlineEnd:0,bottom:0,animationDelay:"0.8s"},"&:nth-child(4)":{bottom:0,insetInlineStart:0,animationDelay:"1.2s"}},"&-spin":{transform:"rotate(45deg)",animationName:Q7,animationDuration:"1.2s",animationIterationCount:"infinite",animationTimingFunction:"linear"}},[`&-sm ${t}-dot`]:{fontSize:e.dotSizeSM,i:{width:n(n(e.dotSizeSM).sub(n(e.marginXXS).div(2))).div(2).equal(),height:n(n(e.dotSizeSM).sub(n(e.marginXXS).div(2))).div(2).equal()}},[`&-lg ${t}-dot`]:{fontSize:e.dotSizeLG,i:{width:n(n(e.dotSizeLG).sub(e.marginXXS)).div(2).equal(),height:n(n(e.dotSizeLG).sub(e.marginXXS)).div(2).equal()}},[`&${t}-show-text ${t}-text`]:{display:"block"}})}},J7=e=>{const{controlHeightLG:t,controlHeight:n}=e;return{contentHeight:400,dotSize:t/2,dotSizeSM:t*.35,dotSizeLG:n}},eB=vn("Spin",e=>{const t=$t(e,{spinDotDefault:e.colorTextDescription});return[Z7(t)]},J7);var tB=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{const{prefixCls:t,spinning:n=!0,delay:r=0,className:o,rootClassName:i,size:a="default",tip:l,wrapperClassName:s,style:c,children:u,fullscreen:d=!1}=e,v=tB(e,["prefixCls","spinning","delay","className","rootClassName","size","tip","wrapperClassName","style","children","fullscreen"]),{getPrefixCls:h}=f.exports.useContext(ot),g=h("spin",t),[p,b,m]=eB(g),[y,S]=f.exports.useState(()=>n&&!rB(n,r));f.exports.useEffect(()=>{if(n){const z=Hk(r,()=>{S(!0)});return z(),()=>{var F;(F=z==null?void 0:z.cancel)===null||F===void 0||F.call(z)}}S(!1)},[r,n]);const x=f.exports.useMemo(()=>typeof u<"u"&&!d,[u,d]),{direction:$,spin:E}=f.exports.useContext(ot),w=te(g,E==null?void 0:E.className,{[`${g}-sm`]:a==="small",[`${g}-lg`]:a==="large",[`${g}-spinning`]:y,[`${g}-show-text`]:!!l,[`${g}-fullscreen`]:d,[`${g}-fullscreen-show`]:d&&y,[`${g}-rtl`]:$==="rtl"},o,i,b,m),R=te(`${g}-container`,{[`${g}-blur`]:y}),P=lr(v,["indicator"]),N=Object.assign(Object.assign({},E==null?void 0:E.style),c),I=ie("div",{...Object.assign({},P,{style:N,className:w,"aria-live":"polite","aria-busy":y}),children:[nB(g,e),l&&(x||d)?C("div",{className:`${g}-text`,children:l}):null]});return p(x?ie("div",{...Object.assign({},P,{className:te(`${g}-nested-loading`,s,b,m)}),children:[y&&C("div",{children:I},"loading"),C("div",{className:R,children:u},"container")]}):I)};I$.setDefaultIndicator=e=>{uu=e};const oB=I$;var iB={percent:0,prefixCls:"rc-progress",strokeColor:"#2db7f5",strokeLinecap:"round",strokeWidth:1,trailColor:"#D9D9D9",trailWidth:1,gapPosition:"bottom"},aB=function(){var t=f.exports.useRef([]),n=f.exports.useRef(null);return f.exports.useEffect(function(){var r=Date.now(),o=!1;t.current.forEach(function(i){if(!!i){o=!0;var a=i.style;a.transitionDuration=".3s, .3s, .3s, .06s",n.current&&r-n.current<100&&(a.transitionDuration="0s, 0s")}}),o&&(n.current=Date.now())}),t.current},c1=0,lB=Rn();function sB(){var e;return lB?(e=c1,c1+=1):e="TEST_OR_SSR",e}const cB=function(e){var t=f.exports.useState(),n=G(t,2),r=n[0],o=n[1];return f.exports.useEffect(function(){o("rc_progress_".concat(sB()))},[]),e||r};var u1=function(t){var n=t.bg,r=t.children;return C("div",{style:{width:"100%",height:"100%",background:n},children:r})};function d1(e,t){return Object.keys(e).map(function(n){var r=parseFloat(n),o="".concat(Math.floor(r*t),"%");return"".concat(e[n]," ").concat(o)})}var uB=f.exports.forwardRef(function(e,t){var n=e.prefixCls,r=e.color,o=e.gradientId,i=e.radius,a=e.style,l=e.ptg,s=e.strokeLinecap,c=e.strokeWidth,u=e.size,d=e.gapDegree,v=r&&Qe(r)==="object",h=v?"#FFF":void 0,g=u/2,p=C("circle",{className:"".concat(n,"-circle-path"),r:i,cx:g,cy:g,stroke:h,strokeLinecap:s,strokeWidth:c,opacity:l===0?0:1,style:a,ref:t});if(!v)return p;var b="".concat(o,"-conic"),m=d?"".concat(180+d/2,"deg"):"0deg",y=d1(r,(360-d)/360),S=d1(r,1),x="conic-gradient(from ".concat(m,", ").concat(y.join(", "),")"),$="linear-gradient(to ".concat(d?"bottom":"top",", ").concat(S.join(", "),")");return ie(Tt,{children:[C("mask",{id:b,children:p}),C("foreignObject",{x:0,y:0,width:u,height:u,mask:"url(#".concat(b,")"),children:C(u1,{bg:$,children:C(u1,{bg:x})})})]})}),Dl=100,Iv=function(t,n,r,o,i,a,l,s,c,u){var d=arguments.length>10&&arguments[10]!==void 0?arguments[10]:0,v=r/100*360*((360-a)/360),h=a===0?0:{bottom:0,top:180,left:90,right:-90}[l],g=(100-o)/100*n;c==="round"&&o!==100&&(g+=u/2,g>=n&&(g=n-.01));var p=Dl/2;return{stroke:typeof s=="string"?s:void 0,strokeDasharray:"".concat(n,"px ").concat(t),strokeDashoffset:g+d,transform:"rotate(".concat(i+v+h,"deg)"),transformOrigin:"".concat(p,"px ").concat(p,"px"),transition:"stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s, stroke-width .06s ease .3s, opacity .3s ease 0s",fillOpacity:0}},dB=["id","prefixCls","steps","strokeWidth","trailWidth","gapDegree","gapPosition","trailColor","strokeLinecap","style","className","strokeColor","percent"];function f1(e){var t=e!=null?e:[];return Array.isArray(t)?t:[t]}var fB=function(t){var n=U(U({},iB),t),r=n.id,o=n.prefixCls,i=n.steps,a=n.strokeWidth,l=n.trailWidth,s=n.gapDegree,c=s===void 0?0:s,u=n.gapPosition,d=n.trailColor,v=n.strokeLinecap,h=n.style,g=n.className,p=n.strokeColor,b=n.percent,m=Je(n,dB),y=Dl/2,S=cB(r),x="".concat(S,"-gradient"),$=y-a/2,E=Math.PI*2*$,w=c>0?90+c/2:-90,R=E*((360-c)/360),P=Qe(i)==="object"?i:{count:i,space:2},N=P.count,I=P.space,z=f1(b),F=f1(p),T=F.find(function(B){return B&&Qe(B)==="object"}),D=T&&Qe(T)==="object",_=D?"butt":v,O=Iv(E,R,0,100,w,c,u,d,_,a),M=aB(),L=function(){var k=0;return z.map(function(j,H){var W=F[H]||F[F.length-1],Y=Iv(E,R,k,j,w,c,u,W,_,a);return k+=j,C(uB,{color:W,ptg:j,radius:$,prefixCls:o,gradientId:x,style:Y,strokeLinecap:_,strokeWidth:a,gapDegree:c,ref:function(q){M[H]=q},size:Dl},H)}).reverse()},A=function(){var k=Math.round(N*(z[0]/100)),j=100/N,H=0;return new Array(N).fill(null).map(function(W,Y){var K=Y<=k-1?F[0]:d,q=K&&Qe(K)==="object"?"url(#".concat(x,")"):void 0,ee=Iv(E,R,H,j,w,c,u,K,"butt",a,I);return H+=(R-ee.strokeDashoffset+I)*100/R,C("circle",{className:"".concat(o,"-circle-path"),r:$,cx:y,cy:y,stroke:q,strokeWidth:a,opacity:1,style:ee,ref:function(Q){M[Y]=Q}},Y)})};return ie("svg",{className:te("".concat(o,"-circle"),g),viewBox:"0 0 ".concat(Dl," ").concat(Dl),style:h,id:r,role:"presentation",...m,children:[!N&&C("circle",{className:"".concat(o,"-circle-trail"),r:$,cx:y,cy:y,stroke:d,strokeLinecap:_,strokeWidth:l||a,style:O}),N?A():L()]})};function Go(e){return!e||e<0?0:e>100?100:e}function ad(e){let{success:t,successPercent:n}=e,r=n;return t&&"progress"in t&&(r=t.progress),t&&"percent"in t&&(r=t.percent),r}const vB=e=>{let{percent:t,success:n,successPercent:r}=e;const o=Go(ad({success:n,successPercent:r}));return[o,Go(Go(t)-o)]},pB=e=>{let{success:t={},strokeColor:n}=e;const{strokeColor:r}=t;return[r||Na.green,n||null]},mf=(e,t,n)=>{var r,o,i,a;let l=-1,s=-1;if(t==="step"){const c=n.steps,u=n.strokeWidth;typeof e=="string"||typeof e>"u"?(l=e==="small"?2:14,s=u!=null?u:8):typeof e=="number"?[l,s]=[e,e]:[l=14,s=8]=e,l*=c}else if(t==="line"){const c=n==null?void 0:n.strokeWidth;typeof e=="string"||typeof e>"u"?s=c||(e==="small"?6:8):typeof e=="number"?[l,s]=[e,e]:[l=-1,s=8]=e}else(t==="circle"||t==="dashboard")&&(typeof e=="string"||typeof e>"u"?[l,s]=e==="small"?[60,60]:[120,120]:typeof e=="number"?[l,s]=[e,e]:(l=(o=(r=e[0])!==null&&r!==void 0?r:e[1])!==null&&o!==void 0?o:120,s=(a=(i=e[0])!==null&&i!==void 0?i:e[1])!==null&&a!==void 0?a:120));return[l,s]},gB=3,hB=e=>gB/e*100,mB=e=>{const{prefixCls:t,trailColor:n=null,strokeLinecap:r="round",gapPosition:o,gapDegree:i,width:a=120,type:l,children:s,success:c,size:u=a}=e,[d,v]=mf(u,"circle");let{strokeWidth:h}=e;h===void 0&&(h=Math.max(hB(d),6));const g={width:d,height:v,fontSize:d*.15+6},p=f.exports.useMemo(()=>{if(i||i===0)return i;if(l==="dashboard")return 75},[i,l]),b=o||l==="dashboard"&&"bottom"||void 0,m=Object.prototype.toString.call(e.strokeColor)==="[object Object]",y=pB({success:c,strokeColor:e.strokeColor}),S=te(`${t}-inner`,{[`${t}-circle-gradient`]:m}),x=C(fB,{percent:vB(e),strokeWidth:h,trailWidth:h,strokeColor:y,strokeLinecap:r,trailColor:n,prefixCls:t,gapDegree:p,gapPosition:b});return C("div",{className:S,style:g,children:d<=20?C(p2,{title:s,children:C("span",{children:x})}):ie(Tt,{children:[x,s]})})},yB=mB,ld="--progress-line-stroke-color",P$="--progress-percent",v1=e=>{const t=e?"100%":"-100%";return new Ct(`antProgress${e?"RTL":"LTR"}Active`,{"0%":{transform:`translateX(${t}) scaleX(0)`,opacity:.1},"20%":{transform:`translateX(${t}) scaleX(0)`,opacity:.5},to:{transform:"translateX(0) scaleX(1)",opacity:0}})},bB=e=>{const{componentCls:t,iconCls:n}=e;return{[t]:Object.assign(Object.assign({},Qt(e)),{display:"inline-block","&-rtl":{direction:"rtl"},"&-line":{position:"relative",width:"100%",fontSize:e.fontSize},[`${t}-outer`]:{display:"inline-block",width:"100%"},[`&${t}-show-info`]:{[`${t}-outer`]:{marginInlineEnd:`calc(-2em - ${X(e.marginXS)})`,paddingInlineEnd:`calc(2em + ${X(e.paddingXS)})`}},[`${t}-inner`]:{position:"relative",display:"inline-block",width:"100%",overflow:"hidden",verticalAlign:"middle",backgroundColor:e.remainingColor,borderRadius:e.lineBorderRadius},[`${t}-inner:not(${t}-circle-gradient)`]:{[`${t}-circle-path`]:{stroke:e.defaultColor}},[`${t}-success-bg, ${t}-bg`]:{position:"relative",background:e.defaultColor,borderRadius:e.lineBorderRadius,transition:`all ${e.motionDurationSlow} ${e.motionEaseInOutCirc}`},[`${t}-bg`]:{overflow:"hidden","&::after":{content:'""',background:{_multi_value_:!0,value:["inherit",`var(${ld})`]},height:"100%",width:`calc(1 / var(${P$}) * 100%)`,display:"block"}},[`${t}-success-bg`]:{position:"absolute",insetBlockStart:0,insetInlineStart:0,backgroundColor:e.colorSuccess},[`${t}-text`]:{display:"inline-block",width:"2em",marginInlineStart:e.marginXS,color:e.colorText,lineHeight:1,whiteSpace:"nowrap",textAlign:"start",verticalAlign:"middle",wordBreak:"normal",[n]:{fontSize:e.fontSize}},[`&${t}-status-active`]:{[`${t}-bg::before`]:{position:"absolute",inset:0,backgroundColor:e.colorBgContainer,borderRadius:e.lineBorderRadius,opacity:0,animationName:v1(),animationDuration:e.progressActiveMotionDuration,animationTimingFunction:e.motionEaseOutQuint,animationIterationCount:"infinite",content:'""'}},[`&${t}-rtl${t}-status-active`]:{[`${t}-bg::before`]:{animationName:v1(!0)}},[`&${t}-status-exception`]:{[`${t}-bg`]:{backgroundColor:e.colorError},[`${t}-text`]:{color:e.colorError}},[`&${t}-status-exception ${t}-inner:not(${t}-circle-gradient)`]:{[`${t}-circle-path`]:{stroke:e.colorError}},[`&${t}-status-success`]:{[`${t}-bg`]:{backgroundColor:e.colorSuccess},[`${t}-text`]:{color:e.colorSuccess}},[`&${t}-status-success ${t}-inner:not(${t}-circle-gradient)`]:{[`${t}-circle-path`]:{stroke:e.colorSuccess}}})}},SB=e=>{const{componentCls:t,iconCls:n}=e;return{[t]:{[`${t}-circle-trail`]:{stroke:e.remainingColor},[`&${t}-circle ${t}-inner`]:{position:"relative",lineHeight:1,backgroundColor:"transparent"},[`&${t}-circle ${t}-text`]:{position:"absolute",insetBlockStart:"50%",insetInlineStart:0,width:"100%",margin:0,padding:0,color:e.circleTextColor,fontSize:e.circleTextFontSize,lineHeight:1,whiteSpace:"normal",textAlign:"center",transform:"translateY(-50%)",[n]:{fontSize:e.circleIconFontSize}},[`${t}-circle&-status-exception`]:{[`${t}-text`]:{color:e.colorError}},[`${t}-circle&-status-success`]:{[`${t}-text`]:{color:e.colorSuccess}}},[`${t}-inline-circle`]:{lineHeight:1,[`${t}-inner`]:{verticalAlign:"bottom"}}}},CB=e=>{const{componentCls:t}=e;return{[t]:{[`${t}-steps`]:{display:"inline-block","&-outer":{display:"flex",flexDirection:"row",alignItems:"center"},"&-item":{flexShrink:0,minWidth:e.progressStepMinWidth,marginInlineEnd:e.progressStepMarginInlineEnd,backgroundColor:e.remainingColor,transition:`all ${e.motionDurationSlow}`,"&-active":{backgroundColor:e.defaultColor}}}}}},xB=e=>{const{componentCls:t,iconCls:n}=e;return{[t]:{[`${t}-small&-line, ${t}-small&-line ${t}-text ${n}`]:{fontSize:e.fontSizeSM}}}},wB=e=>({circleTextColor:e.colorText,defaultColor:e.colorInfo,remainingColor:e.colorFillSecondary,lineBorderRadius:100,circleTextFontSize:"1em",circleIconFontSize:`${e.fontSize/e.fontSizeSM}em`}),$B=vn("Progress",e=>{const t=e.calc(e.marginXXS).div(2).equal(),n=$t(e,{progressStepMarginInlineEnd:t,progressStepMinWidth:t,progressActiveMotionDuration:"2.4s"});return[bB(n),SB(n),CB(n),xB(n)]},wB);var EB=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{let t=[];return Object.keys(e).forEach(n=>{const r=parseFloat(n.replace(/%/g,""));isNaN(r)||t.push({key:r,value:e[n]})}),t=t.sort((n,r)=>n.key-r.key),t.map(n=>{let{key:r,value:o}=n;return`${o} ${r}%`}).join(", ")},OB=(e,t)=>{const{from:n=Na.blue,to:r=Na.blue,direction:o=t==="rtl"?"to left":"to right"}=e,i=EB(e,["from","to","direction"]);if(Object.keys(i).length!==0){const l=MB(i),s=`linear-gradient(${o}, ${l})`;return{background:s,[ld]:s}}const a=`linear-gradient(${o}, ${n}, ${r})`;return{background:a,[ld]:a}},RB=e=>{const{prefixCls:t,direction:n,percent:r,size:o,strokeWidth:i,strokeColor:a,strokeLinecap:l="round",children:s,trailColor:c=null,success:u}=e,d=a&&typeof a!="string"?OB(a,n):{[ld]:a,background:a},v=l==="square"||l==="butt"?0:void 0,h=o!=null?o:[-1,i||(o==="small"?6:8)],[g,p]=mf(h,"line",{strokeWidth:i}),b={backgroundColor:c||void 0,borderRadius:v},m=Object.assign(Object.assign({width:`${Go(r)}%`,height:p,borderRadius:v},d),{[P$]:Go(r)/100}),y=ad(e),S={width:`${Go(y)}%`,height:p,borderRadius:v,backgroundColor:u==null?void 0:u.strokeColor},x={width:g<0?"100%":g,height:p};return ie(Tt,{children:[C("div",{className:`${t}-outer`,style:x,children:ie("div",{className:`${t}-inner`,style:b,children:[C("div",{className:`${t}-bg`,style:m}),y!==void 0?C("div",{className:`${t}-success-bg`,style:S}):null]})}),s]})},IB=RB,PB=e=>{const{size:t,steps:n,percent:r=0,strokeWidth:o=8,strokeColor:i,trailColor:a=null,prefixCls:l,children:s}=e,c=Math.round(n*(r/100)),u=t==="small"?2:14,d=t!=null?t:[u,o],[v,h]=mf(d,"step",{steps:n,strokeWidth:o}),g=v/n,p=new Array(n);for(let b=0;b{const{prefixCls:n,className:r,rootClassName:o,steps:i,strokeColor:a,percent:l=0,size:s="default",showInfo:c=!0,type:u="line",status:d,format:v,style:h}=e,g=NB(e,["prefixCls","className","rootClassName","steps","strokeColor","percent","size","showInfo","type","status","format","style"]),p=f.exports.useMemo(()=>{var F,T;const D=ad(e);return parseInt(D!==void 0?(F=D!=null?D:0)===null||F===void 0?void 0:F.toString():(T=l!=null?l:0)===null||T===void 0?void 0:T.toString(),10)},[l,e.success,e.successPercent]),b=f.exports.useMemo(()=>!_B.includes(d)&&p>=100?"success":d||"normal",[d,p]),{getPrefixCls:m,direction:y,progress:S}=f.exports.useContext(ot),x=m("progress",n),[$,E,w]=$B(x),R=f.exports.useMemo(()=>{if(!c)return null;const F=ad(e);let T;const D=v||(O=>`${O}%`),_=u==="line";return v||b!=="exception"&&b!=="success"?T=D(Go(l),Go(F)):b==="exception"?T=_?C(Nd,{}):C(eo,{}):b==="success"&&(T=_?C(NI,{}):C(lx,{})),C("span",{className:`${x}-text`,title:typeof T=="string"?T:void 0,children:T})},[c,l,p,b,u,x,v]),P=Array.isArray(a)?a[0]:a,N=typeof a=="string"||Array.isArray(a)?a:void 0;let I;u==="line"?I=i?C(TB,{...Object.assign({},e,{strokeColor:N,prefixCls:x,steps:i}),children:R}):C(IB,{...Object.assign({},e,{strokeColor:P,prefixCls:x,direction:y}),children:R}):(u==="circle"||u==="dashboard")&&(I=C(yB,{...Object.assign({},e,{strokeColor:P,prefixCls:x,progressStatus:b}),children:R}));const z=te(x,`${x}-status-${b}`,`${x}-${u==="dashboard"&&"circle"||i&&"steps"||u}`,{[`${x}-inline-circle`]:u==="circle"&&mf(s,"circle")[0]<=20,[`${x}-show-info`]:c,[`${x}-${s}`]:typeof s=="string",[`${x}-rtl`]:y==="rtl"},S==null?void 0:S.className,r,o,E,w);return $(C("div",{...Object.assign({ref:t,style:Object.assign(Object.assign({},S==null?void 0:S.style),h),className:z,role:"progressbar","aria-valuenow":p},lr(g,["trailColor","strokeWidth","width","gapDegree","gapPosition","strokeLinecap","success","successPercent"])),children:I}))}),DB=AB,LB=e=>{const{paddingXXS:t,lineWidth:n,tagPaddingHorizontal:r,componentCls:o,calc:i}=e,a=i(r).sub(n).equal(),l=i(t).sub(n).equal();return{[o]:Object.assign(Object.assign({},Qt(e)),{display:"inline-block",height:"auto",marginInlineEnd:e.marginXS,paddingInline:a,fontSize:e.tagFontSize,lineHeight:e.tagLineHeight,whiteSpace:"nowrap",background:e.defaultBg,border:`${X(e.lineWidth)} ${e.lineType} ${e.colorBorder}`,borderRadius:e.borderRadiusSM,opacity:1,transition:`all ${e.motionDurationMid}`,textAlign:"start",position:"relative",[`&${o}-rtl`]:{direction:"rtl"},"&, a, a:hover":{color:e.defaultColor},[`${o}-close-icon`]:{marginInlineStart:l,fontSize:e.tagIconSize,color:e.colorTextDescription,cursor:"pointer",transition:`all ${e.motionDurationMid}`,"&:hover":{color:e.colorTextHeading}},[`&${o}-has-color`]:{borderColor:"transparent",[`&, a, a:hover, ${e.iconCls}-close, ${e.iconCls}-close:hover`]:{color:e.colorTextLightSolid}},["&-checkable"]:{backgroundColor:"transparent",borderColor:"transparent",cursor:"pointer",[`&:not(${o}-checkable-checked):hover`]:{color:e.colorPrimary,backgroundColor:e.colorFillSecondary},"&:active, &-checked":{color:e.colorTextLightSolid},"&-checked":{backgroundColor:e.colorPrimary,"&:hover":{backgroundColor:e.colorPrimaryHover}},"&:active":{backgroundColor:e.colorPrimaryActive}},["&-hidden"]:{display:"none"},[`> ${e.iconCls} + span, > span + ${e.iconCls}`]:{marginInlineStart:a}}),[`${o}-borderless`]:{borderColor:"transparent",background:e.tagBorderlessBg}}},Nm=e=>{const{lineWidth:t,fontSizeIcon:n,calc:r}=e,o=e.fontSizeSM;return $t(e,{tagFontSize:o,tagLineHeight:X(r(e.lineHeightSM).mul(o).equal()),tagIconSize:r(n).sub(r(t).mul(2)).equal(),tagPaddingHorizontal:8,tagBorderlessBg:e.defaultBg})},_m=e=>({defaultBg:new Mt(e.colorFillQuaternary).onBackground(e.colorBgContainer).toHexString(),defaultColor:e.colorText}),T$=vn("Tag",e=>{const t=Nm(e);return LB(t)},_m);var zB=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{const{prefixCls:n,style:r,className:o,checked:i,onChange:a,onClick:l}=e,s=zB(e,["prefixCls","style","className","checked","onChange","onClick"]),{getPrefixCls:c,tag:u}=f.exports.useContext(ot),d=m=>{a==null||a(!i),l==null||l(m)},v=c("tag",n),[h,g,p]=T$(v),b=te(v,`${v}-checkable`,{[`${v}-checkable-checked`]:i},u==null?void 0:u.className,o,g,p);return h(C("span",{...Object.assign({},s,{ref:t,style:Object.assign(Object.assign({},r),u==null?void 0:u.style),className:b,onClick:d})}))}),kB=FB,BB=e=>ow(e,(t,n)=>{let{textColor:r,lightBorderColor:o,lightColor:i,darkColor:a}=n;return{[`${e.componentCls}${e.componentCls}-${t}`]:{color:r,background:i,borderColor:o,"&-inverse":{color:e.colorTextLightSolid,background:a,borderColor:a},[`&${e.componentCls}-borderless`]:{borderColor:"transparent"}}}}),jB=Kh(["Tag","preset"],e=>{const t=Nm(e);return BB(t)},_m);function HB(e){return typeof e!="string"?e:e.charAt(0).toUpperCase()+e.slice(1)}const Bc=(e,t,n)=>{const r=HB(n);return{[`${e.componentCls}${e.componentCls}-${t}`]:{color:e[`color${n}`],background:e[`color${r}Bg`],borderColor:e[`color${r}Border`],[`&${e.componentCls}-borderless`]:{borderColor:"transparent"}}}},WB=Kh(["Tag","status"],e=>{const t=Nm(e);return[Bc(t,"success","Success"),Bc(t,"processing","Info"),Bc(t,"error","Error"),Bc(t,"warning","Warning")]},_m);var VB=globalThis&&globalThis.__rest||function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var o=0,r=Object.getOwnPropertySymbols(e);o{const{prefixCls:n,className:r,rootClassName:o,style:i,children:a,icon:l,color:s,onClose:c,closeIcon:u,closable:d,bordered:v=!0}=e,h=VB(e,["prefixCls","className","rootClassName","style","children","icon","color","onClose","closeIcon","closable","bordered"]),{getPrefixCls:g,direction:p,tag:b}=f.exports.useContext(ot),[m,y]=f.exports.useState(!0);f.exports.useEffect(()=>{"visible"in h&&y(h.visible)},[h.visible]);const S=d2(s),x=ID(s),$=S||x,E=Object.assign(Object.assign({backgroundColor:s&&!$?s:void 0},b==null?void 0:b.style),i),w=g("tag",n),[R,P,N]=T$(w),I=te(w,b==null?void 0:b.className,{[`${w}-${s}`]:$,[`${w}-has-color`]:s&&!$,[`${w}-hidden`]:!m,[`${w}-rtl`]:p==="rtl",[`${w}-borderless`]:!v},r,o,P,N),z=M=>{M.stopPropagation(),c==null||c(M),!M.defaultPrevented&&y(!1)},[,F]=m6(d,u!=null?u:b==null?void 0:b.closeIcon,M=>M===null?C(eo,{className:`${w}-close-icon`,onClick:z}):C("span",{className:`${w}-close-icon`,onClick:z,children:M}),null,!1),T=typeof h.onClick=="function"||a&&a.type==="a",D=l||null,_=D?ie(Tt,{children:[D,a&&C("span",{children:a})]}):a,O=ie("span",{...Object.assign({},h,{ref:t,className:I,style:E}),children:[_,F,S&&C(jB,{prefixCls:w},"preset"),x&&C(WB,{prefixCls:w},"status")]});return R(T?C(Qh,{component:"Tag",children:O}):O)},N$=f.exports.forwardRef(UB);N$.CheckableTag=kB;const oa=N$;function YB(e){return window.go.main.App.ExportWeChatAllData(e)}function GB(){return window.go.main.App.GetAppVersion()}function KB(){return window.go.main.App.GetWeChatAllInfo()}function qB(e){return window.go.main.App.GetWeChatRoomUserList(e)}function XB(e){return window.go.main.App.GetWechatMessageDate(e)}function QB(e,t,n,r,o){return window.go.main.App.GetWechatMessageListByKeyWord(e,t,n,r,o)}function p1(e,t,n,r){return window.go.main.App.GetWechatMessageListByTime(e,t,n,r)}function ZB(e,t){return window.go.main.App.GetWechatSessionList(e,t)}function JB(e,t){return window.go.main.App.OpenFileOrExplorer(e,t)}function e9(){return window.go.main.App.WeChatInit()}const t9="useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";let Am=(e=21)=>{let t="",n=crypto.getRandomValues(new Uint8Array(e));for(;e--;)t+=t9[n[e]&63];return t};function Ts(e){window.runtime.LogInfo(e)}function n9(e,t,n){return window.runtime.EventsOnMultiple(e,t,n)}function _$(e,t){return n9(e,t,-1)}function A$(e,...t){return window.runtime.EventsOff(e,...t)}function r9(){window.runtime.WindowToggleMaximise()}function o9(){window.runtime.WindowMinimise()}function i9(e){window.runtime.BrowserOpenURL(e)}function a9(){window.runtime.Quit()}function l9(e,t){let n;return function(...r){n&&clearTimeout(n),n=setTimeout(()=>{e.apply(this,r)},t)}}function s9(e){return C("div",{className:"wechat-SearchBar",children:C(ai,{theme:{components:{Input:{activeBorderColor:"#E3E4E5",activeShadow:"#E3E4E5",hoverBorderColor:"#E3E4E5"}}},children:C(C$,{className:"wechat-SearchBar-Input",placeholder:"\u641C\u7D22",prefix:C(_d,{}),allowClear:!0,onChange:t=>e.onChange(t.target.value)})})})}function c9(e){return ie("div",{className:`${e.className} wechat-UserItem`,onClick:e.onClick,tabIndex:"0",children:[C(Yo,{id:"wechat-UserItem-content-Avatar-id",className:"wechat-UserItem-content-Avatar",src:e.Avatar,size:{xs:45,sm:45,md:45,lg:45,xl:45,xxl:45},shape:"square",alt:"\u65E0\u6CD5\u52A0\u8F7D\u5934\u50CF"}),ie("div",{className:"wechat-UserItem-content",children:[C("div",{className:"wechat-UserItem-content-text wechat-UserItem-content-name",children:e.name}),C("div",{className:"wechat-UserItem-content-text wechat-UserItem-content-msg",children:e.msg})]}),C("div",{className:"wechat-UserItem-date",children:e.date})]})}function u9(e){const t=new Date(e*1e3),n=t.getFullYear(),r=t.getMonth()+1,o=t.getDate();return t.getHours(),t.getMinutes(),t.getSeconds(),`${n-2e3}/${r}/${o}`}function d9(e){const[t,n]=f.exports.useState(null),[r,o]=f.exports.useState(0),[i,a]=f.exports.useState(!0),[l,s]=f.exports.useState([]),[c,u]=f.exports.useState(""),d=(g,p)=>{n(g),e.onClickItem&&e.onClickItem(p)};f.exports.useEffect(()=>{i&&e.selfName!==""&&ZB(r,20).then(g=>{var p=JSON.parse(g);if(p.Total>0){let b=[];p.Rows.forEach(m=>{m.UserName.startsWith("gh_")||b.push(m)}),s(m=>[...m,...b]),o(m=>m+1)}else a(!1)})},[r,i,e.selfName]);const v=f.exports.useCallback(l9(g=>{console.log(g),u(g)},400),[]),h=l.filter(g=>g.NickName.includes(c));return ie("div",{className:"wechat-UserList",onClick:e.onClick,children:[C(s9,{onChange:v}),C("div",{className:"wechat-UserList-Items",children:h.map((g,p)=>C(c9,{className:t===p?"selectedItem":"",onClick:()=>{d(p,g)},name:g.NickName,msg:g.Content,date:u9(g.Time),Avatar:g.UserInfo.SmallHeadImgUrl},Am()))})]})}const ia={INIT:"normal",START:"active",END:"success",ERROR:"exception"};function f9({info:e,appVersion:t}){const[n,r]=f.exports.useState({});return f.exports.useEffect(()=>{r({PID:e.PID,path:e.FilePath,version:e.Version!==""?e.Version+" "+(e.Is64Bits?"64bits":"32bits"):"\u7248\u672C\u83B7\u53D6\u5931\u8D25",userName:e.AcountName,result:e.DBkey&&e.DBkey.length>0?"success":"failed"})},[e]),ie(Tt,{children:[C("div",{children:"\u5F53\u524D\u767B\u9646\u7684\u5FAE\u4FE1\u4FE1\u606F"}),ie("div",{className:"WechatInfoTable",children:[ie("div",{className:"WechatInfoTable-column",children:[C("div",{children:"wechatDataBackup \u7248\u672C:"}),C(oa,{className:"WechatInfoTable-column-tag",color:"success",children:t})]}),ie("div",{className:"WechatInfoTable-column",children:[C("div",{children:"\u8FDB\u7A0BPID:"}),C(oa,{className:"WechatInfoTable-column-tag",color:n.PID===0?"red":"success",children:n.PID===0?"\u5F53\u524D\u6CA1\u6709\u6253\u5F00\u5FAE\u4FE1":n.PID})]}),ie("div",{className:"WechatInfoTable-column",children:[C("div",{children:"\u6587\u4EF6\u5B58\u50A8\u8DEF\u5F84:"}),C(oa,{className:"WechatInfoTable-column-tag",color:"success",children:n.path})]}),ie("div",{className:"WechatInfoTable-column",children:[C("div",{children:"\u5FAE\u4FE1\u8F6F\u4EF6\u7248\u672C:"}),C(oa,{className:"WechatInfoTable-column-tag",color:"success",children:n.version})]}),ie("div",{className:"WechatInfoTable-column",children:[C("div",{children:"\u5FAE\u4FE1ID:"}),C(oa,{className:"WechatInfoTable-column-tag",color:n.userName===""?"red":"success",children:n.userName===""?"\u5F53\u524D\u6CA1\u6709\u767B\u9646\u5FAE\u4FE1":n.userName})]}),ie("div",{className:"WechatInfoTable-column",children:[C("div",{children:"\u89E3\u5BC6\u7ED3\u679C:"}),C(oa,{className:"WechatInfoTable-column-tag",color:n.result==="success"?"green":"red",children:n.result==="success"?"\u89E3\u5BC6\u6210\u529F":"\u89E3\u5BC6\u5931\u8D25"})]})]})]})}function v9(e){const[t,n]=f.exports.useState(!1),[r,o]=f.exports.useState({}),[i,a]=f.exports.useState(-1),[l,s]=f.exports.useState(ia.INIT),[c,u]=f.exports.useState(""),d=p=>{console.log(p);const b=JSON.parse(p);b.status==="error"?(s(ia.ERROR),a(100)):(s(b.progress!==100?ia.START:ia.END),a(b.progress))},v=()=>{console.log("showModal"),n(!0),KB().then(p=>{console.log(p),o(JSON.parse(p))}),GB().then(p=>{u(p)}),_$("exportData",d)},h=p=>{n(!1),a(-1),s(ia.INIT),A$("exportData"),e.onModalExit&&e.onModalExit()},g=p=>{YB(p),a(0),s(ia.START)};return ie("div",{className:"Setting-Modal-Parent",children:[C("div",{onClick:v,children:e.children}),ie(js,{className:"Setting-Modal",overlayClassName:"Setting-Modal-Overlay",isOpen:t,onRequestClose:h,children:[C("div",{className:"Setting-Modal-button",title:"\u5173\u95ED",onClick:()=>h(),children:C(eo,{className:"Setting-Modal-button-icon"})}),C(f9,{info:r,appVersion:c}),r.DBkey&&r.DBkey.length>0&&C(p9,{onClickExport:g,children:C(Xu,{className:"Setting-Modal-export-button",type:"primary",children:"\u5BFC\u51FA\u6B64\u8D26\u53F7\u6570\u636E"})}),i>-1&&C(DB,{percent:i,status:l})]})]})}const p9=e=>{const[t,n]=f.exports.useState(!1),r=i=>{n(!1)},o=i=>{n(!1),e.onClickExport&&e.onClickExport(i)};return ie("div",{className:"Setting-Modal-confirm-Parent",children:[C("div",{onClick:()=>n(!0),children:e.children}),ie(js,{className:"Setting-Modal-confirm",overlayClassName:"Setting-Modal-confirm-Overlay",isOpen:t,onRequestClose:r,children:[C("div",{className:"Setting-Modal-confirm-title",children:"\u9009\u62E9\u5BFC\u51FA\u65B9\u5F0F"}),ie("div",{className:"Setting-Modal-confirm-buttons",children:[C(Xu,{className:"Setting-Modal-export-button",type:"primary",onClick:()=>o(!0),children:"\u5168\u91CF\u5BFC\u51FA\uFF08\u901F\u5EA6\u6162\uFF09"}),C(Xu,{className:"Setting-Modal-export-button",type:"primary",onClick:()=>o(!1),children:"\u589E\u91CF\u5BFC\u51FA\uFF08\u901F\u5EA6\u5FEB\uFF09"})]})]})]})};function g9(e){const[t,n]=f.exports.useState("chat"),r=o=>{o!=="avatar"&&n(o),e.onClickItem&&e.onClickItem(o)};return ie("div",{className:"wechat-menu",children:[C(Yo,{id:"wechat-menu-item-Avatar",className:"wechat-menu-item wechat-menu-item-Avatar",src:e.Avatar,size:"large",shape:"square",alt:"\u65E0\u6CD5\u52A0\u8F7D\u5934\u50CF",onClick:()=>r("avatar")}),C(Yo,{icon:C($4,{}),title:"\u67E5\u770B\u804A\u5929",className:`wechat-menu-item wechat-menu-item-icon ${t==="chat"?"wechat-menu-selectedColor":""}`,size:"default",onClick:()=>r("chat")}),C(v9,{onModalExit:()=>e.onClickItem("exit"),children:C(Yo,{icon:C(c4,{}),title:"\u8BBE\u7F6E",className:`wechat-menu-item wechat-menu-item-icon ${t==="setting"?"wechat-menu-selectedColor":""}`,size:"default"})})]})}var Ng=function(e,t){return Ng=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(n,r){n.__proto__=r}||function(n,r){for(var o in r)r.hasOwnProperty(o)&&(n[o]=r[o])},Ng(e,t)};function h9(e,t){Ng(e,t);function n(){this.constructor=e}e.prototype=t===null?Object.create(t):(n.prototype=t.prototype,new n)}var es=function(){return es=Object.assign||function(t){for(var n,r=1,o=arguments.length;re?h():t!==!0&&(o=setTimeout(r?g:h,r===void 0?e-d:e))}return c.cancel=s,c}var La={Pixel:"Pixel",Percent:"Percent"},g1={unit:La.Percent,value:.8};function h1(e){return typeof e=="number"?{unit:La.Percent,value:e*100}:typeof e=="string"?e.match(/^(\d*(\.\d+)?)px$/)?{unit:La.Pixel,value:parseFloat(e)}:e.match(/^(\d*(\.\d+)?)%$/)?{unit:La.Percent,value:parseFloat(e)}:(console.warn('scrollThreshold format is invalid. Valid formats: "120px", "50%"...'),g1):(console.warn("scrollThreshold should be string or number"),g1)}var D$=function(e){h9(t,e);function t(n){var r=e.call(this,n)||this;return r.lastScrollTop=0,r.actionTriggered=!1,r.startY=0,r.currentY=0,r.dragging=!1,r.maxPullDownDistance=0,r.getScrollableTarget=function(){return r.props.scrollableTarget instanceof HTMLElement?r.props.scrollableTarget:typeof r.props.scrollableTarget=="string"?document.getElementById(r.props.scrollableTarget):(r.props.scrollableTarget===null&&console.warn(`You are trying to pass scrollableTarget but it is null. This might + happen because the element may not have been added to DOM yet. + See https://github.com/ankeetmaini/react-infinite-scroll-component/issues/59 for more info. + `),null)},r.onStart=function(o){r.lastScrollTop||(r.dragging=!0,o instanceof MouseEvent?r.startY=o.pageY:o instanceof TouchEvent&&(r.startY=o.touches[0].pageY),r.currentY=r.startY,r._infScroll&&(r._infScroll.style.willChange="transform",r._infScroll.style.transition="transform 0.2s cubic-bezier(0,0,0.31,1)"))},r.onMove=function(o){!r.dragging||(o instanceof MouseEvent?r.currentY=o.pageY:o instanceof TouchEvent&&(r.currentY=o.touches[0].pageY),!(r.currentY=Number(r.props.pullDownToRefreshThreshold)&&r.setState({pullToRefreshThresholdBreached:!0}),!(r.currentY-r.startY>r.maxPullDownDistance*1.5)&&r._infScroll&&(r._infScroll.style.overflow="visible",r._infScroll.style.transform="translate3d(0px, "+(r.currentY-r.startY)+"px, 0px)")))},r.onEnd=function(){r.startY=0,r.currentY=0,r.dragging=!1,r.state.pullToRefreshThresholdBreached&&(r.props.refreshFunction&&r.props.refreshFunction(),r.setState({pullToRefreshThresholdBreached:!1})),requestAnimationFrame(function(){r._infScroll&&(r._infScroll.style.overflow="auto",r._infScroll.style.transform="none",r._infScroll.style.willChange="unset")})},r.onScrollListener=function(o){typeof r.props.onScroll=="function"&&setTimeout(function(){return r.props.onScroll&&r.props.onScroll(o)},0);var i=r.props.height||r._scrollableNode?o.target:document.documentElement.scrollTop?document.documentElement:document.body;if(!r.actionTriggered){var a=r.props.inverse?r.isElementAtTop(i,r.props.scrollThreshold):r.isElementAtBottom(i,r.props.scrollThreshold);a&&r.props.hasMore&&(r.actionTriggered=!0,r.setState({showLoader:!0}),r.props.next&&r.props.next()),r.lastScrollTop=i.scrollTop}},r.state={showLoader:!1,pullToRefreshThresholdBreached:!1,prevDataLength:n.dataLength},r.throttledOnScrollListener=m9(150,r.onScrollListener).bind(r),r.onStart=r.onStart.bind(r),r.onMove=r.onMove.bind(r),r.onEnd=r.onEnd.bind(r),r}return t.prototype.componentDidMount=function(){if(typeof this.props.dataLength>"u")throw new Error('mandatory prop "dataLength" is missing. The prop is needed when loading more content. Check README.md for usage');if(this._scrollableNode=this.getScrollableTarget(),this.el=this.props.height?this._infScroll:this._scrollableNode||window,this.el&&this.el.addEventListener("scroll",this.throttledOnScrollListener),typeof this.props.initialScrollY=="number"&&this.el&&this.el instanceof HTMLElement&&this.el.scrollHeight>this.props.initialScrollY&&this.el.scrollTo(0,this.props.initialScrollY),this.props.pullDownToRefresh&&this.el&&(this.el.addEventListener("touchstart",this.onStart),this.el.addEventListener("touchmove",this.onMove),this.el.addEventListener("touchend",this.onEnd),this.el.addEventListener("mousedown",this.onStart),this.el.addEventListener("mousemove",this.onMove),this.el.addEventListener("mouseup",this.onEnd),this.maxPullDownDistance=this._pullDown&&this._pullDown.firstChild&&this._pullDown.firstChild.getBoundingClientRect().height||0,this.forceUpdate(),typeof this.props.refreshFunction!="function"))throw new Error(`Mandatory prop "refreshFunction" missing. + Pull Down To Refresh functionality will not work + as expected. Check README.md for usage'`)},t.prototype.componentWillUnmount=function(){this.el&&(this.el.removeEventListener("scroll",this.throttledOnScrollListener),this.props.pullDownToRefresh&&(this.el.removeEventListener("touchstart",this.onStart),this.el.removeEventListener("touchmove",this.onMove),this.el.removeEventListener("touchend",this.onEnd),this.el.removeEventListener("mousedown",this.onStart),this.el.removeEventListener("mousemove",this.onMove),this.el.removeEventListener("mouseup",this.onEnd)))},t.prototype.componentDidUpdate=function(n){this.props.dataLength!==n.dataLength&&(this.actionTriggered=!1,this.setState({showLoader:!1}))},t.getDerivedStateFromProps=function(n,r){var o=n.dataLength!==r.prevDataLength;return o?es(es({},r),{prevDataLength:n.dataLength}):null},t.prototype.isElementAtTop=function(n,r){r===void 0&&(r=.8);var o=n===document.body||n===document.documentElement?window.screen.availHeight:n.clientHeight,i=h1(r);return i.unit===La.Pixel?n.scrollTop<=i.value+o-n.scrollHeight+1:n.scrollTop<=i.value/100+o-n.scrollHeight+1},t.prototype.isElementAtBottom=function(n,r){r===void 0&&(r=.8);var o=n===document.body||n===document.documentElement?window.screen.availHeight:n.clientHeight,i=h1(r);return i.unit===La.Pixel?n.scrollTop+o>=n.scrollHeight-i.value:n.scrollTop+o>=i.value/100*n.scrollHeight},t.prototype.render=function(){var n=this,r=es({height:this.props.height||"auto",overflow:"auto",WebkitOverflowScrolling:"touch"},this.props.style),o=this.props.hasChildren||!!(this.props.children&&this.props.children instanceof Array&&this.props.children.length),i=this.props.pullDownToRefresh&&this.props.height?{overflow:"auto"}:{};return C("div",{style:i,className:"infinite-scroll-component__outerdiv",children:ie("div",{className:"infinite-scroll-component "+(this.props.className||""),ref:function(a){return n._infScroll=a},style:r,children:[this.props.pullDownToRefresh&&C("div",{style:{position:"relative"},ref:function(a){return n._pullDown=a},children:C("div",{style:{position:"absolute",left:0,right:0,top:-1*this.maxPullDownDistance},children:this.state.pullToRefreshThresholdBreached?this.props.releaseToRefreshContent:this.props.pullDownToRefreshContent})}),this.props.children,!this.state.showLoader&&!o&&this.props.hasMore&&this.props.loader,this.state.showLoader&&this.props.hasMore&&this.props.loader,!this.props.hasMore&&this.props.endMessage]})})},t}(f.exports.Component);const y9=f.exports.forwardRef((e,t)=>{let n=!1,r=!1;e.message.position==="middle"?n=!0:r=e.message.position!=="right";const o=f.exports.useMemo(()=>e.renderMessageContent(e.message),[e.message]);return ie("div",{className:"MessageBubble",id:e.id,ref:t,children:[C("time",{className:"Time",dateTime:Lt(e.message.createdAt).format(),children:Lt(e.message.createdAt*1e3).format("YYYY\u5E74M\u6708D\u65E5 HH:mm")}),n?o:ie("div",{className:"MessageBubble-content"+(r?"-left":"-right"),children:[C("div",{className:"MessageBubble-content-Avatar",children:r&&C(Yo,{className:"MessageBubble-Avatar-left",src:e.message.user.avatar,size:{xs:40,sm:40,md:40,lg:40,xl:40,xxl:40},shape:"square",alt:"\u65E0\u6CD5\u52A0\u8F7D\u5934\u50CF"})}),ie("div",{className:"Bubble"+(r?"-left":"-right"),children:[C("div",{className:"MessageBubble-Name"+(r?"-left":"-right"),truncate:1,children:e.message.user.name}),o]}),C("div",{className:"MessageBubble-content-Avatar",children:!r&&C(Yo,{className:"MessageBubble-Avatar-right",src:e.message.user.avatar,size:{xs:40,sm:40,md:40,lg:40,xl:40,xxl:40},shape:"square",alt:"\u65E0\u6CD5\u52A0\u8F7D\u5934\u50CF"})})]})]})});function b9(e){const t=f.exports.useRef(),n=f.exports.useRef(0),r=f.exports.useRef(null),o=a=>{a.srcElement.scrollTop>0&&a.srcElement.scrollTop<1&&(a.srcElement.scrollTop=0),a.srcElement.scrollTop===0?(n.current=a.srcElement.scrollHeight,r.current=a.srcElement,e.atBottom&&e.atBottom()):(n.current=0,r.current=null)};function i(){e.next()}return f.exports.useEffect(()=>{n.current!==0&&r.current&&(r.current.scrollTop=-(r.current.scrollHeight-n.current),n.current=0,r.current=null)},[e.messages]),f.exports.useEffect(()=>{t.current&&t.current.scrollIntoView()},[e.messages]),C("div",{id:"scrollableDiv",children:C(D$,{scrollableTarget:"scrollableDiv",dataLength:e.messages.length,next:i,hasMore:e.hasMore,inverse:!0,onScroll:o,children:e.messages.map(a=>C(y9,{message:a,renderMessageContent:e.renderMessageContent,id:a.key,ref:a.key===e.scrollIntoId?t:null},a.key))})})}function S9(e){return C("div",{className:"ChatUi",children:C(b9,{messages:e.messages,next:e.fetchMoreData,hasMore:e.hasMore,renderMessageContent:e.renderMessageContent,atBottom:e.atBottom,scrollIntoId:e.scrollIntoId})})}function L$(e){const[t,n]=f.exports.useState(e);return{messages:t,prependMsgs:a=>{n(a.concat(t))},appendMsgs:a=>{n(t.concat(a))},setMsgs:a=>{n(a)}}}const C9="data:image/png;base64,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",x9="/assets/emoji.b5d5ea11.png",w9="/assets/001_\u5FAE\u7B11.1ec7a344.png",$9="/assets/002_\u6487\u5634.0279218b.png",E9="/assets/003_\u8272.e92bb91a.png",M9="/assets/004_\u53D1\u5446.8d849292.png",O9="/assets/005_\u5F97\u610F.72060784.png",R9="/assets/006_\u6D41\u6CEA.f52e5f23.png",I9="/assets/007_\u5BB3\u7F9E.414541cc.png",P9="/assets/008_\u95ED\u5634.4b6c78a6.png",T9="/assets/009_\u7761.75e64219.png",N9="/assets/010_\u5927\u54ED.2cd2fee3.png",_9="/assets/011_\u5C34\u5C2C.70cfea1c.png",A9="/assets/012_\u53D1\u6012.b88ce021.png",D9="/assets/013_\u8C03\u76AE.f3363541.png",L9="/assets/014_\u5472\u7259.3cd1fb7c.png",z9="/assets/015_\u60CA\u8BB6.c9eb5e15.png",F9="/assets/016_\u96BE\u8FC7.5d872489.png",k9="/assets/017_\u56E7.59ee6551.png",B9="/assets/018_\u6293\u72C2.d1646df8.png",j9="/assets/019_\u5410.51bb226f.png",H9="/assets/020_\u5077\u7B11.59941b0b.png",W9="/assets/021_\u6109\u5FEB.47582f99.png",V9="/assets/022_\u767D\u773C.ca492234.png",U9="/assets/023_\u50B2\u6162.651b4c79.png",Y9="/assets/024_\u56F0.4556c7db.png",G9="/assets/025_\u60CA\u6050.ed5cfeab.png",K9="/assets/026_\u61A8\u7B11.6d317a05.png",q9="/assets/027_\u60A0\u95F2.cef28253.png",X9="/assets/028_\u5492\u9A82.a26d48fa.png",Q9="/assets/029_\u7591\u95EE.aaa09269.png",Z9="/assets/030_\u5618.40e8213d.png",J9="/assets/031_\u6655.44e3541a.png",ej="/assets/032_\u8870.1a3910a6.png",tj="/assets/033_\u9AB7\u9AC5.3c9202dc.png",nj="/assets/034_\u6572\u6253.b2798ca7.png",rj="/assets/035_\u518D\u89C1.db23652c.png",oj="/assets/036_\u64E6\u6C57.b46fa893.png",ij="/assets/037_\u62A0\u9F3B.64bc8033.png",aj="/assets/038_\u9F13\u638C.2a84e4c7.png",lj="/assets/039_\u574F\u7B11.4998b91f.png",sj="/assets/040_\u53F3\u54FC\u54FC.27d8126d.png",cj="/assets/041_\u9119\u89C6.7e22890d.png",uj="/assets/042_\u59D4\u5C48.a5caf83a.png",dj="/assets/043_\u5FEB\u54ED\u4E86.62b1b67c.png",fj="/assets/044_\u9634\u9669.3697222b.png",vj="/assets/045_\u4EB2\u4EB2.dfa6bbdf.png",pj="/assets/046_\u53EF\u601C.634845ad.png",gj="/assets/047_\u7B11\u8138.ab25a28c.png",hj="/assets/048_\u751F\u75C5.cd7aadb3.png",mj="/assets/049_\u8138\u7EA2.9ecb5c1c.png",yj="/assets/050_\u7834\u6D95\u4E3A\u7B11.a3d2342d.png",bj="/assets/051_\u6050\u60E7.7af18313.png",Sj="/assets/052_\u5931\u671B.87e0479b.png",Cj="/assets/053_\u65E0\u8BED.6220ee7c.png",xj="/assets/054_\u563F\u54C8.2116e692.png",wj="/assets/055_\u6342\u8138.28f3a0d3.png",$j="/assets/056_\u5978\u7B11.9cf99423.png",Ej="/assets/057_\u673A\u667A.93c3d05a.png",Mj="/assets/058_\u76B1\u7709.efe09ed7.png",Oj="/assets/059_\u8036.a6bc3d2b.png",Rj="/assets/060_\u5403\u74DC.a2a158de.png",Ij="/assets/061_\u52A0\u6CB9.77c81f5b.png",Pj="/assets/062_\u6C57.be95535c.png",Tj="/assets/063_\u5929\u554A.a8355bf9.png",Nj="/assets/064_Emm.787be530.png",_j="/assets/065_\u793E\u4F1A\u793E\u4F1A.a5f5902a.png",Aj="/assets/066_\u65FA\u67F4.7825a175.png",Dj="/assets/067_\u597D\u7684.a9fffc64.png",Lj="/assets/068_\u6253\u8138.560c8d1f.png",zj="/assets/069_\u54C7.74cdcc27.png",Fj="/assets/070_\u7FFB\u767D\u773C.ecb744e2.png",kj="/assets/071_666.281fb9b6.png",Bj="/assets/072_\u8BA9\u6211\u770B\u770B.cee96a9f.png",jj="/assets/073_\u53F9\u6C14.712846f3.png",Hj="/assets/074_\u82E6\u6DA9.4edf4f58.png",Wj="/assets/075_\u88C2\u5F00.3fb97804.png",Vj="/assets/076_\u5634\u5507.59b9c0be.png",Uj="/assets/077_\u7231\u5FC3.a09c823b.png",Yj="/assets/078_\u5FC3\u788E.9a4fb37d.png",Gj="/assets/079_\u62E5\u62B1.e529a46b.png",Kj="/assets/080_\u5F3A.64fe98a8.png",qj="/assets/081_\u5F31.07ddf3a5.png",Xj="/assets/082_\u63E1\u624B.aeb86265.png",Qj="/assets/083_\u80DC\u5229.e9ff0663.png",Zj="/assets/084_\u62B1\u62F3.0ae5f316.png",Jj="/assets/085_\u52FE\u5F15.a4c3a7b4.png",eH="/assets/086_\u62F3\u5934.2829fdbe.png",tH="/assets/087_OK.fc42db3d.png",nH="/assets/088_\u5408\u5341.58cd6a1d.png",rH="/assets/089_\u5564\u9152.2d022508.png",oH="/assets/090_\u5496\u5561.8f40dc95.png",iH="/assets/091_\u86CB\u7CD5.f01a91ed.png",aH="data:image/png;base64,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",lH="/assets/093_\u51CB\u8C22.aa715ee6.png",sH="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAMAAAD04JH5AAADAFBMVEUAAAD4+PhuZ2D////8/Pw/JhF3d3d5eXk7IAlxZVp3d3d6eHd/fHrd3d2Xl5dCKhOBgYGYmJg5HwuYmJhnZ2c9JBBsamhWPSPu7u5NMxXGx8daPRs7IxFaWlplZWVaWlpCKROXl5ZoaGhaWlpDKhVdXV2GhoVBKRZiYmKNjY17e3tHMB1AKBN9fXxbPhs8JRJ0dHTCwsJXPCA/JxKkpKS1tbV3dHFnZ2djY2NBJxG6urpBJxE+JhJ5eXlaWlrW1taDg4PZ2dmdnZ11dXXb29tjY2NGLBRiYmKNjY2SkpKRkZFILhW9vb3CwsJfXFnPz8+hoaE6IxHBwcHj4+PS0tJycnKUlJR0dHS6urpmZmZ3d3d1dXXHx8dbW1tmZmaJiYmDg4NAJhLq6upHLRRiYmK7u7uOjo6fn5+WlpZzc3OamprHx8dZPBo7IxF9fX03Hgo6IhF9fX1fUkhzc3PIyMjFxcVgYGCGhoZ0dHTNzc12dna6urq5ubm6urq6urpiYmJ/f39jY2Pt7e1ZWVnV1dX///9dTD6dnZ3Dw8NOMBecnJzMzMzFxcXOzs6bm5utra3Hx8fKysqZmZmgoKB2dnZxcXGXl5eUlJRMLhaPj4/Jycm3t7dBKBOMjY15eXmqqqpzc3Nra2thYWHBwcGsrKyKi4ujo6N/f39GKxQ4IhCBgYFwcHBtbW2WlpZNLxbPz8+np6eTk5OHh4c1IA8lFwqRkZFSMxg/JhK5ubmFhYUuHA11dXU7JBEoGQumpqaSkpJmZmZUNhhKLhVILBW7u7uioqKDXyeAXSVEKhMyHw4sGww6IAuzs7N9fX14eHhjY2NbPBqDg4NZWVlgQRwhFAm9vb2EhIR/fn5cXFyDYCZKLRQ9Igx7e3toRx5YORmwsLCpqamJiYloaGiCXyZ9WiV7VyR3VCM9JRF8fHxeXl5vTSBkRB7W1tbR0dG/v79zUiHAwMBsSyDT09O1tbVxUCF7dXBwYFHQ0NBzZlqEb089KhxMMhl3bGN2aV5dRy6DXyjjKJ9PAAAAh3RSTlMACQRHaMNDJPRTMBcKBewnEOLc29vTPh4cFhQL9O/u5OLQxsG2sa+qpJiLfnBkVlBPTUREMiUc/Pf39u/o59LGwr+7trKYko+Gem9kY1ZKREM4NScZ+PPu7Obe0s63tKahnJuHgnFkY1xWVD44+fXz7+7l4d/X1tXCuJ2Zj4R9e3p5eG9rVjchCw8JAAAJT0lEQVR42uyXzWvTYBzH4w4KU8GDDBFUUBQdDDypF0UQ8eUgHhRRUTyIbwdBBBUvKh42sjbb0iSllsS8WANtRFMorARsD92tTWmhL4fBbE/tZQz8B3yeNlnmo1ieZ02L0O8/8Pn8fkme7xNqlFFGGWWU/ydj1FBz5fCh99QQc2VfuV6+MLwlTOwrF5v18vlhGUwcKKuGAQzubKeGkW0vIN9IAINDJ6jBZ/uhspqQLU7mlXb9zDZqIEH5nKTrNcky2uWBG+y6A/mFdCzWiC9bCbV+ZpwaZHYdrgN+LS1mzIxYakGDA4M02AH4cH4xLLCCKaZbXKLYPjBBDSpjR+uqwbWqYphlaEYIi+lCx2ArRRhyPkuDsB0DPtved5waSM63AX+5KpoCQ9PTNNxBJNk1eEz5n7EL63wW8KehAQsMdI5vquobyvfcV1VDlkqxjMBAPmpwn/I571RVsSDfmX+jgS0rqupzOT4+VVRkKb4+v2fwJdLQJVkpqr6W43HAtyDfm98zSDXiwCBbPLqD8itb93fnT3nzewqOgeGbAeRnIb+R+uLOjxrEOgbZu7soPzJ+E/BtvZHy9o8YCBnXwI8ryvjuDj8ZQeZHDEqgHJvZg9t94DcVnuvwGZTvvYpCRoQGSvZgvy8I23rx3R2YYrUFDJq7J/rMVwC/loyEUT66A9dAudnPcjxxUDHW+YgAYuBcEHhD2d+/ctzb5acjYQHlo6HdCwI0eNQn/pbDgA8vQD3md3cAiiFdAwZG8UF/BI5lOVsGfHf+XgqMY5BInOqHwc5jKhdaKsV7z4+UIzQoXt68wMWiHZpb+RRGCuDfCq4Bf/LSZvmXOvx8Lhpie/CRcgQGNs/zyuTm+JdPSqG5uXy0oq19YxFOrx00OgaJyU3xsw5/TZvRfjAYAoxTjrzMvyYvx4fO/Lk1TdNmZj4xWDtwDeRzpNU0lZBCKyuAvwr5IHM0jbMDwTGwXp0gu4Bcl5by+Z+Lle78MCs9Df6sZ5m3uNtE5Xiu8H0xGs1VNIcPEshP4+0gI0IDjszgXCy6Wll12K7Bz14GaDl2Dexb4wSPwDYXA4H5hYX5wAaDaAjXoLps8ZxEYjBlmblZEGAQ8AxyIQbTIF0ABsuntxJ8htfNytcgMPgwv9FgCceAdqqJa5EYPOLNSjAYRAwqn/F2AAwKHG8XnhFcUZ7cMHPBr6jB6nfHAKscudrTKRKDcG4WPobfXkXtG+4OoIGt62/xDa6eDi/+YRDQPhLtQNcnx/ANnqdQA+dYJjCIxycJdvAy4hg4XyPesez9v8dtYFC6h//vuuds5C87COQxisH9fyc2SEUX/mKAdSyDHYBytKR49Qj+BeFa1yA4+wE5lhnMcqzWpEKVxGDvkYy7A/JiYMHnGEuXksnkFEVg8KtdMwltIgrj+LgEFLHFSq3bQUHwoCiu4AKiiBc3XBAPgqh4UlFED+JyELVJO00nDbRpMsWDScgcmrZMmilhRkmiWaYeAi1IKq2FpA3UxGrVui/vzaKdN63JTC8e5n8Qb//f93/ffN97bTtcBMgAIegCGWicCM3Nnparh3S8j053uJxoBnAsl5yB3f7M+8ze0NDp8fy8vE4PQZOLEBeDguCxtVR/b/vgYLu31eP5kk1dWqPnjSQQoBm8LXEsA/+Hbnd9TYvnSzwW7ydXL9FFgNehfQDv66XV766vr7e3tIz3D8djmRGfqVzHO60VEtTCU5i4mh7WlFQ/9G9uGQ+m+kfjsfSwpWKjTgKIQOCKxWAtYi/5e5ubx/2WYOr1h+yv9NDAlf063opPXHhtG5qB+dW/h6Ls39n52e+3WIIDPSNDsXS8h923TDPBgRMu8yQZgLFctP7HnU8Ef4Hg3VAmltHVihsggZABgZd2X5f9Ozp+AH9R4R7YiukPkcqL2gnKxAzQxVBtnbp+8AG0NzV9h/4yAWjFLGjF4HLtM+lCWZcZrGc0g67JF4Ps39r00eGQ3MVjAK2YiWVTy9dqJ1gACOSRhNzX1fP3MfQfbGz8+M03AUBqxQxoRUZ7Kx5dgGSA3tfR+qH/15c+h19BEO55NxxPZ94lTFWaCRYiGUxxX5frb2h88ZWjyChKkBKm4qhDeysekwhs6sWg9n/Y0LpydTefzCX6HBaFwnAmxdJD4Z2aW3HLyqdIBtJYtqr9ra0rl86roHia8UUQAtCKcCZlU7lzeghs6lN45K5B/asbF27BsLnbkjxFKtvg70yKv2bOaG3F43tkAnQx1Kj9gda8DIVYMip9i2grwvVYNQ0Cs+rFYLcL/m5744LN4i/dV7G8QGBBFBbX4+g3zetx6Z4uNAP5vg79BwX/hoXQH6qqguJgI0qngLZifDiseSrOv+nCneoM8Pf2apC/6A/ql7VxTpKjmYTUiOhMimdHw8s3aiW49d4sEyjGstcL669/Zv3rL7YBIPBJHyPaCEOj/RGT5sfr7UkzIN64hQtATdlRbKLO5Hiekj9GdCaNjPQEGe13lDsCQZ0iA5yoJV65of9h5K8/TCzHU6SCoM/XJzXC61SUXKX9/X6+SyJw4n/8bbVtxHNvNfBHtLWC5UIKgkR3d3dCIBgYCCaYneWYdgIXTsgZiP5O8LO1Ory97CCm0qI5lIKgrxtKyCBocSRYchOmXQe2yxkQuFg/kBN/cw+bRHPn0BMJogKAT/i/P0JS5HpMDwHIQCaA9UN/86Oz9xdPQRCABOI8iLyEikB/hyPK0PoAsIPbCUJcTU6bTfQ37509awY2FQFPyfPAB/zFABzRBJsER6CXwAkIIAOUDUf81QR0LiHuBYc0Fvx9PiZJryjH9GnDSYKoa2srFAqf6or4iwRckgWNIE5lKQCSClHgM9RNADqxMJYfK3yyEebdiD9KsIMKBJLgGOQ7EgyCZJM8sxbTrcPXcGchn8+P1Rbxh3pQmePAMYAQRAQ/bACao3dUYfp17LrZNpbPFwjzLtRfrSWryVAvF6JZJuGLRqJRH6if40khAP0Ep3BbfkzyL6pz26gARKDYHMPkKDoUCLCmZdi0tBgQOCX/4tpUyYR6ewN8KAkU4np7KeQT0ENwA1ecf5FjWLMjFwoABiDwL7XiCDZtzbh7FvqXqiP7VjA0D905mjQh9evULA3+MIW1qyq3kSS507QfOX+9mj8f06iqI+vXbyqfiRkyZMiQIUOGDBkyZOg/0m/+aqodh3mGTQAAAABJRU5ErkJggg==",cH="/assets/095_\u70B8\u5F39.3dffd8e8.png",uH="/assets/096_\u4FBF\u4FBF.b0d5c50c.png",dH="/assets/097_\u6708\u4EAE.47389834.png",fH="/assets/098_\u592A\u9633.89c3d0ab.png",vH="/assets/099_\u5E86\u795D.2d9e8f8a.png",pH="/assets/100_\u793C\u7269.37ae5ec0.png",gH="data:image/png;base64,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",hH="/assets/102_\u767C.f43fee5c.png",mH="/assets/103_\u798F.58c94555.png",yH="/assets/104_\u70DF\u82B1.61568e1e.png",bH="/assets/105_\u7206\u7AF9.35531687.png",SH="/assets/106_\u732A\u5934.7eb8ff1d.png",CH="/assets/107_\u8DF3\u8DF3.24101efa.png",xH="/assets/108_\u53D1\u6296.3eabd306.png",wH="/assets/109_\u8F6C\u5708.67669ca4.png",m1={"[\u5FAE\u7B11]":w9,"[\u6487\u5634]":$9,"[\u8272]":E9,"[\u53D1\u5446]":M9,"[\u5F97\u610F]":O9,"[\u6D41\u6CEA]":R9,"[\u5BB3\u7F9E]":I9,"[\u95ED\u5634]":P9,"[\u7761]":T9,"[\u5927\u54ED]":N9,"[\u5C34\u5C2C]":_9,"[\u53D1\u6012]":A9,"[\u8C03\u76AE]":D9,"[\u5472\u7259]":L9,"[\u60CA\u8BB6]":z9,"[\u96BE\u8FC7]":F9,"[\u56E7]":k9,"[\u6293\u72C2]":B9,"[\u5410]":j9,"[\u5077\u7B11]":H9,"[\u6109\u5FEB]":W9,"[\u767D\u773C]":V9,"[\u50B2\u6162]":U9,"[\u56F0]":Y9,"[\u60CA\u6050]":G9,"[\u61A8\u7B11]":K9,"[\u60A0\u95F2]":q9,"[\u5492\u9A82]":X9,"[\u7591\u95EE]":Q9,"[\u5618]":Z9,"[\u6655]":J9,"[\u8870]":ej,"[\u9AB7\u9AC5]":tj,"[\u6572\u6253]":nj,"[\u518D\u89C1]":rj,"[\u64E6\u6C57]":oj,"[\u62A0\u9F3B]":ij,"[\u9F13\u638C]":aj,"[\u574F\u7B11]":lj,"[\u53F3\u54FC\u54FC]":sj,"[\u9119\u89C6]":cj,"[\u59D4\u5C48]":uj,"[\u5FEB\u54ED\u4E86]":dj,"[\u9634\u9669]":fj,"[\u4EB2\u4EB2]":vj,"[\u53EF\u601C]":pj,"[\u7B11\u8138]":gj,"[\u751F\u75C5]":hj,"[\u8138\u7EA2]":mj,"[\u7834\u6D95\u4E3A\u7B11]":yj,"[\u6050\u60E7]":bj,"[\u5931\u671B]":Sj,"[\u65E0\u8BED]":Cj,"[\u563F\u54C8]":xj,"[\u6342\u8138]":wj,"[\u5978\u7B11]":$j,"[\u673A\u667A]":Ej,"[\u76B1\u7709]":Mj,"[\u8036]":Oj,"[\u5403\u74DC]":Rj,"[\u52A0\u6CB9]":Ij,"[\u6C57]":Pj,"[\u5929\u554A]":Tj,"[Emm]":Nj,"[\u793E\u4F1A\u793E\u4F1A]":_j,"[\u65FA\u67F4]":Aj,"[\u597D\u7684]":Dj,"[\u6253\u8138]":Lj,"[\u54C7]":zj,"[\u7FFB\u767D\u773C]":Fj,"[666]":kj,"[\u8BA9\u6211\u770B\u770B]":Bj,"[\u53F9\u6C14]":jj,"[\u82E6\u6DA9]":Hj,"[\u88C2\u5F00]":Wj,"[\u5634\u5507]":Vj,"[\u7231\u5FC3]":Uj,"[\u5FC3\u788E]":Yj,"[\u62E5\u62B1]":Gj,"[\u5F3A]":Kj,"[\u5F31]":qj,"[\u63E1\u624B]":Xj,"[\u80DC\u5229]":Qj,"[\u62B1\u62F3]":Zj,"[\u52FE\u5F15]":Jj,"[\u62F3\u5934]":eH,"[OK]":tH,"[\u5408\u5341]":nH,"[\u5564\u9152]":rH,"[\u5496\u5561]":oH,"[\u86CB\u7CD5]":iH,"[\u73AB\u7470]":aH,"[\u51CB\u8C22]":lH,"[\u83DC\u5200]":sH,"[\u70B8\u5F39]":cH,"[\u4FBF\u4FBF]":uH,"[\u6708\u4EAE]":dH,"[\u592A\u9633]":fH,"[\u5E86\u795D]":vH,"[\u793C\u7269]":pH,"[\u7EA2\u5305]":gH,"[\u767C]":hH,"[\u798F]":mH,"[\u70DF\u82B1]":yH,"[\u7206\u7AF9]":bH,"[\u732A\u5934]":SH,"[\u8DF3\u8DF3]":CH,"[\u53D1\u6296]":xH,"[\u8F6C\u5708]":wH},$H=e=>{const t=Object.keys(e).map(n=>n.replace(/[\[\]]/g,"\\$&"));return new RegExp(t.join("|"),"g")},EH=(e,t,n)=>{const r=[];let o=0;e.replace(n,(a,l)=>(o{typeof a=="string"?a.split(` +`).forEach((c,u)=>{u>0&&i.push(C("br",{},`${l}-${u}`)),i.push(c)}):i.push(a)}),i};function Dm(e){const t=f.exports.useMemo(()=>$H(m1),[]),[n,r]=f.exports.useState([]);return f.exports.useEffect(()=>{const o=EH(e.text,m1,t);r(o)},[e.text,t]),C(m$,{className:"CardMessageText "+e.className,size:"small",children:C(Tt,{children:n})})}const MH=e=>!!e&&e[0]==="o",y1=Gn.exports.unstable_batchedUpdates||(e=>e()),aa=(e,t,n=1e-4)=>Math.abs(e-t)e===!0||!!(e&&e[t]),kr=(e,t)=>typeof e=="function"?e(t):e,Lm=(e,t)=>(t&&Object.keys(t).forEach(n=>{const r=e[n],o=t[n];typeof o=="function"&&r?e[n]=(...i)=>{o(...i),r(...i)}:e[n]=o}),e),OH=e=>{if(typeof e!="string")return{top:0,right:0,bottom:0,left:0};const t=e.trim().split(/\s+/,4).map(parseFloat),n=isNaN(t[0])?0:t[0],r=isNaN(t[1])?n:t[1];return{top:n,right:r,bottom:isNaN(t[2])?n:t[2],left:isNaN(t[3])?r:t[3]}},Pv=e=>{for(;e;){if(e=e.parentNode,!e||e===document.body||!e.parentNode)return;const{overflow:t,overflowX:n,overflowY:r}=getComputedStyle(e);if(/auto|scroll|overlay|hidden/.test(t+r+n))return e}};function z$(e,t){return{"aria-disabled":e||void 0,tabIndex:t?0:-1}}function b1(e,t){for(let n=0;nf.exports.useMemo(()=>{const o=t?`${e}__${t}`:e;let i=o;n&&Object.keys(n).forEach(l=>{const s=n[l];s&&(i+=` ${o}--${s===!0?l:`${l}-${s}`}`)});let a=typeof r=="function"?r(n):r;return typeof a=="string"&&(a=a.trim(),a&&(i+=` ${a}`)),i},[e,t,n,r]),RH="szh-menu-container",du="szh-menu",IH="arrow",PH="item",F$=f.exports.createContext(),k$=f.exports.createContext({}),S1=f.exports.createContext({}),B$=f.exports.createContext({}),TH=f.exports.createContext({}),zm=f.exports.createContext({}),co=Object.freeze({ENTER:"Enter",ESC:"Escape",SPACE:" ",HOME:"Home",END:"End",LEFT:"ArrowLeft",RIGHT:"ArrowRight",UP:"ArrowUp",DOWN:"ArrowDown"}),rn=Object.freeze({RESET:0,SET:1,UNSET:2,INCREASE:3,DECREASE:4,FIRST:5,LAST:6,SET_INDEX:7}),Ns=Object.freeze({CLICK:"click",CANCEL:"cancel",BLUR:"blur",SCROLL:"scroll"}),C1=Object.freeze({FIRST:"first",LAST:"last"}),Tv="absolute",NH="presentation",j$="menuitem",x1={"aria-hidden":!0,role:j$},_H=({className:e,containerRef:t,containerProps:n,children:r,isOpen:o,theming:i,transition:a,onClose:l})=>{const s=_g(a,"item");return C("div",{...Lm({onKeyDown:({key:d})=>{switch(d){case co.ESC:kr(l,{key:d,reason:Ns.CANCEL});break}},onBlur:d=>{o&&!d.currentTarget.contains(d.relatedTarget)&&kr(l,{reason:Ns.BLUR})}},n),className:sd({block:RH,modifiers:f.exports.useMemo(()=>({theme:i,itemTransition:s}),[i,s]),className:e}),style:{position:"absolute",...n==null?void 0:n.style},ref:t,children:r})},AH=()=>{let e,t=0;return{toggle:n=>{n?t++:t--,t=Math.max(t,0)},on:(n,r,o)=>{t?e||(e=setTimeout(()=>{e=0,r()},n)):o==null||o()},off:()=>{e&&(clearTimeout(e),e=0)}}},DH=(e,t)=>{const[n,r]=f.exports.useState(),i=f.exports.useRef({items:[],hoverIndex:-1,sorted:!1}).current,a=f.exports.useCallback((s,c)=>{const{items:u}=i;if(!s)i.items=[];else if(c)u.push(s);else{const d=u.indexOf(s);d>-1&&(u.splice(d,1),s.contains(document.activeElement)&&(t.current.focus(),r()))}i.hoverIndex=-1,i.sorted=!1},[i,t]),l=f.exports.useCallback((s,c,u)=>{const{items:d,hoverIndex:v}=i,h=()=>{if(i.sorted)return;const b=e.current.querySelectorAll(".szh-menu__item");d.sort((m,y)=>b1(b,m)-b1(b,y)),i.sorted=!0};let g=-1,p;switch(s){case rn.RESET:break;case rn.SET:p=c;break;case rn.UNSET:p=b=>b===c?void 0:b;break;case rn.FIRST:h(),g=0,p=d[g];break;case rn.LAST:h(),g=d.length-1,p=d[g];break;case rn.SET_INDEX:h(),g=u,p=d[g];break;case rn.INCREASE:h(),g=v,g<0&&(g=d.indexOf(c)),g++,g>=d.length&&(g=0),p=d[g];break;case rn.DECREASE:h(),g=v,g<0&&(g=d.indexOf(c)),g--,g<0&&(g=d.length-1),p=d[g];break}p||(g=-1),r(p),i.hoverIndex=g},[e,i]);return{hoverItem:n,dispatch:l,updateItems:a}},LH=(e,t,n,r)=>{const o=t.current.getBoundingClientRect(),i=e.current.getBoundingClientRect(),a=n===window?{left:0,top:0,right:document.documentElement.clientWidth,bottom:window.innerHeight}:n.getBoundingClientRect(),l=OH(r),s=g=>g+i.left-a.left-l.left,c=g=>g+i.left+o.width-a.right+l.right,u=g=>g+i.top-a.top-l.top,d=g=>g+i.top+o.height-a.bottom+l.bottom;return{menuRect:o,containerRect:i,getLeftOverflow:s,getRightOverflow:c,getTopOverflow:u,getBottomOverflow:d,confineHorizontally:g=>{let p=s(g);if(p<0)g-=p;else{const b=c(g);b>0&&(g-=b,p=s(g),p<0&&(g-=p))}return g},confineVertically:g=>{let p=u(g);if(p<0)g-=p;else{const b=d(g);b>0&&(g-=b,p=u(g),p<0&&(g-=p))}return g}}},zH=({arrowRef:e,menuY:t,anchorRect:n,containerRect:r,menuRect:o})=>{let i=n.top-r.top-t+n.height/2;const a=e.current.offsetHeight*1.25;return i=Math.max(a,i),i=Math.min(i,o.height-a),i},FH=({anchorRect:e,containerRect:t,menuRect:n,placeLeftorRightY:r,placeLeftX:o,placeRightX:i,getLeftOverflow:a,getRightOverflow:l,confineHorizontally:s,confineVertically:c,arrowRef:u,arrow:d,direction:v,position:h})=>{let g=v,p=r;h!=="initial"&&(p=c(p),h==="anchor"&&(p=Math.min(p,e.bottom-t.top),p=Math.max(p,e.top-t.top-n.height)));let b,m,y;return g==="left"?(b=o,h!=="initial"&&(m=a(b),m<0&&(y=l(i),(y<=0||-m>y)&&(b=i,g="right")))):(b=i,h!=="initial"&&(y=l(b),y>0&&(m=a(o),(m>=0||-m{let i=n.left-r.left-t+n.width/2;const a=e.current.offsetWidth*1.25;return i=Math.max(a,i),i=Math.min(i,o.width-a),i},BH=({anchorRect:e,containerRect:t,menuRect:n,placeToporBottomX:r,placeTopY:o,placeBottomY:i,getTopOverflow:a,getBottomOverflow:l,confineHorizontally:s,confineVertically:c,arrowRef:u,arrow:d,direction:v,position:h})=>{let g=v==="top"?"top":"bottom",p=r;h!=="initial"&&(p=s(p),h==="anchor"&&(p=Math.min(p,e.right-t.left),p=Math.max(p,e.left-t.left-n.width)));let b,m,y;return g==="top"?(b=o,h!=="initial"&&(m=a(b),m<0&&(y=l(i),(y<=0||-m>y)&&(b=i,g="bottom")))):(b=i,h!=="initial"&&(y=l(b),y>0&&(m=a(o),(m>=0||-m{const{menuRect:c,containerRect:u}=s,d=n==="left"||n==="right";let v=d?r:o,h=d?o:r;if(e){const $=l.current;d?v+=$.offsetWidth:h+=$.offsetHeight}const g=a.left-u.left-c.width-v,p=a.right-u.left+v,b=a.top-u.top-c.height-h,m=a.bottom-u.top+h;let y,S;t==="end"?(y=a.right-u.left-c.width,S=a.bottom-u.top-c.height):t==="center"?(y=a.left-u.left-(c.width-a.width)/2,S=a.top-u.top-(c.height-a.height)/2):(y=a.left-u.left,S=a.top-u.top),y+=v,S+=h;const x={...s,anchorRect:a,placeLeftX:g,placeRightX:p,placeLeftorRightY:S,placeTopY:b,placeBottomY:m,placeToporBottomX:y,arrowRef:l,arrow:e,direction:n,position:i};switch(n){case"left":case"right":return FH(x);case"top":case"bottom":default:return BH(x)}},fu=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u"?f.exports.useLayoutEffect:f.exports.useEffect;function w1(e,t){typeof e=="function"?e(t):e.current=t}const H$=(e,t)=>f.exports.useMemo(()=>e?t?n=>{w1(e,n),w1(t,n)}:e:t,[e,t]),$1=-9999,HH=({ariaLabel:e,menuClassName:t,menuStyle:n,arrow:r,arrowProps:o={},anchorPoint:i,anchorRef:a,containerRef:l,containerProps:s,focusProps:c,externalRef:u,parentScrollingRef:d,align:v="start",direction:h="bottom",position:g="auto",overflow:p="visible",setDownOverflow:b,repositionFlag:m,captureFocus:y=!0,state:S,endTransition:x,isDisabled:$,menuItemFocus:E,gap:w=0,shift:R=0,children:P,onClose:N,...I})=>{const[z,F]=f.exports.useState({x:$1,y:$1}),[T,D]=f.exports.useState({}),[_,O]=f.exports.useState(),[M,L]=f.exports.useState(h),[A]=f.exports.useState(AH),[B,k]=f.exports.useReducer(Ue=>Ue+1,1),{transition:j,boundingBoxRef:H,boundingBoxPadding:W,rootMenuRef:Y,rootAnchorRef:K,scrollNodesRef:q,reposition:ee,viewScroll:Z,submenuCloseDelay:Q}=f.exports.useContext(zm),{submenuCtx:ne,reposSubmenu:ae=m}=f.exports.useContext(S1),J=f.exports.useRef(null),re=f.exports.useRef(),fe=f.exports.useRef(),ve=f.exports.useRef(!1),pe=f.exports.useRef({width:0,height:0}),oe=f.exports.useRef(()=>{}),{hoverItem:se,dispatch:le,updateItems:Ce}=DH(J,re),ce=MH(S),de=_g(j,"open"),xe=_g(j,"close"),he=q.current,ke=Ue=>{switch(Ue.key){case co.HOME:le(rn.FIRST);break;case co.END:le(rn.LAST);break;case co.UP:le(rn.DECREASE,se);break;case co.DOWN:le(rn.INCREASE,se);break;case co.SPACE:Ue.target&&Ue.target.className.indexOf(du)!==-1&&Ue.preventDefault();return;default:return}Ue.preventDefault(),Ue.stopPropagation()},we=()=>{S==="closing"&&O(),kr(x)},ge=Ue=>{Ue.stopPropagation(),A.on(Q,()=>{le(rn.RESET),re.current.focus()})},Pe=Ue=>{Ue.target===Ue.currentTarget&&A.off()},Se=f.exports.useCallback(Ue=>{var He;const Xe=a?(He=a.current)==null?void 0:He.getBoundingClientRect():i?{left:i.x,right:i.x,top:i.y,bottom:i.y,width:0,height:0}:null;if(!Xe)return;he.menu||(he.menu=(H?H.current:Pv(Y.current))||window);const Le=LH(l,J,he.menu,W);let{arrowX:Re,arrowY:be,x:Ae,y:Me,computedDirection:$e}=jH({arrow:r,align:v,direction:h,gap:w,shift:R,position:g,anchorRect:Xe,arrowRef:fe,positionHelpers:Le});const{menuRect:Te}=Le;let ye=Te.height;if(!Ue&&p!=="visible"){const{getTopOverflow:Ge,getBottomOverflow:Ze}=Le;let et,ht;const mt=pe.current.height,ct=Ze(Me);if(ct>0||aa(ct,0)&&aa(ye,mt))et=ye-ct,ht=ct;else{const We=Ge(Me);(We<0||aa(We,0)&&aa(ye,mt))&&(et=ye+We,ht=0-We,et>=0&&(Me-=We))}et>=0?(ye=et,O({height:et,overflowAmt:ht})):O()}r&&D({x:Re,y:be}),F({x:Ae,y:Me}),L($e),pe.current={width:Te.width,height:ye}},[r,v,W,h,w,R,g,p,i,a,l,H,Y,he]);fu(()=>{ce&&(Se(),ve.current&&k()),ve.current=ce,oe.current=Se},[ce,Se,ae]),fu(()=>{_&&!b&&(J.current.scrollTop=0)},[_,b]),fu(()=>Ce,[Ce]),f.exports.useEffect(()=>{let{menu:Ue}=he;if(!ce||!Ue)return;if(Ue=Ue.addEventListener?Ue:window,!he.anchors){he.anchors=[];let Re=Pv(K&&K.current);for(;Re&&Re!==Ue;)he.anchors.push(Re),Re=Pv(Re)}let He=Z;if(he.anchors.length&&He==="initial"&&(He="auto"),He==="initial")return;const Xe=()=>{He==="auto"?y1(()=>Se(!0)):kr(N,{reason:Ns.SCROLL})},Le=he.anchors.concat(Z!=="initial"?Ue:[]);return Le.forEach(Re=>Re.addEventListener("scroll",Xe)),()=>Le.forEach(Re=>Re.removeEventListener("scroll",Xe))},[K,he,ce,N,Z,Se]);const st=!!_&&_.overflowAmt>0;f.exports.useEffect(()=>{if(st||!ce||!d)return;const Ue=()=>y1(Se),He=d.current;return He.addEventListener("scroll",Ue),()=>He.removeEventListener("scroll",Ue)},[ce,st,d,Se]),f.exports.useEffect(()=>{if(typeof ResizeObserver!="function"||ee==="initial")return;const Ue=new ResizeObserver(([Xe])=>{const{borderBoxSize:Le,target:Re}=Xe;let be,Ae;if(Le){const{inlineSize:Me,blockSize:$e}=Le[0]||Le;be=Me,Ae=$e}else{const Me=Re.getBoundingClientRect();be=Me.width,Ae=Me.height}be===0||Ae===0||aa(be,pe.current.width,1)&&aa(Ae,pe.current.height,1)||Gn.exports.flushSync(()=>{oe.current(),k()})}),He=J.current;return Ue.observe(He,{box:"border-box"}),()=>Ue.unobserve(He)},[ee]),f.exports.useEffect(()=>{if(!ce){le(rn.RESET),xe||O();return}const{position:Ue,alwaysUpdate:He}=E||{},Xe=()=>{Ue===C1.FIRST?le(rn.FIRST):Ue===C1.LAST?le(rn.LAST):Ue>=-1&&le(rn.SET_INDEX,void 0,Ue)};if(He)Xe();else if(y){const Le=setTimeout(()=>{const Re=J.current;Re&&!Re.contains(document.activeElement)&&(re.current.focus(),Xe())},de?170:100);return()=>clearTimeout(Le)}},[ce,de,xe,y,E,le]);const nt=f.exports.useMemo(()=>({isParentOpen:ce,submenuCtx:A,dispatch:le,updateItems:Ce}),[ce,A,le,Ce]);let Ne,Ee;_&&(b?Ee=_.overflowAmt:Ne=_.height);const _e=f.exports.useMemo(()=>({reposSubmenu:B,submenuCtx:A,overflow:p,overflowAmt:Ee,parentMenuRef:J,parentDir:M}),[B,A,p,Ee,M]),Be=Ne>=0?{maxHeight:Ne,overflow:p}:void 0,qe=f.exports.useMemo(()=>({state:S,dir:M}),[S,M]),it=f.exports.useMemo(()=>({dir:M}),[M]),ft=sd({block:du,element:IH,modifiers:it,className:o.className}),ut=ie("ul",{role:"menu","aria-label":e,...z$($),...Lm({onPointerEnter:ne==null?void 0:ne.off,onPointerMove:ge,onPointerLeave:Pe,onKeyDown:ke,onAnimationEnd:we},I),ref:H$(u,J),className:sd({block:du,modifiers:qe,className:t}),style:{...n,...Be,margin:0,display:S==="closed"?"none":void 0,position:Tv,left:z.x,top:z.y},children:[C("li",{tabIndex:-1,style:{position:Tv,left:0,top:0,display:"block",outline:"none"},ref:re,...x1,...c}),r&&C("li",{...x1,...o,className:ft,style:{display:"block",position:Tv,left:T.x,top:T.y,...o.style},ref:fe}),C(S1.Provider,{value:_e,children:C(k$.Provider,{value:nt,children:C(F$.Provider,{value:se,children:kr(P,qe)})})})]});return s?C(_H,{...s,isOpen:ce,children:ut}):ut},W$=f.exports.forwardRef(function({"aria-label":t,className:n,containerProps:r,initialMounted:o,unmountOnClose:i,transition:a,transitionTimeout:l,boundingBoxRef:s,boundingBoxPadding:c,reposition:u="auto",submenuOpenDelay:d=300,submenuCloseDelay:v=150,viewScroll:h="initial",portal:g,theming:p,onItemClick:b,...m},y){const S=f.exports.useRef(null),x=f.exports.useRef({}),{anchorRef:$,state:E,onClose:w}=m,R=f.exports.useMemo(()=>({initialMounted:o,unmountOnClose:i,transition:a,transitionTimeout:l,boundingBoxRef:s,boundingBoxPadding:c,rootMenuRef:S,rootAnchorRef:$,scrollNodesRef:x,reposition:u,viewScroll:h,submenuOpenDelay:d,submenuCloseDelay:v}),[o,i,a,l,$,s,c,u,h,d,v]),P=f.exports.useMemo(()=>({handleClick(I,z){I.stopPropagation||kr(b,I);let F=I.keepOpen;F===void 0&&(F=z&&I.key===co.SPACE),F||kr(w,{value:I.value,key:I.key,reason:Ns.CLICK})},handleClose(I){kr(w,{key:I,reason:Ns.CLICK})}}),[b,w]);if(!E)return null;const N=C(zm.Provider,{value:R,children:C(B$.Provider,{value:P,children:C(HH,{...m,ariaLabel:t||"Menu",externalRef:y,containerRef:S,containerProps:{className:n,containerRef:S,containerProps:r,theming:p,transition:a,onClose:w}})})});return g===!0&&typeof document<"u"?Gn.exports.createPortal(N,document.body):g?g.target?Gn.exports.createPortal(N,g.target):g.stablePosition?null:N:N}),WH=(e,t)=>{const n=f.exports.memo(t),r=f.exports.forwardRef((o,i)=>{const a=f.exports.useRef(null);return C(n,{...o,itemRef:a,externalRef:i,isHovering:f.exports.useContext(F$)===a.current})});return r.displayName=`WithHovering(${e})`,r},VH=(e,t,n)=>{fu(()=>{if(e)return;const r=t.current;return n(r,!0),()=>{n(r)}},[e,t,n])},UH=(e,t,n,r)=>{const{submenuCloseDelay:o}=f.exports.useContext(zm),{isParentOpen:i,submenuCtx:a,dispatch:l,updateItems:s}=f.exports.useContext(k$),c=()=>{!n&&!r&&l(rn.SET,e.current)},u=()=>{!r&&l(rn.UNSET,e.current)},d=g=>{n&&!g.currentTarget.contains(g.relatedTarget)&&u()},v=g=>{r||(g.stopPropagation(),a.on(o,c,c))},h=(g,p)=>{a.off(),!p&&u()};return VH(r,e,s),f.exports.useEffect(()=>{n&&i&&t.current&&t.current.focus()},[t,n,i]),{setHover:c,onBlur:d,onPointerMove:v,onPointerLeave:h}},cd=WH("MenuItem",function({className:t,value:n,href:r,type:o,checked:i,disabled:a,children:l,onClick:s,isHovering:c,itemRef:u,externalRef:d,...v}){const h=!!a,{setHover:g,...p}=UH(u,u,c,h),b=f.exports.useContext(B$),m=f.exports.useContext(TH),y=o==="radio",S=o==="checkbox",x=!!r&&!h&&!y&&!S,$=y?m.value===n:S?!!i:!1,E=I=>{if(h){I.stopPropagation(),I.preventDefault();return}const z={value:n,syntheticEvent:I};I.key!==void 0&&(z.key=I.key),S&&(z.checked=!$),y&&(z.name=m.name),kr(s,z),y&&kr(m.onRadioChange,z),b.handleClick(z,S||y)},w=I=>{if(!!c)switch(I.key){case co.ENTER:I.preventDefault();case co.SPACE:x?u.current.click():E(I)}},R=f.exports.useMemo(()=>({type:o,disabled:h,hover:c,checked:$,anchor:x}),[o,h,c,$,x]),P=Lm({...p,onPointerDown:g,onKeyDown:w,onClick:E},v),N={role:y?"menuitemradio":S?"menuitemcheckbox":j$,"aria-checked":y||S?$:void 0,...z$(h,c),...P,ref:H$(d,u),className:sd({block:du,element:PH,modifiers:R,className:t}),children:f.exports.useMemo(()=>kr(l,R),[l,R])};return x?C("li",{role:NH,children:C("a",{href:r,...N})}):C("li",{...N})});var V$={exports:{}};/*! + * clipboard.js v2.0.11 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */(function(e,t){(function(r,o){e.exports=o()})(Hr,function(){return function(){var n={686:function(i,a,l){l.d(a,{default:function(){return B}});var s=l(279),c=l.n(s),u=l(370),d=l.n(u),v=l(817),h=l.n(v);function g(k){try{return document.execCommand(k)}catch{return!1}}var p=function(j){var H=h()(j);return g("cut"),H},b=p;function m(k){var j=document.documentElement.getAttribute("dir")==="rtl",H=document.createElement("textarea");H.style.fontSize="12pt",H.style.border="0",H.style.padding="0",H.style.margin="0",H.style.position="absolute",H.style[j?"right":"left"]="-9999px";var W=window.pageYOffset||document.documentElement.scrollTop;return H.style.top="".concat(W,"px"),H.setAttribute("readonly",""),H.value=k,H}var y=function(j,H){var W=m(j);H.container.appendChild(W);var Y=h()(W);return g("copy"),W.remove(),Y},S=function(j){var H=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},W="";return typeof j=="string"?W=y(j,H):j instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(j==null?void 0:j.type)?W=y(j.value,H):(W=h()(j),g("copy")),W},x=S;function $(k){return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?$=function(H){return typeof H}:$=function(H){return H&&typeof Symbol=="function"&&H.constructor===Symbol&&H!==Symbol.prototype?"symbol":typeof H},$(k)}var E=function(){var j=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},H=j.action,W=H===void 0?"copy":H,Y=j.container,K=j.target,q=j.text;if(W!=="copy"&&W!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(K!==void 0)if(K&&$(K)==="object"&&K.nodeType===1){if(W==="copy"&&K.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(W==="cut"&&(K.hasAttribute("readonly")||K.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if(q)return x(q,{container:Y});if(K)return W==="cut"?b(K):x(K,{container:Y})},w=E;function R(k){return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?R=function(H){return typeof H}:R=function(H){return H&&typeof Symbol=="function"&&H.constructor===Symbol&&H!==Symbol.prototype?"symbol":typeof H},R(k)}function P(k,j){if(!(k instanceof j))throw new TypeError("Cannot call a class as a function")}function N(k,j){for(var H=0;H"u"||!Reflect.construct||Reflect.construct.sham)return!1;if(typeof Proxy=="function")return!0;try{return Date.prototype.toString.call(Reflect.construct(Date,[],function(){})),!0}catch{return!1}}function M(k){return M=Object.setPrototypeOf?Object.getPrototypeOf:function(H){return H.__proto__||Object.getPrototypeOf(H)},M(k)}function L(k,j){var H="data-clipboard-".concat(k);if(!!j.hasAttribute(H))return j.getAttribute(H)}var A=function(k){z(H,k);var j=T(H);function H(W,Y){var K;return P(this,H),K=j.call(this),K.resolveOptions(Y),K.listenClick(W),K}return I(H,[{key:"resolveOptions",value:function(){var Y=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof Y.action=="function"?Y.action:this.defaultAction,this.target=typeof Y.target=="function"?Y.target:this.defaultTarget,this.text=typeof Y.text=="function"?Y.text:this.defaultText,this.container=R(Y.container)==="object"?Y.container:document.body}},{key:"listenClick",value:function(Y){var K=this;this.listener=d()(Y,"click",function(q){return K.onClick(q)})}},{key:"onClick",value:function(Y){var K=Y.delegateTarget||Y.currentTarget,q=this.action(K)||"copy",ee=w({action:q,container:this.container,target:this.target(K),text:this.text(K)});this.emit(ee?"success":"error",{action:q,text:ee,trigger:K,clearSelection:function(){K&&K.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(Y){return L("action",Y)}},{key:"defaultTarget",value:function(Y){var K=L("target",Y);if(K)return document.querySelector(K)}},{key:"defaultText",value:function(Y){return L("text",Y)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(Y){var K=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return x(Y,K)}},{key:"cut",value:function(Y){return b(Y)}},{key:"isSupported",value:function(){var Y=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],K=typeof Y=="string"?[Y]:Y,q=!!document.queryCommandSupported;return K.forEach(function(ee){q=q&&!!document.queryCommandSupported(ee)}),q}}]),H}(c()),B=A},828:function(i){var a=9;if(typeof Element<"u"&&!Element.prototype.matches){var l=Element.prototype;l.matches=l.matchesSelector||l.mozMatchesSelector||l.msMatchesSelector||l.oMatchesSelector||l.webkitMatchesSelector}function s(c,u){for(;c&&c.nodeType!==a;){if(typeof c.matches=="function"&&c.matches(u))return c;c=c.parentNode}}i.exports=s},438:function(i,a,l){var s=l(828);function c(v,h,g,p,b){var m=d.apply(this,arguments);return v.addEventListener(g,m,b),{destroy:function(){v.removeEventListener(g,m,b)}}}function u(v,h,g,p,b){return typeof v.addEventListener=="function"?c.apply(null,arguments):typeof g=="function"?c.bind(null,document).apply(null,arguments):(typeof v=="string"&&(v=document.querySelectorAll(v)),Array.prototype.map.call(v,function(m){return c(m,h,g,p,b)}))}function d(v,h,g,p){return function(b){b.delegateTarget=s(b.target,h),b.delegateTarget&&p.call(v,b)}}i.exports=u},879:function(i,a){a.node=function(l){return l!==void 0&&l instanceof HTMLElement&&l.nodeType===1},a.nodeList=function(l){var s=Object.prototype.toString.call(l);return l!==void 0&&(s==="[object NodeList]"||s==="[object HTMLCollection]")&&"length"in l&&(l.length===0||a.node(l[0]))},a.string=function(l){return typeof l=="string"||l instanceof String},a.fn=function(l){var s=Object.prototype.toString.call(l);return s==="[object Function]"}},370:function(i,a,l){var s=l(879),c=l(438);function u(g,p,b){if(!g&&!p&&!b)throw new Error("Missing required arguments");if(!s.string(p))throw new TypeError("Second argument must be a String");if(!s.fn(b))throw new TypeError("Third argument must be a Function");if(s.node(g))return d(g,p,b);if(s.nodeList(g))return v(g,p,b);if(s.string(g))return h(g,p,b);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function d(g,p,b){return g.addEventListener(p,b),{destroy:function(){g.removeEventListener(p,b)}}}function v(g,p,b){return Array.prototype.forEach.call(g,function(m){m.addEventListener(p,b)}),{destroy:function(){Array.prototype.forEach.call(g,function(m){m.removeEventListener(p,b)})}}}function h(g,p,b){return c(document.body,g,p,b)}i.exports=u},817:function(i){function a(l){var s;if(l.nodeName==="SELECT")l.focus(),s=l.value;else if(l.nodeName==="INPUT"||l.nodeName==="TEXTAREA"){var c=l.hasAttribute("readonly");c||l.setAttribute("readonly",""),l.select(),l.setSelectionRange(0,l.value.length),c||l.removeAttribute("readonly"),s=l.value}else{l.hasAttribute("contenteditable")&&l.focus();var u=window.getSelection(),d=document.createRange();d.selectNodeContents(l),u.removeAllRanges(),u.addRange(d),s=u.toString()}return s}i.exports=a},279:function(i){function a(){}a.prototype={on:function(l,s,c){var u=this.e||(this.e={});return(u[l]||(u[l]=[])).push({fn:s,ctx:c}),this},once:function(l,s,c){var u=this;function d(){u.off(l,d),s.apply(c,arguments)}return d._=s,this.on(l,d,c)},emit:function(l){var s=[].slice.call(arguments,1),c=((this.e||(this.e={}))[l]||[]).slice(),u=0,d=c.length;for(u;u{const l=new YH(".CardMessageLink-Copy");return()=>{l.destroy()}},[]);const[t,n]=f.exports.useState(!1),[r,o]=f.exports.useState({x:0,y:0}),i=l=>{typeof document.hasFocus=="function"&&!document.hasFocus()||(l.preventDefault(),o({x:l.clientX,y:l.clientY}),n(!0))},a=()=>{i9(e.info.Url)};return ie("div",{className:"CardMessage CardMessageLink",size:"small",onDoubleClick:a,onContextMenu:i,children:[C("div",{className:"CardMessage-Title",children:e.info.Title}),ie("div",{className:"CardMessage-Content",children:[C("div",{className:"CardMessage-Desc",children:e.info.Description}),C(cu,{className:"CardMessageLink-Image",src:e.image,height:45,width:45,preview:!1,fallback:C9})]}),C("div",{className:e.info.DisPlayName===""?"CardMessageLink-Line-None":"CardMessageLink-Line"}),C("div",{className:"CardMessageLink-Name",children:e.info.DisPlayName}),ie(W$,{anchorPoint:r,state:t?"open":"closed",direction:"right",onClose:()=>n(!1),menuClassName:"CardMessage-Menu",children:[C(cd,{onClick:a,children:"\u6253\u5F00"}),C(cd,{className:"CardMessageLink-Copy",onClick:()=>handleOpenFile("fiexplorerle"),"data-clipboard-text":e.info.Url,children:"\u590D\u5236\u94FE\u63A5"})]})]})}function qH(e){const[t,n]=f.exports.useState(!1),[r,o]=f.exports.useState(!1),[i,a]=f.exports.useState({x:0,y:0}),l=u=>{typeof document.hasFocus=="function"&&!document.hasFocus()||(u.preventDefault(),a({x:u.clientX,y:u.clientY}),o(!0))},s=u=>{JB(e.info.filePath,u==="explorer").then(d=>{JSON.parse(d).status==="failed"&&n(!0)})},c=({hover:u})=>u?"CardMessage-Menu-hover":"CardMessage-Menu";return ie("div",{className:"CardMessage CardMessageFile",size:"small",onDoubleClick:()=>s("file"),onContextMenu:l,children:[C("div",{className:"CardMessage-Title",children:e.info.fileName}),ie("div",{className:"CardMessage-Content",children:[ie("div",{className:"CardMessage-Desc",children:[e.info.fileSize,C("span",{className:"CardMessage-Desc-Span",children:t?"\u6587\u4EF6\u4E0D\u5B58\u5728":""})]}),C("div",{className:"CardMessageFile-Icon",children:C(cx,{})})]}),ie(W$,{anchorPoint:i,state:r?"open":"closed",direction:"right",onClose:()=>o(!1),menuClassName:"CardMessage-Menu",children:[C(cd,{className:c,onClick:()=>s("file"),children:"\u6253\u5F00"}),C(cd,{className:c,onClick:()=>s("fiexplorerle"),children:"\u5728\u6587\u4EF6\u5939\u4E2D\u663E\u793A"})]})]})}function XH(e){let t=null,n=null;switch(e.info.Type){case Fm:switch(e.info.SubType){case Q$:n=C(cx,{});break;case X$:n=C(mP,{});break}case U$:t=ie("div",{className:"MessageRefer-Content-Text",children:[e.info.Displayname,":",n,e.info.Content]});break;case q$:t=C(v4,{});break;case Y$:t=C(LP,{});break;case K$:t=C(S4,{});break;case G$:t=C(RI,{});break;default:t=ie("div",{children:["\u672A\u77E5\u7684\u5F15\u7528\u7C7B\u578B ID:",e.info.Svrid,"Type:",e.info.Type]})}return ie("div",{className:e.position==="left"?"MessageRefer-Left":"MessageRefer-Right",children:[C(Dm,{className:"MessageRefer-MessageText",text:e.content}),C("div",{className:"MessageRefer-Content",children:t})]})}function J$(e){switch(e.content.type){case U$:return C(Dm,{text:e.content.content});case Y$:return C(cu,{src:e.content.ThumbPath,preview:{src:e.content.ImagePath}});case K$:return C(cu,{src:e.content.ThumbPath,preview:{imageRender:(t,n)=>C("video",{className:"video_view",height:"100%",width:"100%",controls:!0,src:e.content.VideoPath}),onVisibleChange:(t,n,r)=>{t===!1&&n===!0&&document.getElementsByClassName("video_view")[0].pause()}}});case G$:return C(m$,{className:"CardMessageText",children:C("audio",{className:"CardMessageAudio",controls:!0,src:e.content.VoicePath})});case q$:return C(cu,{src:e.content.EmojiPath,height:"110px",width:"110px",preview:!1,fallback:x9});case GH:return C("div",{className:"System-Text",children:e.content.content});case Fm:switch(e.content.SubType){case X$:return C(KH,{info:e.content.LinkInfo,image:e.content.ThumbPath,tmp:e.content.MsgSvrId});case Z$:return C(XH,{content:e.content.content,info:e.content.ReferInfo,position:e.content.IsSender?"right":"left"});case Q$:return C(qH,{info:e.content.fileInfo})}default:return ie("div",{children:["ID: ",e.content.LocalId,"\u672A\u77E5\u7C7B\u578B: ",e.content.type," \u5B50\u7C7B\u578B: ",e.content.SubType]})}}function QH(e){let t=J$(e);return e.content.type==Fm&&e.content.SubType==Z$&&(t=C(Dm,{text:e.content.content})),t}function ZH(e){return C(Tt,{children:e.selectTag===""?C(_d,{}):ie("div",{className:"SearchInputIcon",children:[C($I,{className:"SearchInputIcon-size SearchInputIcon-first"}),C("div",{className:"SearchInputIcon-size SearchInputIcon-second",children:e.selectTag}),C(eo,{className:"SearchInputIcon-size SearchInputIcon-third",onClick:()=>e.onClickClose()})]})})}function eE(e){const t=r=>{e.onChange&&e.onChange(r.target.value)},n=r=>{r.stopPropagation()};return C("div",{className:"wechat-SearchInput",children:C(ai,{theme:{components:{Input:{activeBorderColor:"#E3E4E5",activeShadow:"#E3E4E5",hoverBorderColor:"#E3E4E5"}}},children:C(C$,{className:"wechat-SearchInput-Input",placeholder:e.selectTag===""?"\u641C\u7D22":"",prefix:C(ZH,{selectTag:e.selectTag,onClickClose:()=>e.onClickClose()}),allowClear:!0,onChange:t,onClick:n})})})}function JH(e){const t=f.exports.useMemo(()=>e.renderMessageContent(e.message),[e.message]);return ie("div",{className:"MessageBubble RecordsUi-MessageBubble",onDoubleClick:()=>{e.onDoubleClick&&e.onDoubleClick(e.message)},children:[C("time",{className:"Time",dateTime:Lt(e.message.createdAt).format(),children:Lt(e.message.createdAt*1e3).format("YYYY\u5E74M\u6708D\u65E5 HH:mm")}),ie("div",{className:"MessageBubble-content-left",children:[C("div",{className:"MessageBubble-content-Avatar",children:C(Yo,{className:"MessageBubble-Avatar-left",src:e.message.user.avatar,size:{xs:40,sm:40,md:40,lg:40,xl:40,xxl:40},shape:"square",alt:"\u65E0\u6CD5\u52A0\u8F7D\u5934\u50CF"})}),ie("div",{className:"Bubble-left",children:[C("div",{className:"MessageBubble-Name-left",truncate:1,children:e.message.user.name}),t]})]})]})}function eW(e){const t=f.exports.useRef(0),n=f.exports.useRef(null),r=i=>{i.srcElement.scrollTop===0?(t.current=i.srcElement.scrollHeight,n.current=i.srcElement,e.atBottom&&e.atBottom()):(t.current=0,n.current=null)};function o(){e.next()}return f.exports.useEffect(()=>{t.current!==0&&n.current&&(n.current.scrollTop=-(n.current.scrollHeight-t.current),t.current=0,n.current=null)},[e.messages]),C("div",{id:"RecordsUiscrollableDiv",children:C(D$,{scrollableTarget:"RecordsUiscrollableDiv",dataLength:e.messages.length,next:o,hasMore:e.hasMore,inverse:!0,onScroll:r,children:e.messages.map(i=>C(JH,{message:i,renderMessageContent:e.renderMessageContent,onDoubleClick:e.onDoubleClick},i.key))})})}function tW(e){return C("div",{className:"RecordsUi",children:C(eW,{messages:e.messages,next:e.fetchMoreData,hasMore:e.hasMore,renderMessageContent:e.renderMessageContent,atBottom:e.atBottom,onDoubleClick:e.onDoubleClick})})}var nW={locale:"zh_CN",yearFormat:"YYYY\u5E74",cellDateFormat:"D",cellMeridiemFormat:"A",today:"\u4ECA\u5929",now:"\u6B64\u523B",backToToday:"\u8FD4\u56DE\u4ECA\u5929",ok:"\u786E\u5B9A",timeSelect:"\u9009\u62E9\u65F6\u95F4",dateSelect:"\u9009\u62E9\u65E5\u671F",weekSelect:"\u9009\u62E9\u5468",clear:"\u6E05\u9664",month:"\u6708",year:"\u5E74",previousMonth:"\u4E0A\u4E2A\u6708 (\u7FFB\u9875\u4E0A\u952E)",nextMonth:"\u4E0B\u4E2A\u6708 (\u7FFB\u9875\u4E0B\u952E)",monthSelect:"\u9009\u62E9\u6708\u4EFD",yearSelect:"\u9009\u62E9\u5E74\u4EFD",decadeSelect:"\u9009\u62E9\u5E74\u4EE3",previousYear:"\u4E0A\u4E00\u5E74 (Control\u952E\u52A0\u5DE6\u65B9\u5411\u952E)",nextYear:"\u4E0B\u4E00\u5E74 (Control\u952E\u52A0\u53F3\u65B9\u5411\u952E)",previousDecade:"\u4E0A\u4E00\u5E74\u4EE3",nextDecade:"\u4E0B\u4E00\u5E74\u4EE3",previousCentury:"\u4E0A\u4E00\u4E16\u7EAA",nextCentury:"\u4E0B\u4E00\u4E16\u7EAA"};const rW={placeholder:"\u8BF7\u9009\u62E9\u65F6\u95F4",rangePlaceholder:["\u5F00\u59CB\u65F6\u95F4","\u7ED3\u675F\u65F6\u95F4"]},oW=rW,tE={lang:Object.assign({placeholder:"\u8BF7\u9009\u62E9\u65E5\u671F",yearPlaceholder:"\u8BF7\u9009\u62E9\u5E74\u4EFD",quarterPlaceholder:"\u8BF7\u9009\u62E9\u5B63\u5EA6",monthPlaceholder:"\u8BF7\u9009\u62E9\u6708\u4EFD",weekPlaceholder:"\u8BF7\u9009\u62E9\u5468",rangePlaceholder:["\u5F00\u59CB\u65E5\u671F","\u7ED3\u675F\u65E5\u671F"],rangeYearPlaceholder:["\u5F00\u59CB\u5E74\u4EFD","\u7ED3\u675F\u5E74\u4EFD"],rangeMonthPlaceholder:["\u5F00\u59CB\u6708\u4EFD","\u7ED3\u675F\u6708\u4EFD"],rangeQuarterPlaceholder:["\u5F00\u59CB\u5B63\u5EA6","\u7ED3\u675F\u5B63\u5EA6"],rangeWeekPlaceholder:["\u5F00\u59CB\u5468","\u7ED3\u675F\u5468"]},nW),timePickerLocale:Object.assign({},oW)};tE.lang.ok="\u786E\u5B9A";const iW=tE;var aW={exports:{}};(function(e,t){(function(n,r){e.exports=r($m.exports)})(Hr,function(n){function r(a){return a&&typeof a=="object"&&"default"in a?a:{default:a}}var o=r(n),i={name:"zh-cn",weekdays:"\u661F\u671F\u65E5_\u661F\u671F\u4E00_\u661F\u671F\u4E8C_\u661F\u671F\u4E09_\u661F\u671F\u56DB_\u661F\u671F\u4E94_\u661F\u671F\u516D".split("_"),weekdaysShort:"\u5468\u65E5_\u5468\u4E00_\u5468\u4E8C_\u5468\u4E09_\u5468\u56DB_\u5468\u4E94_\u5468\u516D".split("_"),weekdaysMin:"\u65E5_\u4E00_\u4E8C_\u4E09_\u56DB_\u4E94_\u516D".split("_"),months:"\u4E00\u6708_\u4E8C\u6708_\u4E09\u6708_\u56DB\u6708_\u4E94\u6708_\u516D\u6708_\u4E03\u6708_\u516B\u6708_\u4E5D\u6708_\u5341\u6708_\u5341\u4E00\u6708_\u5341\u4E8C\u6708".split("_"),monthsShort:"1\u6708_2\u6708_3\u6708_4\u6708_5\u6708_6\u6708_7\u6708_8\u6708_9\u6708_10\u6708_11\u6708_12\u6708".split("_"),ordinal:function(a,l){return l==="W"?a+"\u5468":a+"\u65E5"},weekStart:1,yearStart:4,formats:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY/MM/DD",LL:"YYYY\u5E74M\u6708D\u65E5",LLL:"YYYY\u5E74M\u6708D\u65E5Ah\u70B9mm\u5206",LLLL:"YYYY\u5E74M\u6708D\u65E5ddddAh\u70B9mm\u5206",l:"YYYY/M/D",ll:"YYYY\u5E74M\u6708D\u65E5",lll:"YYYY\u5E74M\u6708D\u65E5 HH:mm",llll:"YYYY\u5E74M\u6708D\u65E5dddd HH:mm"},relativeTime:{future:"%s\u5185",past:"%s\u524D",s:"\u51E0\u79D2",m:"1 \u5206\u949F",mm:"%d \u5206\u949F",h:"1 \u5C0F\u65F6",hh:"%d \u5C0F\u65F6",d:"1 \u5929",dd:"%d \u5929",M:"1 \u4E2A\u6708",MM:"%d \u4E2A\u6708",y:"1 \u5E74",yy:"%d \u5E74"},meridiem:function(a,l){var s=100*a+l;return s<600?"\u51CC\u6668":s<900?"\u65E9\u4E0A":s<1100?"\u4E0A\u5348":s<1300?"\u4E2D\u5348":s<1800?"\u4E0B\u5348":"\u665A\u4E0A"}};return o.default.locale(i,null,!0),i})})(aW);var nE={exports:{}};(function(e,t){(function(n,r){e.exports=r()})(Hr,function(){var n="minute",r=/[+-]\d\d(?::?\d\d)?/g,o=/([+-]|\d\d)/g;return function(i,a,l){var s=a.prototype;l.utc=function(p){var b={date:p,utc:!0,args:arguments};return new a(b)},s.utc=function(p){var b=l(this.toDate(),{locale:this.$L,utc:!0});return p?b.add(this.utcOffset(),n):b},s.local=function(){return l(this.toDate(),{locale:this.$L,utc:!1})};var c=s.parse;s.parse=function(p){p.utc&&(this.$u=!0),this.$utils().u(p.$offset)||(this.$offset=p.$offset),c.call(this,p)};var u=s.init;s.init=function(){if(this.$u){var p=this.$d;this.$y=p.getUTCFullYear(),this.$M=p.getUTCMonth(),this.$D=p.getUTCDate(),this.$W=p.getUTCDay(),this.$H=p.getUTCHours(),this.$m=p.getUTCMinutes(),this.$s=p.getUTCSeconds(),this.$ms=p.getUTCMilliseconds()}else u.call(this)};var d=s.utcOffset;s.utcOffset=function(p,b){var m=this.$utils().u;if(m(p))return this.$u?0:m(this.$offset)?d.call(this):this.$offset;if(typeof p=="string"&&(p=function($){$===void 0&&($="");var E=$.match(r);if(!E)return null;var w=(""+E[0]).match(o)||["-",0,0],R=w[0],P=60*+w[1]+ +w[2];return P===0?0:R==="+"?P:-P}(p),p===null))return this;var y=Math.abs(p)<=16?60*p:p,S=this;if(b)return S.$offset=y,S.$u=p===0,S;if(p!==0){var x=this.$u?this.toDate().getTimezoneOffset():-1*this.utcOffset();(S=this.local().add(y+x,n)).$offset=y,S.$x.$localOffset=x}else S=this.utc();return S};var v=s.format;s.format=function(p){var b=p||(this.$u?"YYYY-MM-DDTHH:mm:ss[Z]":"");return v.call(this,b)},s.valueOf=function(){var p=this.$utils().u(this.$offset)?0:this.$offset+(this.$x.$localOffset||this.$d.getTimezoneOffset());return this.$d.valueOf()-6e4*p},s.isUTC=function(){return!!this.$u},s.toISOString=function(){return this.toDate().toISOString()},s.toString=function(){return this.toDate().toUTCString()};var h=s.toDate;s.toDate=function(p){return p==="s"&&this.$offset?l(this.format("YYYY-MM-DD HH:mm:ss:SSS")).toDate():h.call(this)};var g=s.diff;s.diff=function(p,b,m){if(p&&this.$u===p.$u)return g.call(this,p,b,m);var y=this.local(),S=l(p).local();return g.call(y,S,b,m)}}})})(nE);const lW=nE.exports;var rE={exports:{}};(function(e,t){(function(n,r){e.exports=r()})(Hr,function(){var n={year:0,month:1,day:2,hour:3,minute:4,second:5},r={};return function(o,i,a){var l,s=function(v,h,g){g===void 0&&(g={});var p=new Date(v),b=function(m,y){y===void 0&&(y={});var S=y.timeZoneName||"short",x=m+"|"+S,$=r[x];return $||($=new Intl.DateTimeFormat("en-US",{hour12:!1,timeZone:m,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",timeZoneName:S}),r[x]=$),$}(h,g);return b.formatToParts(p)},c=function(v,h){for(var g=s(v,h),p=[],b=0;b=0&&(p[x]=parseInt(S,10))}var $=p[3],E=$===24?0:$,w=p[0]+"-"+p[1]+"-"+p[2]+" "+E+":"+p[4]+":"+p[5]+":000",R=+v;return(a.utc(w).valueOf()-(R-=R%1e3))/6e4},u=i.prototype;u.tz=function(v,h){v===void 0&&(v=l);var g=this.utcOffset(),p=this.toDate(),b=p.toLocaleString("en-US",{timeZone:v}),m=Math.round((p-new Date(b))/1e3/60),y=a(b,{locale:this.$L}).$set("millisecond",this.$ms).utcOffset(15*-Math.round(p.getTimezoneOffset()/15)-m,!0);if(h){var S=y.utcOffset();y=y.add(g-S,"minute")}return y.$x.$timezone=v,y},u.offsetName=function(v){var h=this.$x.$timezone||a.tz.guess(),g=s(this.valueOf(),h,{timeZoneName:v}).find(function(p){return p.type.toLowerCase()==="timezonename"});return g&&g.value};var d=u.startOf;u.startOf=function(v,h){if(!this.$x||!this.$x.$timezone)return d.call(this,v,h);var g=a(this.format("YYYY-MM-DD HH:mm:ss:SSS"),{locale:this.$L});return d.call(g,v,h).tz(this.$x.$timezone,!0)},a.tz=function(v,h,g){var p=g&&h,b=g||h||l,m=c(+a(),b);if(typeof v!="string")return a(v).tz(b);var y=function(E,w,R){var P=E-60*w*1e3,N=c(P,R);if(w===N)return[P,w];var I=c(P-=60*(N-w)*1e3,R);return N===I?[P,N]:[E-60*Math.min(N,I)*1e3,Math.max(N,I)]}(a.utc(v,p).valueOf(),m,b),S=y[0],x=y[1],$=a(S).utcOffset(x);return $.$x.$timezone=b,$},a.tz.guess=function(){return Intl.DateTimeFormat().resolvedOptions().timeZone},a.tz.setDefault=function(v){l=v}}})})(rE);const sW=rE.exports,cW=()=>C("div",{className:"CalendarLoading",children:C(oB,{tip:"\u52A0\u8F7D\u4E2D...",size:"large",children:C("div",{className:"content"})})}),uW=({info:e,selectDate:t})=>{const[n,r]=f.exports.useState([]),[o,i]=f.exports.useState(!0),a=f.exports.useRef(null);f.exports.useEffect(()=>{Lt.extend(lW),Lt.extend(sW),Lt.tz.setDefault()},[]),f.exports.useEffect(()=>{XB(e.UserName).then(c=>{r(JSON.parse(c).Date),i(!1)})},[e.UserName]);const l=c=>{for(let u=0;u{u.source==="date"&&(a.current=c,t&&t(c.valueOf()/1e3))};return C(Tt,{children:o?C(cW,{}):C(cF,{className:"CalendarChoose",disabledDate:l,fullscreen:!1,locale:iW,validRange:n.length>0?[Lt(n[n.length-1]),Lt(n[0])]:void 0,defaultValue:a.current?a.current:n.length>0?Lt(n[0]):void 0,onSelect:s})})};const dW=["\u6587\u4EF6","\u56FE\u7247\u4E0E\u89C6\u9891","\u94FE\u63A5","\u65E5\u671F"],fW=["\u6587\u4EF6","\u56FE\u7247\u4E0E\u89C6\u9891","\u94FE\u63A5","\u65E5\u671F","\u7FA4\u6210\u5458"];function vW(e){const[t,n]=f.exports.useState(!1),r=()=>{e.info.UserName&&n(!0)},o=()=>{n(!1)},{messages:i,prependMsgs:a,appendMsgs:l,setMsgs:s}=L$([]),[c,u]=f.exports.useState(!1),[d,v]=f.exports.useState(!0),[h,g]=f.exports.useState(""),[p,b]=f.exports.useState(""),[m,y]=f.exports.useState(1),[S,x]=f.exports.useState(!1),[$,E]=f.exports.useState(e.info.Time),[w,R]=f.exports.useState(!1),[P,N]=f.exports.useState("");f.exports.useEffect(()=>{e.info.UserName&&$>0&&p!="\u65E5\u671F"&&(u(!0),QB(e.info.UserName,$,h,p,30).then(A=>{let B=JSON.parse(A);B.Total==0&&(v(!1),i.length==0&&R(!0));let k=[];B.Rows.forEach(j=>{k.unshift({_id:j.MsgSvrId,content:j,position:j.type===1e4?"middle":j.IsSender===1?"right":"left",user:{avatar:j.userInfo.SmallHeadImgUrl,name:j.userInfo.ReMark===""?j.userInfo.NickName:j.userInfo.ReMark},createdAt:j.createTime,key:j.MsgSvrId})}),u(!1),a(k)}))},[e.info.UserName,$,h,p]);const I=()=>{Ts("fetchMoreData"),c||setTimeout(()=>{E(i[0].createdAt-1)},300)},z=A=>{console.log("onKeyWordChange",A),E(e.info.Time),s([]),y(m+1),g(A),R(!1)},F=f.exports.useCallback(oE(A=>{z(A)},600),[]),T=A=>{console.log("onFilterTag",A),A!=="\u7FA4\u6210\u5458"&&(s([]),y(m+1),E(e.info.Time),b(A),R(!1),x(A==="\u65E5\u671F"),N(""))},D=()=>{s([]),y(m+1),E(e.info.Time),b(""),R(!1),N("")},_=e.info.IsGroup?fW:dW,O=A=>{o(),e.onSelectMessage&&e.onSelectMessage(A)},M=A=>{o(),e.onSelectDate&&e.onSelectDate(A)},L=A=>{console.log(A),b("\u7FA4\u6210\u5458"+A.UserName),N(A.NickName),E(e.info.Time),s([]),y(m+1),g(""),R(!1),x(!1)};return ie("div",{children:[C("div",{onClick:r,children:e.children}),C(js,{className:"ChattingRecords-Modal",overlayClassName:"ChattingRecords-Modal-Overlay",isOpen:t,onRequestClose:o,children:ie("div",{className:"ChattingRecords-Modal-Body",children:[ie("div",{className:"ChattingRecords-Modal-Bar",children:[ie("div",{className:"ChattingRecords-Modal-Bar-Top",children:[C("div",{children:e.info.NickName}),C("div",{className:"ChattingRecords-Modal-Bar-button",title:"\u5173\u95ED",onClick:o,children:C(eo,{className:"ChattingRecords-Modal-Bar-button-icon"})})]}),C(eE,{onChange:F,selectTag:p.includes("\u7FA4\u6210\u5458")?"\u7FA4\u6210\u5458":p,onClickClose:D}),C("div",{className:"ChattingRecords-Modal-Bar-Tag",children:_.map(A=>C("div",{onClick:()=>T(A),children:A==="\u7FA4\u6210\u5458"?C(gW,{info:e.info,onClick:L,children:A}):A},Am()))})]}),S==!1?w?C(pW,{text:h!==""?h:P}):C(tW,{messages:i,fetchMoreData:I,hasMore:d&&!c,renderMessageContent:QH,onDoubleClick:O},m):C(uW,{info:e.info,selectDate:M})]})})]})}function oE(e,t){let n;return function(...r){n&&clearTimeout(n),n=setTimeout(()=>{e.apply(this,r)},t)}}const pW=({text:e})=>C("div",{className:"NotMessageContent",children:ie("div",{children:["\u6CA1\u6709\u627E\u5230\u4E0E",ie("span",{className:"NotMessageContent-keyword",children:['"',e,'"']}),"\u76F8\u5173\u7684\u8BB0\u5F55"]})}),gW=e=>{const[t,n]=f.exports.useState(!1),[r,o]=f.exports.useState(!0),[i,a]=f.exports.useState([]),[l,s]=f.exports.useState("");f.exports.useEffect(()=>{t&&qB(e.info.UserName).then(b=>{let m=JSON.parse(b);a(m.Users),o(!1)})},[e.info,t]);const c=b=>{b.stopPropagation(),console.log("showModal"),n(!0),o(!0)},u=b=>{n(!1)},d=b=>{s(b)},v=f.exports.useCallback(oE(b=>{d(b)},400),[]),h=()=>{},g=b=>{n(!1),e.onClick&&e.onClick(b)},p=i.filter(b=>b.NickName.includes(l));return ie("div",{className:"ChattingRecords-ChatRoomUserList-Parent",children:[C("div",{onClick:c,children:e.children}),ie(js,{className:"ChattingRecords-ChatRoomUserList",overlayClassName:"ChattingRecords-ChatRoomUserList-Overlay",isOpen:t,onRequestClose:u,children:[C(eE,{onChange:v,selectTag:"",onClickClose:h}),r?C("div",{className:"ChattingRecords-ChatRoomUserList-Loading",children:"\u52A0\u8F7D\u4E2D..."}):C(hW,{userList:p,onClick:g})]})]})},hW=e=>ie("div",{className:"ChattingRecords-ChatRoomUserList-List",children:[e.userList.map(t=>C(mW,{info:t,onClick:()=>e.onClick(t)},Am())),C("div",{className:"ChattingRecords-ChatRoomUserList-List-End",children:"- \u5DF2\u7ECF\u5230\u5E95\u5566 -"})]}),mW=e=>ie("div",{className:"ChattingRecords-ChatRoomUserList-User",onClick:n=>{n.stopPropagation(),e.onClick&&e.onClick()},children:[C(Yo,{className:"ChattingRecords-ChatRoomUserList-Avatar",src:e.info.SmallHeadImgUrl,size:{xs:35,sm:35,md:35,lg:35,xl:35,xxl:35},shape:"square",alt:"\u65E0\u6CD5\u52A0\u8F7D\u5934\u50CF"}),C("div",{className:"ChattingRecords-ChatRoomUserList-Name",children:e.info.NickName})]});function yW(e){const[t,n]=f.exports.useState(!1);return ie("div",{className:"wechat-UserDialog-Bar",children:[C("div",{className:"wechat-UserDialog-text wechat-UserDialog-name",children:e.name}),ie("div",{className:"wechat-UserDialog-Bar-button-block",children:[ie("div",{className:"wechat-UserDialog-Bar-button-list",children:[C("div",{className:"wechat-UserDialog-Bar-button",title:"\u6700\u5C0F\u5316",onClick:()=>e.onClickButton("min"),children:C(RP,{className:"wechat-UserDialog-Bar-button-icon"})}),C("div",{className:"wechat-UserDialog-Bar-button",title:t?"\u8FD8\u539F":"\u6700\u5927\u5316",onClick:()=>{n(!t),e.onClickButton("max")},children:t?C(NP,{className:"wechat-UserDialog-Bar-button-icon"}):C(VP,{className:"wechat-UserDialog-Bar-button-icon"})}),C("div",{className:"wechat-UserDialog-Bar-button",title:"\u5173\u95ED",onClick:()=>e.onClickButton("close"),children:C(eo,{className:"wechat-UserDialog-Bar-button-icon"})})]}),C(vW,{info:e.info,onSelectMessage:e.onSelectMessage,onSelectDate:e.onSelectDate,children:e.name===""?C(Tt,{}):C("div",{className:"wechat-UserDialog-Bar-button wechat-UserDialog-Bar-button-msg",title:"\u804A\u5929\u8BB0\u5F55",onClick:()=>e.onClickButton("msg"),children:C($P,{className:"wechat-UserDialog-Bar-button-icon2"})})})]})]})}function bW(e){const{messages:t,prependMsgs:n,appendMsgs:r,setMsgs:o}=L$([]),[i,a]=f.exports.useState(e.info.Time),[l,s]=f.exports.useState("forward"),[c,u]=f.exports.useState(!1),[d,v]=f.exports.useState(!0),[h,g]=f.exports.useState(1),[p,b]=f.exports.useState(""),[m,y]=f.exports.useState(0),S=f.exports.useDeferredValue(t);f.exports.useEffect(()=>{e.info.UserName&&i>0&&(u(!0),p1(e.info.UserName,i,30,l).then(R=>{let P=JSON.parse(R);P.Total==0&&l=="forward"&&v(!1),console.log(P.Total,l);let N=[];P.Rows.forEach(I=>{N.unshift({_id:I.MsgSvrId,content:I,position:I.type===1e4?"middle":I.IsSender===1?"right":"left",user:{avatar:I.userInfo.SmallHeadImgUrl,name:I.userInfo.ReMark===""?I.userInfo.NickName:I.userInfo.ReMark},createdAt:I.createTime,key:I.MsgSvrId})}),u(!1),l==="backward"?r(N):n(N)}))},[e.info.UserName,l,i]),f.exports.useEffect(()=>{e.info.UserName&&m>0&&(u(!0),p1(e.info.UserName,m,1,"backward").then(R=>{let P=JSON.parse(R);P.Rows.length==1&&(g(N=>N+1),o([]),a(P.Rows[0].createTime),s("both"),b(P.Rows[0].MsgSvrId)),u(!1)}))},[e.info.UserName,m]);const x=()=>{Ts("fetchMoreData"),c||setTimeout(()=>{a(t[0].createdAt-1),s("forward"),b("")},100)},$=()=>{Ts("fetchMoreDataDown"),c||setTimeout(()=>{a(t[t.length-1].createdAt+1),s("backward"),b("")},100)},E=R=>{g(P=>P+1),o([]),a(R.createdAt),s("both"),b(R.key)},w=R=>{y(R)};return ie("div",{className:"wechat-UserDialog",children:[C(yW,{name:e.info.NickName===null?"":e.info.NickName,onClickButton:e.onClickButton,info:e.info,onSelectMessage:E,onSelectDate:w}),C(S9,{messages:S,fetchMoreData:x,hasMore:d&&!c,renderMessageContent:J$,scrollIntoId:p,atBottom:$},h)]})}function SW(){const[e,t]=f.exports.useState(0),[n,r]=f.exports.useState(1),[o,i]=f.exports.useState(!1),[a,l]=f.exports.useState(null),[s,c]=f.exports.useState({}),u=v=>{Ts(v),v==="setting"?i(!0):v==="exit"&&(r(n+1),t(h=>h+1))},d=v=>{switch(v){case"min":o9();break;case"max":r9();break;case"close":a9();break}};return f.exports.useEffect(()=>{t(1)},[]),f.exports.useEffect(()=>{if(e!=0)return e9(),_$("selfInfo",v=>{l(JSON.parse(v))}),()=>{A$("selfInfo")}},[e]),ie("div",{id:"App",children:[C(g9,{onClickItem:v=>{console.log(v),u(v)},Avatar:a?a.SmallHeadImgUrl:""}),C(d9,{selfName:a?a.UserName:"",onClickItem:v=>{c(v),Ts("click: "+v.UserName)}},n),C(bW,{info:s,onClickButton:d},s.UserName)]})}const CW=document.getElementById("root"),xW=AC(CW);js.setAppElement("#root");xW.render(C(lt.StrictMode,{children:C(SW,{})})); diff --git a/frontend/dist/assets/index.de7292ad.css b/frontend/dist/assets/index.de7292ad.css new file mode 100644 index 0000000..65557f2 --- /dev/null +++ b/frontend/dist/assets/index.de7292ad.css @@ -0,0 +1 @@ +@charset "UTF-8";html{background-color:#f5f5f5}body{margin:0;font-family:Nunito,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif}@font-face{font-family:Nunito;font-style:normal;font-weight:400;src:local(""),url(/assets/nunito-v16-latin-regular.06f3af3f.woff2) format("woff2")}#app{height:100vh;text-align:center}#App{height:100vh;text-align:center;display:flex;flex-direction:row}::-webkit-scrollbar{width:6px}::-webkit-scrollbar-thumb{--tw-border-opacity: 1;background-color:#b6b4b4cc;border-color:rgba(181,180,178,var(--tw-border-opacity));border-radius:9999px;border-width:1px}.wechat-UserList{width:275px;height:100%;background-color:#eae8e7}.wechat-SearchBar{height:60px;background-color:#f7f7f7;--wails-draggable:drag}.wechat-SearchBar-Input{height:26px;width:240px;background-color:#e6e6e6;margin-top:22px;--wails-draggable:no-drag}.wechat-UserList-Items{height:calc(100% - 60px);overflow:auto}.wechat-UserItem{display:flex;justify-content:space-between;height:64px}.wechat-UserItem{transition:background-color .3s ease}.wechat-UserItem:hover{background-color:#dcdad9}.wechat-UserItem:focus{background-color:#c9c8c6}.selectedItem{background-color:#c9c8c6}#wechat-UserItem-content-Avatar-id{border-radius:0}.wechat-UserItem-content-Avatar{margin-top:12px;margin-left:9px;margin-right:9px}.wechat-UserItem-content{flex:1;width:55%;display:flex;flex-direction:column;justify-content:space-between}.wechat-UserItem-content-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:left}.wechat-UserItem-content-name{color:#000;font-size:95%;margin-top:12px}.wechat-UserItem-content-msg{color:#999;font-size:80%;margin-bottom:10px}.wechat-UserItem-date{color:#999;font-size:80%;margin-top:12px;margin-right:9px}.Setting-Modal{width:500px;background-color:#f5f5f5;position:fixed;top:35%;left:50%;transform:translate(-50%,-50%);padding:20px;border-radius:5px;box-shadow:2px 2px 2px #a2a2a2}.Setting-Modal-Overlay{position:fixed;top:0;left:0;right:0;bottom:0}.WechatInfoTable{display:flex;flex-direction:column;font-size:.9rem;border-top:1px solid #b9b9b9}.WechatInfoTable-column{display:flex;margin-top:8px}.WechatInfoTable-column-tag{margin-left:8px}.Setting-Modal-export-button{margin-top:10px}.Setting-Modal-button{position:absolute;top:10px;right:10px;padding:5px 10px;border:none;cursor:pointer}.Setting-Modal-confirm{background-color:#f5f5f5;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);padding:20px;border-radius:5px;box-shadow:2px 2px 2px #a2a2a2}.Setting-Modal-confirm-Overlay{position:fixed;top:0;left:0;right:0;bottom:0}.Setting-Modal-confirm-title{text-align:center}.Setting-Modal-confirm-buttons{display:flex;gap:10px}.wechat-menu{display:flex;flex-direction:column;width:52px;justify-content:flex-start;height:100%;background-color:#2e2e2e;--wails-draggable:drag}.wechat-menu-item{margin-left:auto;margin-right:auto;margin-top:30px;--wails-draggable:no-drag}#wechat-menu-item-Avatar{border-radius:0}.wechat-menu-item-icon{background-color:#2e2e2e}.wechat-menu-selectedColor{color:#07c160}.ChatUi{background-color:#f3f3f3;height:calc(100% - 60px)}.ChatUiBar{display:flex;justify-content:space-between;align-items:center;padding:4% 2% 2%;border-bottom:.5px solid #dddbdb;background-color:#fff}.ChatUiBar--Text{flex:1;text-align:center;margin:1%}.ChatUiBar--Btn>.Icon{height:1.5em;width:1.5em}#scrollableDiv{height:100%;overflow:auto;display:flex;flex-direction:column-reverse}.MessageBubble{display:flex;flex-direction:column;justify-content:space-between;align-items:center;padding:10px}.MessageBubble>.Time{text-align:center;font-size:.8rem;margin-bottom:3px;background-color:#c9c8c6;color:#fff;padding:2px 3px;border-radius:4px}.MessageBubble-content-left{align-self:flex-start;display:flex;max-width:60%}.MessageBubble-content-right{align-self:flex-end;display:flex;max-width:60%}.Bubble-right>.Bubble{background-color:#95ec69}.MessageBubble-Avatar-left{margin-right:2px;border-radius:10%}.MessageBubble-Avatar-right{margin-left:2px;border-radius:10%}.Bubble-left{display:flex;flex-direction:column;align-items:flex-start;flex:1 1;max-width:100%}.MessageBubble-Name-left{color:#383838;font-size:small;margin-bottom:1px}.Bubble-right{display:flex;flex-direction:column;align-items:flex-end;flex:1 1;max-width:100%}.MessageBubble-Name-right{color:#383838;font-size:small;margin-bottom:1px}.CardMessageText{text-align:start;max-width:100%;word-break:break-all;padding:0}.MessageText-emoji{width:1.2rem;height:1.2rem;vertical-align:text-bottom}div.Bubble-right>div.CardMessageText{background-color:#95ec69}.System-Text{font-size:.8rem;color:#686868}.CardMessage{background-color:#fff;border-radius:3%;height:130px;width:260px;flex:1;display:flex;flex-direction:column;justify-content:space-between;text-align:start;padding:12px;cursor:pointer}.CardMessage-Content{display:flex;flex-direction:row;justify-content:space-between;max-width:100%;max-height:70%;padding-bottom:5px}.CardMessage-Title{overflow:hidden;text-overflow:ellipsis;word-break:break-all;max-width:95%}.CardMessage-Desc{overflow:hidden;text-overflow:ellipsis;max-width:80%;font-size:.75rem;height:90%;padding-top:5px;padding-bottom:5px;color:#949292}.CardMessage-Desc-Span{color:#bd0b0b}.CardMessageLink-Line{height:1px;width:100%;background-color:#f6f4f4}.CardMessageLink-Line-None{display:none}.CardMessageLink-Name{padding-top:4px;font-size:.65rem}.MessageRefer-Right{display:flex;flex-direction:column;align-items:flex-end}.MessageRefer-Left{display:flex;flex-direction:column;align-items:flex-start}.MessageRefer-Content{margin-top:6px;font-size:.8rem;color:#595959;background-color:#c9c8c6;border-radius:2px;padding:4px}.MessageRefer-Content-Text{max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:left}.CardMessageFile-Icon{font-size:45px;color:#595959}.CardMessage-Menu{font-size:.8rem}.CardMessageAudio{max-width:100%}.szh-menu{margin:0;padding:0;list-style:none;box-sizing:border-box;width:max-content;z-index:100;border:1px solid rgba(0,0,0,.1);background-color:#fff}.szh-menu:focus{outline:none}.szh-menu__arrow{box-sizing:border-box;width:.75rem;height:.75rem;background-color:#fff;border:1px solid transparent;border-left-color:#0000001a;border-top-color:#0000001a;z-index:-1}.szh-menu__arrow--dir-left{right:-.375rem;transform:translateY(-50%) rotate(135deg)}.szh-menu__arrow--dir-right{left:-.375rem;transform:translateY(-50%) rotate(-45deg)}.szh-menu__arrow--dir-top{bottom:-.375rem;transform:translate(-50%) rotate(-135deg)}.szh-menu__arrow--dir-bottom{top:-.375rem;transform:translate(-50%) rotate(45deg)}.szh-menu__item{cursor:pointer}.szh-menu__item:focus{outline:none}.szh-menu__item--hover{background-color:#ebebeb}.szh-menu__item--focusable{cursor:default;background-color:inherit}.szh-menu__item--disabled{cursor:default;color:#aaa}.szh-menu__group{box-sizing:border-box}.szh-menu__radio-group{margin:0;padding:0;list-style:none}.szh-menu__divider{height:1px;margin:.5rem 0;background-color:#0000001f}.szh-menu-button{box-sizing:border-box}.szh-menu{user-select:none;color:#212529;border:none;border-radius:.25rem;box-shadow:0 3px 7px #0002,0 .6px 2px #0000001a;min-width:10rem;padding:.5rem 0}.szh-menu__item{display:flex;align-items:center;position:relative;padding:.375rem 1.5rem}.szh-menu-container--itemTransition .szh-menu__item{transition-property:background-color,color;transition-duration:.15s;transition-timing-function:ease-in-out}.szh-menu__item--type-radio{padding-left:2.2rem}.szh-menu__item--type-radio:before{content:"\25cb";position:absolute;left:.8rem;top:.55rem;font-size:.8rem}.szh-menu__item--type-radio.szh-menu__item--checked:before{content:"\25cf"}.szh-menu__item--type-checkbox{padding-left:2.2rem}.szh-menu__item--type-checkbox:before{position:absolute;left:.8rem}.szh-menu__item--type-checkbox.szh-menu__item--checked:before{content:"\2714"}.szh-menu__submenu>.szh-menu__item{padding-right:2.5rem}.szh-menu__submenu>.szh-menu__item:after{content:"\276f";position:absolute;right:1rem}.szh-menu__header{color:#888;font-size:.8rem;padding:.2rem 1.5rem;text-transform:uppercase}.SearchInputIcon{background-color:#f5f4f4;display:flex;align-items:center}.SearchInputIcon-second{font-size:12px;margin:0 3px;cursor:default}#RecordsUiscrollableDiv{height:400px;overflow:auto;display:flex;flex-direction:column-reverse;border-top:1px solid #efefef}#RecordsUiscrollableDiv>div>div>.MessageBubble:hover{background-color:#dcdad9}.RecordsUi-MessageBubble>.MessageBubble-content-left{max-width:95%}.CalendarChoose{height:400px}.CalendarLoading{height:220px;padding-top:180px}.ChattingRecords-Modal{width:500px;background-color:#f5f5f5;position:fixed;top:45%;left:50%;transform:translate(-50%,-50%);padding:20px;border-radius:5px;box-shadow:2px 2px 2px #a2a2a2}.ChattingRecords-Modal-Overlay{position:fixed;top:0;left:0;right:0;bottom:0}.ChattingRecords-Modal-Bar-Tag{display:flex;flex-direction:row;justify-content:space-around;margin-top:5px;margin-bottom:5px;cursor:default;color:#576b95;font-size:.9rem}.ChattingRecords-Modal-Bar-Top{display:flex;flex-direction:row;justify-content:space-between;padding:0 5px 5px}.NotMessageContent{height:400px;display:flex;justify-content:center;align-items:center}.NotMessageContent-keyword{color:#07c160}.ChattingRecords-ChatRoomUserList{width:260px;height:300px;background-color:#f5f5f5;position:fixed;top:48%;left:70%;transform:translate(-50%,-50%);padding:20px;border-radius:5px;box-shadow:2px 2px 2px #a2a2a2}.ChattingRecords-ChatRoomUserList-Overlay{position:fixed;top:0;left:0;right:0;bottom:0}.ChattingRecords-ChatRoomUserList>.wechat-SearchInput{margin-bottom:10px}.ChattingRecords-ChatRoomUserList-List{overflow:auto;height:90%}.ChattingRecords-ChatRoomUserList-User{display:flex;padding-bottom:5px;align-items:center}.ChattingRecords-ChatRoomUserList-User:hover{background-color:#dcdad9}.ChattingRecords-ChatRoomUserList-Name{padding-left:8px;font-size:.85rem}.ChattingRecords-ChatRoomUserList-Loading{padding:20px;text-align:center}.ChattingRecords-ChatRoomUserList-List-End{padding:5px;text-align:center;font-size:.85rem}.wechat-UserDialog{flex-grow:1;background-color:#f5f5f5;flex:1;height:100%;display:flex;flex-direction:column;justify-content:space-between;width:calc(100% - 327px)}.wechat-UserDialog-Bar{height:60px;background-color:#f5f5f5;border-left:1px solid #E6E6E6;border-bottom:1px solid #E6E6E6;display:flex;flex-direction:row;justify-content:space-between;--wails-draggable:drag}.wechat-UserDialog-Bar-button-block{display:flex;flex-direction:column}.wechat-UserDialog-Bar-button-list{display:flex;flex-direction:row;--wails-draggable:no-drag}.wechat-UserDialog-Bar-button{width:34px;height:22px;color:#131212}.wechat-UserDialog-Bar-button-icon{width:12px;height:10px}.wechat-UserDialog-Bar-button-msg{margin-left:auto;margin-top:5px;--wails-draggable:no-drag}.wechat-UserDialog-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:left}.wechat-UserDialog-name{color:#000;font-size:large;margin-top:20px;margin-left:16px;--wails-draggable:no-drag} diff --git a/frontend/dist/assets/nunito-v16-latin-regular.06f3af3f.woff2 b/frontend/dist/assets/nunito-v16-latin-regular.06f3af3f.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..2f9cc5964455b8f5ca989db989250dbebb1a5f66 GIT binary patch literal 18972 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