From 82b290dc5ca4bce8e08c3f6e3314a04db8e445d2 Mon Sep 17 00:00:00 2001 From: Richard Allen Date: Sun, 21 Jul 2013 23:15:13 +0000 Subject: [PATCH] Updating to ioq3 git dated 21 Jul 2013 --- .gitignore | 33 + BUGS | 4 + Makefile | 1209 ++++--- NOTTODO | 1 + README | 30 +- Reaction-ChangeLog | 2 + build/README | 1 - code/AL/VERSION | 13 +- code/AL/al.h | 1112 +++--- code/AL/alc.h | 341 +- code/AL/alctypes.h | 143 - code/AL/alext.h | 355 ++ code/AL/altypes.h | 352 -- code/AL/alut.h | 90 - code/AL/efx-creative.h | 3 + code/AL/efx-presets.h | 402 +++ code/AL/efx.h | 761 ++++ code/asm/ftola.asm | 3 + code/asm/ftola.c | 4 +- code/asm/snapvector.asm | 3 + code/asm/snapvector.c | 4 +- code/botlib/be_aas_def.h | 14 - code/botlib/be_aas_main.c | 90 - code/botlib/be_aas_main.h | 4 - code/botlib/be_aas_reach.c | 8 +- code/botlib/be_aas_route.c | 7 +- code/botlib/be_ai_char.c | 3 - code/botlib/be_ai_chat.c | 18 +- code/botlib/be_ai_goal.c | 6 +- code/botlib/be_ai_move.c | 2 - code/botlib/be_ai_weap.c | 20 +- code/botlib/be_ai_weight.c | 1 - code/botlib/be_interface.c | 12 +- code/botlib/botlib.h | 7 +- code/botlib/l_precomp.c | 11 +- code/botlib/lcc.mak | 55 - code/botlib/linux-i386.mak | 92 - code/cgame/cg_draw.c | 4 +- code/cgame/cg_local.h | 18 +- code/cgame/cg_view.c | 3 +- code/cgame/cgame.q3asm | 27 - code/cgame/cgame_ta.q3asm | 28 - code/cgame/make-cgame.bat | 87 - code/cgame/tr_types.h | 233 -- code/client/cl_cin.c | 5 - code/client/cl_console.c | 46 +- code/client/cl_curl.c | 2 +- code/client/cl_keys.c | 60 +- code/client/cl_main.c | 24 +- code/client/cl_parse.c | 20 +- code/client/cl_ui.c | 6 +- code/client/client.h | 4 +- code/client/snd_adpcm.c | 2 +- code/client/snd_codec.c | 4 + code/client/snd_codec.h | 9 + code/client/snd_codec_opus.c | 452 +++ code/client/snd_dma.c | 3 +- code/client/snd_mix.c | 3 +- code/client/snd_openal.c | 6 +- code/client/snd_wavelet.c | 6 +- code/game/be_aas.h | 216 -- code/game/be_ai_char.h | 57 - code/game/be_ai_chat.h | 133 - code/game/be_ai_gen.h | 32 - code/game/be_ai_goal.h | 148 - code/game/be_ai_move.h | 154 - code/game/be_ai_weap.h | 111 - code/game/be_ea.h | 69 - code/game/bg_misc.c | 4 +- code/game/botai.h | 92 - code/game/botlib.h | 514 --- code/game/g_bot.c | 3 +- code/game/g_client.c | 2 +- code/game/g_cmds.c | 2 +- code/game/g_combat.c | 55 +- code/game/g_fileio.c | 47 - code/game/g_local.h | 2 +- code/game/g_main.c | 1 + code/game/game.q3asm | 43 - code/game/game_ta.q3asm | 35 - code/game/make-game.bat | 126 - code/libogg-1.3.0/include/ogg/config_types.h | 24 + code/libogg-1.3.0/include/ogg/ogg.h | 210 ++ code/libogg-1.3.0/include/ogg/os_types.h | 147 + code/libogg-1.3.0/src/bitwise.c | 857 +++++ code/libogg-1.3.0/src/framing.c | 2093 +++++++++++ code/libs/macosx/libSDL-1.2.0.dylib | Bin 1844452 -> 1844612 bytes code/libs/macosx/libSDLmain.a | Bin 123204 -> 123212 bytes code/null/null_glimp.c | 2 +- code/null/null_main.c | 4 + code/opus-1.0.2/celt/_kiss_fft_guts.h | 175 + code/opus-1.0.2/celt/arch.h | 209 ++ code/opus-1.0.2/celt/bands.c | 1302 +++++++ code/opus-1.0.2/celt/bands.h | 95 + code/opus-1.0.2/celt/celt.c | 2906 ++++++++++++++++ code/opus-1.0.2/celt/celt.h | 117 + code/opus-1.0.2/celt/celt_lpc.c | 188 + code/opus-1.0.2/celt/celt_lpc.h | 53 + code/opus-1.0.2/celt/cwrs.c | 645 ++++ code/opus-1.0.2/celt/cwrs.h | 48 + code/opus-1.0.2/celt/ecintrin.h | 87 + code/opus-1.0.2/celt/entcode.c | 93 + code/opus-1.0.2/celt/entcode.h | 116 + code/opus-1.0.2/celt/entdec.c | 245 ++ code/opus-1.0.2/celt/entdec.h | 100 + code/opus-1.0.2/celt/entenc.c | 294 ++ code/opus-1.0.2/celt/entenc.h | 110 + code/opus-1.0.2/celt/fixed_debug.h | 763 ++++ code/opus-1.0.2/celt/fixed_generic.h | 129 + code/opus-1.0.2/celt/float_cast.h | 140 + code/opus-1.0.2/celt/kiss_fft.c | 722 ++++ code/opus-1.0.2/celt/kiss_fft.h | 139 + code/opus-1.0.2/celt/laplace.c | 134 + code/opus-1.0.2/celt/laplace.h | 48 + code/opus-1.0.2/celt/mathops.c | 206 ++ code/opus-1.0.2/celt/mathops.h | 237 ++ code/opus-1.0.2/celt/mdct.c | 332 ++ code/opus-1.0.2/celt/mdct.h | 70 + code/opus-1.0.2/celt/mfrngcod.h | 48 + code/opus-1.0.2/celt/modes.c | 430 +++ code/opus-1.0.2/celt/modes.h | 83 + code/opus-1.0.2/celt/opus_custom_demo.c | 210 ++ code/opus-1.0.2/celt/os_support.h | 89 + code/opus-1.0.2/celt/pitch.c | 410 +++ code/opus-1.0.2/celt/pitch.h | 48 + code/opus-1.0.2/celt/quant_bands.c | 570 +++ code/opus-1.0.2/celt/quant_bands.h | 60 + code/opus-1.0.2/celt/rate.c | 638 ++++ code/opus-1.0.2/celt/rate.h | 101 + code/opus-1.0.2/celt/stack_alloc.h | 149 + code/opus-1.0.2/celt/static_modes_fixed.h | 595 ++++ code/opus-1.0.2/celt/static_modes_float.h | 599 ++++ code/opus-1.0.2/celt/vq.c | 415 +++ code/opus-1.0.2/celt/vq.h | 73 + code/opus-1.0.2/include/opus.h | 903 +++++ code/opus-1.0.2/include/opus_custom.h | 329 ++ code/opus-1.0.2/include/opus_defines.h | 655 ++++ code/opus-1.0.2/include/opus_multistream.h | 632 ++++ code/opus-1.0.2/include/opus_types.h | 159 + code/opus-1.0.2/silk/A2NLSF.c | 252 ++ code/opus-1.0.2/silk/API.h | 132 + code/opus-1.0.2/silk/CNG.c | 167 + code/opus-1.0.2/silk/HP_variable_cutoff.c | 77 + code/opus-1.0.2/silk/Inlines.h | 188 + code/opus-1.0.2/silk/LPC_analysis_filter.c | 85 + code/opus-1.0.2/silk/LPC_inv_pred_gain.c | 154 + code/opus-1.0.2/silk/LP_variable_cutoff.c | 135 + code/opus-1.0.2/silk/MacroCount.h | 718 ++++ code/opus-1.0.2/silk/MacroDebug.h | 952 +++++ code/opus-1.0.2/silk/NLSF2A.c | 178 + code/opus-1.0.2/silk/NLSF_VQ.c | 68 + code/opus-1.0.2/silk/NLSF_VQ_weights_laroia.c | 80 + code/opus-1.0.2/silk/NLSF_decode.c | 101 + code/opus-1.0.2/silk/NLSF_del_dec_quant.c | 207 ++ code/opus-1.0.2/silk/NLSF_encode.c | 128 + code/opus-1.0.2/silk/NLSF_stabilize.c | 142 + code/opus-1.0.2/silk/NLSF_unpack.c | 55 + code/opus-1.0.2/silk/NSQ.c | 439 +++ code/opus-1.0.2/silk/NSQ_del_dec.c | 705 ++++ code/opus-1.0.2/silk/PLC.c | 423 +++ code/opus-1.0.2/silk/PLC.h | 61 + code/opus-1.0.2/silk/SigProc_FIX.h | 589 ++++ code/opus-1.0.2/silk/VAD.c | 330 ++ code/opus-1.0.2/silk/VQ_WMat_EC.c | 111 + code/opus-1.0.2/silk/ana_filt_bank_1.c | 74 + code/opus-1.0.2/silk/biquad_alt.c | 78 + code/opus-1.0.2/silk/bwexpander.c | 51 + code/opus-1.0.2/silk/bwexpander_32.c | 50 + code/opus-1.0.2/silk/check_control_input.c | 106 + code/opus-1.0.2/silk/code_signs.c | 115 + code/opus-1.0.2/silk/control.h | 139 + code/opus-1.0.2/silk/control_SNR.c | 81 + .../opus-1.0.2/silk/control_audio_bandwidth.c | 123 + code/opus-1.0.2/silk/control_codec.c | 411 +++ code/opus-1.0.2/silk/debug.c | 170 + code/opus-1.0.2/silk/debug.h | 284 ++ code/opus-1.0.2/silk/dec_API.c | 392 +++ code/opus-1.0.2/silk/decode_core.c | 238 ++ code/opus-1.0.2/silk/decode_frame.c | 128 + code/opus-1.0.2/silk/decode_indices.c | 151 + code/opus-1.0.2/silk/decode_parameters.c | 115 + code/opus-1.0.2/silk/decode_pitch.c | 77 + code/opus-1.0.2/silk/decode_pulses.c | 115 + code/opus-1.0.2/silk/decoder_set_fs.c | 108 + code/opus-1.0.2/silk/define.h | 235 ++ code/opus-1.0.2/silk/enc_API.c | 538 +++ code/opus-1.0.2/silk/encode_indices.c | 181 + code/opus-1.0.2/silk/encode_pulses.c | 199 ++ code/opus-1.0.2/silk/errors.h | 98 + .../silk/fixed/LTP_analysis_filter_FIX.c | 85 + .../silk/fixed/LTP_scale_ctrl_FIX.c | 53 + .../silk/fixed/apply_sine_window_FIX.c | 101 + code/opus-1.0.2/silk/fixed/autocorr_FIX.c | 76 + .../opus-1.0.2/silk/fixed/burg_modified_FIX.c | 269 ++ code/opus-1.0.2/silk/fixed/corrMatrix_FIX.c | 156 + code/opus-1.0.2/silk/fixed/encode_frame_FIX.c | 372 ++ code/opus-1.0.2/silk/fixed/find_LPC_FIX.c | 145 + code/opus-1.0.2/silk/fixed/find_LTP_FIX.c | 244 ++ .../silk/fixed/find_pitch_lags_FIX.c | 137 + .../silk/fixed/find_pred_coefs_FIX.c | 136 + code/opus-1.0.2/silk/fixed/k2a_FIX.c | 53 + code/opus-1.0.2/silk/fixed/k2a_Q16_FIX.c | 53 + code/opus-1.0.2/silk/fixed/main_FIX.h | 254 ++ .../silk/fixed/noise_shape_analysis_FIX.c | 440 +++ .../silk/fixed/pitch_analysis_core_FIX.c | 745 ++++ code/opus-1.0.2/silk/fixed/prefilter_FIX.c | 204 ++ .../opus-1.0.2/silk/fixed/process_gains_FIX.c | 117 + .../silk/fixed/regularize_correlations_FIX.c | 47 + .../silk/fixed/residual_energy16_FIX.c | 103 + .../silk/fixed/residual_energy_FIX.c | 91 + code/opus-1.0.2/silk/fixed/schur64_FIX.c | 77 + code/opus-1.0.2/silk/fixed/schur_FIX.c | 92 + code/opus-1.0.2/silk/fixed/solve_LS_FIX.c | 245 ++ code/opus-1.0.2/silk/fixed/structs_FIX.h | 133 + code/opus-1.0.2/silk/fixed/vector_ops_FIX.c | 127 + .../silk/fixed/warped_autocorrelation_FIX.c | 88 + .../silk/float/LPC_analysis_filter_FLP.c | 249 ++ .../silk/float/LPC_inv_pred_gain_FLP.c | 76 + .../silk/float/LTP_analysis_filter_FLP.c | 75 + .../silk/float/LTP_scale_ctrl_FLP.c | 52 + code/opus-1.0.2/silk/float/SigProc_FLP.h | 203 ++ .../silk/float/apply_sine_window_FLP.c | 81 + .../silk/float/autocorrelation_FLP.c | 52 + .../opus-1.0.2/silk/float/burg_modified_FLP.c | 186 + code/opus-1.0.2/silk/float/bwexpander_FLP.c | 49 + code/opus-1.0.2/silk/float/corrMatrix_FLP.c | 93 + code/opus-1.0.2/silk/float/encode_frame_FLP.c | 372 ++ code/opus-1.0.2/silk/float/energy_FLP.c | 60 + code/opus-1.0.2/silk/float/find_LPC_FLP.c | 104 + code/opus-1.0.2/silk/float/find_LTP_FLP.c | 132 + .../silk/float/find_pitch_lags_FLP.c | 131 + .../silk/float/find_pred_coefs_FLP.c | 116 + .../opus-1.0.2/silk/float/inner_product_FLP.c | 60 + code/opus-1.0.2/silk/float/k2a_FLP.c | 53 + .../silk/float/levinsondurbin_FLP.c | 81 + code/opus-1.0.2/silk/float/main_FLP.h | 309 ++ .../silk/float/noise_shape_analysis_FLP.c | 365 ++ .../silk/float/pitch_analysis_core_FLP.c | 630 ++++ code/opus-1.0.2/silk/float/prefilter_FLP.c | 206 ++ .../opus-1.0.2/silk/float/process_gains_FLP.c | 103 + .../silk/float/regularize_correlations_FLP.c | 48 + .../silk/float/residual_energy_FLP.c | 117 + .../silk/float/scale_copy_vector_FLP.c | 57 + code/opus-1.0.2/silk/float/scale_vector_FLP.c | 56 + code/opus-1.0.2/silk/float/schur_FLP.c | 70 + code/opus-1.0.2/silk/float/solve_LS_FLP.c | 207 ++ code/opus-1.0.2/silk/float/sort_FLP.c | 83 + code/opus-1.0.2/silk/float/structs_FLP.h | 131 + .../silk/float/warped_autocorrelation_FLP.c | 73 + code/opus-1.0.2/silk/float/wrappers_FLP.c | 200 ++ code/opus-1.0.2/silk/gain_quant.c | 141 + code/opus-1.0.2/silk/init_decoder.c | 56 + code/opus-1.0.2/silk/init_encoder.c | 60 + code/opus-1.0.2/silk/inner_prod_aligned.c | 47 + code/opus-1.0.2/silk/interpolate.c | 51 + code/opus-1.0.2/silk/lin2log.c | 46 + code/opus-1.0.2/silk/log2lin.c | 56 + code/opus-1.0.2/silk/macros.h | 135 + code/opus-1.0.2/silk/main.h | 434 +++ code/opus-1.0.2/silk/pitch_est_defines.h | 88 + code/opus-1.0.2/silk/pitch_est_tables.c | 99 + code/opus-1.0.2/silk/process_NLSFs.c | 105 + code/opus-1.0.2/silk/quant_LTP_gains.c | 107 + code/opus-1.0.2/silk/resampler.c | 215 ++ code/opus-1.0.2/silk/resampler_down2.c | 74 + code/opus-1.0.2/silk/resampler_down2_3.c | 98 + code/opus-1.0.2/silk/resampler_private.h | 88 + code/opus-1.0.2/silk/resampler_private_AR2.c | 55 + .../silk/resampler_private_IIR_FIR.c | 103 + .../silk/resampler_private_down_FIR.c | 189 + .../silk/resampler_private_up2_HQ.c | 113 + code/opus-1.0.2/silk/resampler_rom.c | 96 + code/opus-1.0.2/silk/resampler_rom.h | 68 + code/opus-1.0.2/silk/resampler_structs.h | 57 + code/opus-1.0.2/silk/shell_coder.c | 151 + code/opus-1.0.2/silk/sigm_Q15.c | 76 + code/opus-1.0.2/silk/sort.c | 154 + code/opus-1.0.2/silk/stereo_LR_to_MS.c | 219 ++ code/opus-1.0.2/silk/stereo_MS_to_LR.c | 85 + code/opus-1.0.2/silk/stereo_decode_pred.c | 73 + code/opus-1.0.2/silk/stereo_encode_pred.c | 62 + code/opus-1.0.2/silk/stereo_find_predictor.c | 79 + code/opus-1.0.2/silk/stereo_quant_pred.c | 73 + code/opus-1.0.2/silk/structs.h | 324 ++ code/opus-1.0.2/silk/sum_sqr_shift.c | 85 + code/opus-1.0.2/silk/table_LSF_cos.c | 70 + code/opus-1.0.2/silk/tables.h | 120 + code/opus-1.0.2/silk/tables_LTP.c | 272 ++ code/opus-1.0.2/silk/tables_NLSF_CB_NB_MB.c | 159 + code/opus-1.0.2/silk/tables_NLSF_CB_WB.c | 198 ++ code/opus-1.0.2/silk/tables_gain.c | 63 + code/opus-1.0.2/silk/tables_other.c | 138 + code/opus-1.0.2/silk/tables_pitch_lag.c | 69 + .../opus-1.0.2/silk/tables_pulses_per_block.c | 264 ++ code/opus-1.0.2/silk/tuning_parameters.h | 168 + code/opus-1.0.2/silk/typedef.h | 77 + code/opus-1.0.2/src/opus.c | 47 + code/opus-1.0.2/src/opus_decoder.c | 1051 ++++++ code/opus-1.0.2/src/opus_encoder.c | 1617 +++++++++ code/opus-1.0.2/src/opus_multistream.c | 1027 ++++++ code/opus-1.0.2/src/opus_private.h | 85 + code/opus-1.0.2/src/repacketizer.c | 208 ++ code/opusfile-0.2/include/opusfile.h | 1623 +++++++++ code/opusfile-0.2/src/http.c | 3075 +++++++++++++++++ code/opusfile-0.2/src/info.c | 286 ++ code/opusfile-0.2/src/internal.c | 38 + code/opusfile-0.2/src/internal.h | 217 ++ code/opusfile-0.2/src/opusfile.c | 2994 ++++++++++++++++ code/opusfile-0.2/src/stream.c | 184 + code/q3_ui/ui_controls2.c | 27 +- code/q3_ui/ui_local.h | 2 +- code/q3_ui/ui_players.c | 14 +- code/q3_ui/ui_serverinfo.c | 4 +- code/q3_ui/ui_servers2.c | 5 - code/qcommon/cm_polylib.c | 8 +- code/qcommon/cm_trace.c | 8 +- code/qcommon/cmd.c | 2 +- code/qcommon/common.c | 10 +- code/qcommon/cvar.c | 26 +- code/qcommon/files.c | 521 +-- code/qcommon/huffman.c | 2 - code/qcommon/msg.c | 67 +- code/qcommon/net_ip.c | 4 +- code/qcommon/q_platform.h | 16 +- code/qcommon/q_shared.c | 35 +- code/qcommon/q_shared.h | 9 +- code/qcommon/qcommon.h | 12 +- code/qcommon/qfiles.h | 7 - code/qcommon/unzip.c | 14 +- code/qcommon/vm_powerpc.c | 8 +- code/qcommon/vm_sparc.c | 2 +- code/qcommon/vm_x86.c | 3 +- code/qcommon/vm_x86_64.c | 1096 ------ code/qcommon/vm_x86_64_assembler.c | 1461 -------- code/rend2/tr_image_bmp.c | 243 -- code/rend2/tr_image_jpg.c | 441 --- code/rend2/tr_image_pcx.c | 179 - code/rend2/tr_image_png.c | 2490 ------------- code/rend2/tr_image_tga.c | 324 -- code/renderer/qgl.h | 380 -- code/renderer/qglextensions.h | 67 - code/renderer/tr_extramath.c | 151 - code/renderer/tr_extramath.h | 74 - code/renderer/tr_fbo.c | 499 --- code/renderer/tr_font.c | 555 --- code/renderer/tr_glsl.c | 2079 ----------- code/renderer/tr_noise.c | 93 - code/renderer/tr_postprocess.c | 494 --- code/renderer/tr_vbo.c | 867 ----- code/{renderer => renderercommon}/iqm.h | 0 code/{rend2 => renderercommon}/qgl.h | 675 ++-- code/renderercommon/tr_common.h | 157 + code/{rend2 => renderercommon}/tr_font.c | 19 +- .../tr_image_bmp.c | 7 +- .../tr_image_jpg.c | 8 +- .../tr_image_pcx.c | 6 +- .../tr_image_png.c | 7 +- .../tr_image_tga.c | 11 +- code/{rend2 => renderercommon}/tr_noise.c | 4 +- code/{renderer => renderercommon}/tr_public.h | 0 code/{renderer => renderercommon}/tr_types.h | 5 +- code/{renderer => renderergl1}/tr_animation.c | 3 - code/{renderer => renderergl1}/tr_backend.c | 63 +- code/{renderer => renderergl1}/tr_bsp.c | 13 +- code/{renderer => renderergl1}/tr_cmds.c | 98 +- code/{renderer => renderergl1}/tr_curve.c | 0 code/{renderer => renderergl1}/tr_flares.c | 6 +- code/{renderer => renderergl1}/tr_image.c | 235 +- code/{renderer => renderergl1}/tr_init.c | 50 +- code/{renderer => renderergl1}/tr_light.c | 6 +- code/{renderer => renderergl1}/tr_local.h | 160 +- code/{renderer => renderergl1}/tr_main.c | 13 +- code/{renderer => renderergl1}/tr_marks.c | 4 +- code/{renderer => renderergl1}/tr_mesh.c | 4 - code/{renderer => renderergl1}/tr_model.c | 66 +- code/{renderer => renderergl1}/tr_model_iqm.c | 255 +- code/{renderer => renderergl1}/tr_scene.c | 32 +- code/{renderer => renderergl1}/tr_shade.c | 0 .../{renderer => renderergl1}/tr_shade_calc.c | 0 code/{renderer => renderergl1}/tr_shader.c | 123 +- code/{rend2 => renderergl1}/tr_shadows.c | 0 code/{renderer => renderergl1}/tr_sky.c | 63 +- code/{rend2 => renderergl1}/tr_subs.c | 0 code/{renderer => renderergl1}/tr_surface.c | 10 +- code/{renderer => renderergl1}/tr_world.c | 10 +- .../{rend2 => renderergl2}/glsl/bokeh_fp.glsl | 0 .../{rend2 => renderergl2}/glsl/bokeh_vp.glsl | 0 .../glsl/calclevels4x_fp.glsl | 0 .../glsl/calclevels4x_vp.glsl | 0 .../glsl/depthblur_fp.glsl | 0 .../glsl/depthblur_vp.glsl | 0 .../glsl/dlight_fp.glsl | 0 .../glsl/dlight_vp.glsl | 0 .../glsl/down4x_fp.glsl | 0 .../glsl/down4x_vp.glsl | 0 .../glsl/fogpass_fp.glsl | 0 .../glsl/fogpass_vp.glsl | 0 .../glsl/generic_fp.glsl | 0 .../glsl/generic_vp.glsl | 0 .../glsl/lightall_fp.glsl | 235 +- .../glsl/lightall_vp.glsl | 79 +- .../glsl/pshadow_fp.glsl | 0 .../glsl/pshadow_vp.glsl | 0 .../glsl/shadowfill_fp.glsl | 0 .../glsl/shadowfill_vp.glsl | 0 .../glsl/shadowmask_fp.glsl | 2 +- .../glsl/shadowmask_vp.glsl | 0 code/{rend2 => renderergl2}/glsl/ssao_fp.glsl | 0 code/{rend2 => renderergl2}/glsl/ssao_vp.glsl | 0 .../glsl/texturecolor_fp.glsl | 0 .../glsl/texturecolor_vp.glsl | 0 .../glsl/tonemap_fp.glsl | 0 .../glsl/tonemap_vp.glsl | 0 code/{rend2 => renderergl2}/tr_animation.c | 2 - code/{rend2 => renderergl2}/tr_backend.c | 394 +-- code/{rend2 => renderergl2}/tr_bsp.c | 231 +- code/{rend2 => renderergl2}/tr_cmds.c | 98 +- code/{rend2 => renderergl2}/tr_curve.c | 0 code/{rend2 => renderergl2}/tr_extensions.c | 0 code/{rend2 => renderergl2}/tr_extramath.c | 0 code/{rend2 => renderergl2}/tr_extramath.h | 1 + code/{rend2 => renderergl2}/tr_extratypes.h | 5 +- code/{rend2 => renderergl2}/tr_fbo.c | 32 +- code/{rend2 => renderergl2}/tr_fbo.h | 0 code/{rend2 => renderergl2}/tr_flares.c | 4 +- code/{rend2 => renderergl2}/tr_glsl.c | 602 ++-- code/{rend2 => renderergl2}/tr_image.c | 119 +- code/{rend2 => renderergl2}/tr_init.c | 81 +- code/{rend2 => renderergl2}/tr_light.c | 14 +- code/{rend2 => renderergl2}/tr_local.h | 440 +-- code/{rend2 => renderergl2}/tr_main.c | 36 +- code/{rend2 => renderergl2}/tr_marks.c | 4 +- code/{rend2 => renderergl2}/tr_mesh.c | 4 - code/{rend2 => renderergl2}/tr_model.c | 73 +- code/{rend2 => renderergl2}/tr_model_iqm.c | 255 +- code/{rend2 => renderergl2}/tr_postprocess.c | 101 +- code/{rend2 => renderergl2}/tr_postprocess.h | 6 +- code/{rend2 => renderergl2}/tr_scene.c | 82 +- code/{rend2 => renderergl2}/tr_shade.c | 408 +-- code/{rend2 => renderergl2}/tr_shade_calc.c | 4 +- code/{rend2 => renderergl2}/tr_shader.c | 137 +- code/{renderer => renderergl2}/tr_shadows.c | 0 code/{rend2 => renderergl2}/tr_sky.c | 87 +- code/{renderer => renderergl2}/tr_subs.c | 0 code/{rend2 => renderergl2}/tr_surface.c | 151 +- code/{rend2 => renderergl2}/tr_vbo.c | 30 +- code/{rend2 => renderergl2}/tr_world.c | 53 +- code/sdl/sdl_gamma.c | 2 +- code/sdl/sdl_glimp.c | 256 +- code/sdl/sdl_input.c | 18 +- code/server/server.h | 25 +- code/server/sv_bot.c | 2 + code/server/sv_client.c | 14 + code/server/sv_init.c | 8 +- code/server/sv_main.c | 28 +- code/server/sv_snapshot.c | 1 - code/server/sv_world.c | 1 - code/sys/con_win32.c | 155 +- code/sys/sys_unix.c | 17 +- code/sys/sys_win32.c | 26 +- code/tools/asm/q3asm.c | 2 - code/tools/lcc/cpp/cpp.c | 1 - code/tools/lcc/cpp/include.c | 1 - code/tools/lcc/cpp/macro.c | 1 - code/tools/lcc/cpp/unix.c | 4 +- code/tools/lcc/lburg/gram.c | 509 ++- code/ui/make-ui.bat | 52 - code/ui/ui.q3asm | 10 - code/ui/ui_local.h | 2 +- code/ui/ui_main.c | 10 +- code/ui/ui_shared.h | 2 +- code/zlib/inffast.c | 1 - cross-make-mingw.sh | 35 - cross-make-mingw64.sh | 35 - jenkins-ci-build.sh | 32 + make-macosx-app.sh | 375 ++ make-macosx-ub.sh | 202 +- make-macosx.sh | 155 +- misc/sdl-win32-fixes.diff | 596 ---- misc/setup/doit | 2 +- rend2-readme.txt => opengl2-readme.txt | 61 +- travis-ci-build.sh | 30 + 482 files changed, 66409 insertions(+), 21063 deletions(-) create mode 100644 .gitignore create mode 100644 BUGS create mode 100644 NOTTODO delete mode 100644 build/README delete mode 100644 code/AL/alctypes.h create mode 100644 code/AL/alext.h delete mode 100644 code/AL/altypes.h delete mode 100644 code/AL/alut.h create mode 100644 code/AL/efx-creative.h create mode 100644 code/AL/efx-presets.h create mode 100644 code/AL/efx.h delete mode 100644 code/botlib/lcc.mak delete mode 100644 code/botlib/linux-i386.mak delete mode 100644 code/cgame/cgame.q3asm delete mode 100644 code/cgame/cgame_ta.q3asm delete mode 100644 code/cgame/make-cgame.bat delete mode 100644 code/cgame/tr_types.h create mode 100644 code/client/snd_codec_opus.c delete mode 100644 code/game/be_aas.h delete mode 100644 code/game/be_ai_char.h delete mode 100644 code/game/be_ai_chat.h delete mode 100644 code/game/be_ai_gen.h delete mode 100644 code/game/be_ai_goal.h delete mode 100644 code/game/be_ai_move.h delete mode 100644 code/game/be_ai_weap.h delete mode 100644 code/game/be_ea.h delete mode 100644 code/game/botai.h delete mode 100644 code/game/botlib.h delete mode 100644 code/game/g_fileio.c delete mode 100644 code/game/game.q3asm delete mode 100644 code/game/game_ta.q3asm delete mode 100644 code/game/make-game.bat create mode 100644 code/libogg-1.3.0/include/ogg/config_types.h create mode 100644 code/libogg-1.3.0/include/ogg/ogg.h create mode 100644 code/libogg-1.3.0/include/ogg/os_types.h create mode 100644 code/libogg-1.3.0/src/bitwise.c create mode 100644 code/libogg-1.3.0/src/framing.c create mode 100644 code/opus-1.0.2/celt/_kiss_fft_guts.h create mode 100644 code/opus-1.0.2/celt/arch.h create mode 100644 code/opus-1.0.2/celt/bands.c create mode 100644 code/opus-1.0.2/celt/bands.h create mode 100644 code/opus-1.0.2/celt/celt.c create mode 100644 code/opus-1.0.2/celt/celt.h create mode 100644 code/opus-1.0.2/celt/celt_lpc.c create mode 100644 code/opus-1.0.2/celt/celt_lpc.h create mode 100644 code/opus-1.0.2/celt/cwrs.c create mode 100644 code/opus-1.0.2/celt/cwrs.h create mode 100644 code/opus-1.0.2/celt/ecintrin.h create mode 100644 code/opus-1.0.2/celt/entcode.c create mode 100644 code/opus-1.0.2/celt/entcode.h create mode 100644 code/opus-1.0.2/celt/entdec.c create mode 100644 code/opus-1.0.2/celt/entdec.h create mode 100644 code/opus-1.0.2/celt/entenc.c create mode 100644 code/opus-1.0.2/celt/entenc.h create mode 100644 code/opus-1.0.2/celt/fixed_debug.h create mode 100644 code/opus-1.0.2/celt/fixed_generic.h create mode 100644 code/opus-1.0.2/celt/float_cast.h create mode 100644 code/opus-1.0.2/celt/kiss_fft.c create mode 100644 code/opus-1.0.2/celt/kiss_fft.h create mode 100644 code/opus-1.0.2/celt/laplace.c create mode 100644 code/opus-1.0.2/celt/laplace.h create mode 100644 code/opus-1.0.2/celt/mathops.c create mode 100644 code/opus-1.0.2/celt/mathops.h create mode 100644 code/opus-1.0.2/celt/mdct.c create mode 100644 code/opus-1.0.2/celt/mdct.h create mode 100644 code/opus-1.0.2/celt/mfrngcod.h create mode 100644 code/opus-1.0.2/celt/modes.c create mode 100644 code/opus-1.0.2/celt/modes.h create mode 100644 code/opus-1.0.2/celt/opus_custom_demo.c create mode 100644 code/opus-1.0.2/celt/os_support.h create mode 100644 code/opus-1.0.2/celt/pitch.c create mode 100644 code/opus-1.0.2/celt/pitch.h create mode 100644 code/opus-1.0.2/celt/quant_bands.c create mode 100644 code/opus-1.0.2/celt/quant_bands.h create mode 100644 code/opus-1.0.2/celt/rate.c create mode 100644 code/opus-1.0.2/celt/rate.h create mode 100644 code/opus-1.0.2/celt/stack_alloc.h create mode 100644 code/opus-1.0.2/celt/static_modes_fixed.h create mode 100644 code/opus-1.0.2/celt/static_modes_float.h create mode 100644 code/opus-1.0.2/celt/vq.c create mode 100644 code/opus-1.0.2/celt/vq.h create mode 100644 code/opus-1.0.2/include/opus.h create mode 100644 code/opus-1.0.2/include/opus_custom.h create mode 100644 code/opus-1.0.2/include/opus_defines.h create mode 100644 code/opus-1.0.2/include/opus_multistream.h create mode 100644 code/opus-1.0.2/include/opus_types.h create mode 100644 code/opus-1.0.2/silk/A2NLSF.c create mode 100644 code/opus-1.0.2/silk/API.h create mode 100644 code/opus-1.0.2/silk/CNG.c create mode 100644 code/opus-1.0.2/silk/HP_variable_cutoff.c create mode 100644 code/opus-1.0.2/silk/Inlines.h create mode 100644 code/opus-1.0.2/silk/LPC_analysis_filter.c create mode 100644 code/opus-1.0.2/silk/LPC_inv_pred_gain.c create mode 100644 code/opus-1.0.2/silk/LP_variable_cutoff.c create mode 100644 code/opus-1.0.2/silk/MacroCount.h create mode 100644 code/opus-1.0.2/silk/MacroDebug.h create mode 100644 code/opus-1.0.2/silk/NLSF2A.c create mode 100644 code/opus-1.0.2/silk/NLSF_VQ.c create mode 100644 code/opus-1.0.2/silk/NLSF_VQ_weights_laroia.c create mode 100644 code/opus-1.0.2/silk/NLSF_decode.c create mode 100644 code/opus-1.0.2/silk/NLSF_del_dec_quant.c create mode 100644 code/opus-1.0.2/silk/NLSF_encode.c create mode 100644 code/opus-1.0.2/silk/NLSF_stabilize.c create mode 100644 code/opus-1.0.2/silk/NLSF_unpack.c create mode 100644 code/opus-1.0.2/silk/NSQ.c create mode 100644 code/opus-1.0.2/silk/NSQ_del_dec.c create mode 100644 code/opus-1.0.2/silk/PLC.c create mode 100644 code/opus-1.0.2/silk/PLC.h create mode 100644 code/opus-1.0.2/silk/SigProc_FIX.h create mode 100644 code/opus-1.0.2/silk/VAD.c create mode 100644 code/opus-1.0.2/silk/VQ_WMat_EC.c create mode 100644 code/opus-1.0.2/silk/ana_filt_bank_1.c create mode 100644 code/opus-1.0.2/silk/biquad_alt.c create mode 100644 code/opus-1.0.2/silk/bwexpander.c create mode 100644 code/opus-1.0.2/silk/bwexpander_32.c create mode 100644 code/opus-1.0.2/silk/check_control_input.c create mode 100644 code/opus-1.0.2/silk/code_signs.c create mode 100644 code/opus-1.0.2/silk/control.h create mode 100644 code/opus-1.0.2/silk/control_SNR.c create mode 100644 code/opus-1.0.2/silk/control_audio_bandwidth.c create mode 100644 code/opus-1.0.2/silk/control_codec.c create mode 100644 code/opus-1.0.2/silk/debug.c create mode 100644 code/opus-1.0.2/silk/debug.h create mode 100644 code/opus-1.0.2/silk/dec_API.c create mode 100644 code/opus-1.0.2/silk/decode_core.c create mode 100644 code/opus-1.0.2/silk/decode_frame.c create mode 100644 code/opus-1.0.2/silk/decode_indices.c create mode 100644 code/opus-1.0.2/silk/decode_parameters.c create mode 100644 code/opus-1.0.2/silk/decode_pitch.c create mode 100644 code/opus-1.0.2/silk/decode_pulses.c create mode 100644 code/opus-1.0.2/silk/decoder_set_fs.c create mode 100644 code/opus-1.0.2/silk/define.h create mode 100644 code/opus-1.0.2/silk/enc_API.c create mode 100644 code/opus-1.0.2/silk/encode_indices.c create mode 100644 code/opus-1.0.2/silk/encode_pulses.c create mode 100644 code/opus-1.0.2/silk/errors.h create mode 100644 code/opus-1.0.2/silk/fixed/LTP_analysis_filter_FIX.c create mode 100644 code/opus-1.0.2/silk/fixed/LTP_scale_ctrl_FIX.c create mode 100644 code/opus-1.0.2/silk/fixed/apply_sine_window_FIX.c create mode 100644 code/opus-1.0.2/silk/fixed/autocorr_FIX.c create mode 100644 code/opus-1.0.2/silk/fixed/burg_modified_FIX.c create mode 100644 code/opus-1.0.2/silk/fixed/corrMatrix_FIX.c create mode 100644 code/opus-1.0.2/silk/fixed/encode_frame_FIX.c create mode 100644 code/opus-1.0.2/silk/fixed/find_LPC_FIX.c create mode 100644 code/opus-1.0.2/silk/fixed/find_LTP_FIX.c create mode 100644 code/opus-1.0.2/silk/fixed/find_pitch_lags_FIX.c create mode 100644 code/opus-1.0.2/silk/fixed/find_pred_coefs_FIX.c create mode 100644 code/opus-1.0.2/silk/fixed/k2a_FIX.c create mode 100644 code/opus-1.0.2/silk/fixed/k2a_Q16_FIX.c create mode 100644 code/opus-1.0.2/silk/fixed/main_FIX.h create mode 100644 code/opus-1.0.2/silk/fixed/noise_shape_analysis_FIX.c create mode 100644 code/opus-1.0.2/silk/fixed/pitch_analysis_core_FIX.c create mode 100644 code/opus-1.0.2/silk/fixed/prefilter_FIX.c create mode 100644 code/opus-1.0.2/silk/fixed/process_gains_FIX.c create mode 100644 code/opus-1.0.2/silk/fixed/regularize_correlations_FIX.c create mode 100644 code/opus-1.0.2/silk/fixed/residual_energy16_FIX.c create mode 100644 code/opus-1.0.2/silk/fixed/residual_energy_FIX.c create mode 100644 code/opus-1.0.2/silk/fixed/schur64_FIX.c create mode 100644 code/opus-1.0.2/silk/fixed/schur_FIX.c create mode 100644 code/opus-1.0.2/silk/fixed/solve_LS_FIX.c create mode 100644 code/opus-1.0.2/silk/fixed/structs_FIX.h create mode 100644 code/opus-1.0.2/silk/fixed/vector_ops_FIX.c create mode 100644 code/opus-1.0.2/silk/fixed/warped_autocorrelation_FIX.c create mode 100644 code/opus-1.0.2/silk/float/LPC_analysis_filter_FLP.c create mode 100644 code/opus-1.0.2/silk/float/LPC_inv_pred_gain_FLP.c create mode 100644 code/opus-1.0.2/silk/float/LTP_analysis_filter_FLP.c create mode 100644 code/opus-1.0.2/silk/float/LTP_scale_ctrl_FLP.c create mode 100644 code/opus-1.0.2/silk/float/SigProc_FLP.h create mode 100644 code/opus-1.0.2/silk/float/apply_sine_window_FLP.c create mode 100644 code/opus-1.0.2/silk/float/autocorrelation_FLP.c create mode 100644 code/opus-1.0.2/silk/float/burg_modified_FLP.c create mode 100644 code/opus-1.0.2/silk/float/bwexpander_FLP.c create mode 100644 code/opus-1.0.2/silk/float/corrMatrix_FLP.c create mode 100644 code/opus-1.0.2/silk/float/encode_frame_FLP.c create mode 100644 code/opus-1.0.2/silk/float/energy_FLP.c create mode 100644 code/opus-1.0.2/silk/float/find_LPC_FLP.c create mode 100644 code/opus-1.0.2/silk/float/find_LTP_FLP.c create mode 100644 code/opus-1.0.2/silk/float/find_pitch_lags_FLP.c create mode 100644 code/opus-1.0.2/silk/float/find_pred_coefs_FLP.c create mode 100644 code/opus-1.0.2/silk/float/inner_product_FLP.c create mode 100644 code/opus-1.0.2/silk/float/k2a_FLP.c create mode 100644 code/opus-1.0.2/silk/float/levinsondurbin_FLP.c create mode 100644 code/opus-1.0.2/silk/float/main_FLP.h create mode 100644 code/opus-1.0.2/silk/float/noise_shape_analysis_FLP.c create mode 100644 code/opus-1.0.2/silk/float/pitch_analysis_core_FLP.c create mode 100644 code/opus-1.0.2/silk/float/prefilter_FLP.c create mode 100644 code/opus-1.0.2/silk/float/process_gains_FLP.c create mode 100644 code/opus-1.0.2/silk/float/regularize_correlations_FLP.c create mode 100644 code/opus-1.0.2/silk/float/residual_energy_FLP.c create mode 100644 code/opus-1.0.2/silk/float/scale_copy_vector_FLP.c create mode 100644 code/opus-1.0.2/silk/float/scale_vector_FLP.c create mode 100644 code/opus-1.0.2/silk/float/schur_FLP.c create mode 100644 code/opus-1.0.2/silk/float/solve_LS_FLP.c create mode 100644 code/opus-1.0.2/silk/float/sort_FLP.c create mode 100644 code/opus-1.0.2/silk/float/structs_FLP.h create mode 100644 code/opus-1.0.2/silk/float/warped_autocorrelation_FLP.c create mode 100644 code/opus-1.0.2/silk/float/wrappers_FLP.c create mode 100644 code/opus-1.0.2/silk/gain_quant.c create mode 100644 code/opus-1.0.2/silk/init_decoder.c create mode 100644 code/opus-1.0.2/silk/init_encoder.c create mode 100644 code/opus-1.0.2/silk/inner_prod_aligned.c create mode 100644 code/opus-1.0.2/silk/interpolate.c create mode 100644 code/opus-1.0.2/silk/lin2log.c create mode 100644 code/opus-1.0.2/silk/log2lin.c create mode 100644 code/opus-1.0.2/silk/macros.h create mode 100644 code/opus-1.0.2/silk/main.h create mode 100644 code/opus-1.0.2/silk/pitch_est_defines.h create mode 100644 code/opus-1.0.2/silk/pitch_est_tables.c create mode 100644 code/opus-1.0.2/silk/process_NLSFs.c create mode 100644 code/opus-1.0.2/silk/quant_LTP_gains.c create mode 100644 code/opus-1.0.2/silk/resampler.c create mode 100644 code/opus-1.0.2/silk/resampler_down2.c create mode 100644 code/opus-1.0.2/silk/resampler_down2_3.c create mode 100644 code/opus-1.0.2/silk/resampler_private.h create mode 100644 code/opus-1.0.2/silk/resampler_private_AR2.c create mode 100644 code/opus-1.0.2/silk/resampler_private_IIR_FIR.c create mode 100644 code/opus-1.0.2/silk/resampler_private_down_FIR.c create mode 100644 code/opus-1.0.2/silk/resampler_private_up2_HQ.c create mode 100644 code/opus-1.0.2/silk/resampler_rom.c create mode 100644 code/opus-1.0.2/silk/resampler_rom.h create mode 100644 code/opus-1.0.2/silk/resampler_structs.h create mode 100644 code/opus-1.0.2/silk/shell_coder.c create mode 100644 code/opus-1.0.2/silk/sigm_Q15.c create mode 100644 code/opus-1.0.2/silk/sort.c create mode 100644 code/opus-1.0.2/silk/stereo_LR_to_MS.c create mode 100644 code/opus-1.0.2/silk/stereo_MS_to_LR.c create mode 100644 code/opus-1.0.2/silk/stereo_decode_pred.c create mode 100644 code/opus-1.0.2/silk/stereo_encode_pred.c create mode 100644 code/opus-1.0.2/silk/stereo_find_predictor.c create mode 100644 code/opus-1.0.2/silk/stereo_quant_pred.c create mode 100644 code/opus-1.0.2/silk/structs.h create mode 100644 code/opus-1.0.2/silk/sum_sqr_shift.c create mode 100644 code/opus-1.0.2/silk/table_LSF_cos.c create mode 100644 code/opus-1.0.2/silk/tables.h create mode 100644 code/opus-1.0.2/silk/tables_LTP.c create mode 100644 code/opus-1.0.2/silk/tables_NLSF_CB_NB_MB.c create mode 100644 code/opus-1.0.2/silk/tables_NLSF_CB_WB.c create mode 100644 code/opus-1.0.2/silk/tables_gain.c create mode 100644 code/opus-1.0.2/silk/tables_other.c create mode 100644 code/opus-1.0.2/silk/tables_pitch_lag.c create mode 100644 code/opus-1.0.2/silk/tables_pulses_per_block.c create mode 100644 code/opus-1.0.2/silk/tuning_parameters.h create mode 100644 code/opus-1.0.2/silk/typedef.h create mode 100644 code/opus-1.0.2/src/opus.c create mode 100644 code/opus-1.0.2/src/opus_decoder.c create mode 100644 code/opus-1.0.2/src/opus_encoder.c create mode 100644 code/opus-1.0.2/src/opus_multistream.c create mode 100644 code/opus-1.0.2/src/opus_private.h create mode 100644 code/opus-1.0.2/src/repacketizer.c create mode 100644 code/opusfile-0.2/include/opusfile.h create mode 100644 code/opusfile-0.2/src/http.c create mode 100644 code/opusfile-0.2/src/info.c create mode 100644 code/opusfile-0.2/src/internal.c create mode 100644 code/opusfile-0.2/src/internal.h create mode 100644 code/opusfile-0.2/src/opusfile.c create mode 100644 code/opusfile-0.2/src/stream.c delete mode 100644 code/qcommon/vm_x86_64.c delete mode 100644 code/qcommon/vm_x86_64_assembler.c delete mode 100644 code/rend2/tr_image_bmp.c delete mode 100644 code/rend2/tr_image_jpg.c delete mode 100644 code/rend2/tr_image_pcx.c delete mode 100644 code/rend2/tr_image_png.c delete mode 100644 code/rend2/tr_image_tga.c delete mode 100644 code/renderer/qgl.h delete mode 100644 code/renderer/qglextensions.h delete mode 100644 code/renderer/tr_extramath.c delete mode 100644 code/renderer/tr_extramath.h delete mode 100644 code/renderer/tr_fbo.c delete mode 100644 code/renderer/tr_font.c delete mode 100644 code/renderer/tr_glsl.c delete mode 100644 code/renderer/tr_noise.c delete mode 100644 code/renderer/tr_postprocess.c delete mode 100644 code/renderer/tr_vbo.c rename code/{renderer => renderercommon}/iqm.h (100%) rename code/{rend2 => renderercommon}/qgl.h (99%) create mode 100644 code/renderercommon/tr_common.h rename code/{rend2 => renderercommon}/tr_font.c (98%) rename code/{renderer => renderercommon}/tr_image_bmp.c (97%) rename code/{renderer => renderercommon}/tr_image_jpg.c (98%) rename code/{renderer => renderercommon}/tr_image_pcx.c (96%) rename code/{renderer => renderercommon}/tr_image_png.c (99%) rename code/{renderer => renderercommon}/tr_image_tga.c (97%) rename code/{rend2 => renderercommon}/tr_noise.c (96%) rename code/{renderer => renderercommon}/tr_public.h (100%) rename code/{renderer => renderercommon}/tr_types.h (98%) rename code/{renderer => renderergl1}/tr_animation.c (99%) rename code/{renderer => renderergl1}/tr_backend.c (96%) rename code/{renderer => renderergl1}/tr_bsp.c (99%) rename code/{renderer => renderergl1}/tr_cmds.c (84%) rename code/{renderer => renderergl1}/tr_curve.c (100%) rename code/{renderer => renderergl1}/tr_flares.c (99%) rename code/{renderer => renderergl1}/tr_image.c (88%) rename code/{renderer => renderergl1}/tr_init.c (96%) rename code/{renderer => renderergl1}/tr_light.c (98%) rename code/{renderer => renderergl1}/tr_local.h (89%) rename code/{renderer => renderergl1}/tr_main.c (99%) rename code/{renderer => renderergl1}/tr_marks.c (99%) rename code/{renderer => renderergl1}/tr_mesh.c (99%) rename code/{renderer => renderergl1}/tr_model.c (96%) rename code/{renderer => renderergl1}/tr_model_iqm.c (84%) rename code/{renderer => renderergl1}/tr_scene.c (91%) rename code/{renderer => renderergl1}/tr_shade.c (100%) rename code/{renderer => renderergl1}/tr_shade_calc.c (100%) rename code/{renderer => renderergl1}/tr_shader.c (97%) rename code/{rend2 => renderergl1}/tr_shadows.c (100%) rename code/{renderer => renderergl1}/tr_sky.c (90%) rename code/{rend2 => renderergl1}/tr_subs.c (100%) rename code/{renderer => renderergl1}/tr_surface.c (99%) rename code/{renderer => renderergl1}/tr_world.c (98%) rename code/{rend2 => renderergl2}/glsl/bokeh_fp.glsl (100%) rename code/{rend2 => renderergl2}/glsl/bokeh_vp.glsl (100%) rename code/{rend2 => renderergl2}/glsl/calclevels4x_fp.glsl (100%) rename code/{rend2 => renderergl2}/glsl/calclevels4x_vp.glsl (100%) rename code/{rend2 => renderergl2}/glsl/depthblur_fp.glsl (100%) rename code/{rend2 => renderergl2}/glsl/depthblur_vp.glsl (100%) rename code/{rend2 => renderergl2}/glsl/dlight_fp.glsl (100%) rename code/{rend2 => renderergl2}/glsl/dlight_vp.glsl (100%) rename code/{rend2 => renderergl2}/glsl/down4x_fp.glsl (100%) rename code/{rend2 => renderergl2}/glsl/down4x_vp.glsl (100%) rename code/{rend2 => renderergl2}/glsl/fogpass_fp.glsl (100%) rename code/{rend2 => renderergl2}/glsl/fogpass_vp.glsl (100%) rename code/{rend2 => renderergl2}/glsl/generic_fp.glsl (100%) rename code/{rend2 => renderergl2}/glsl/generic_vp.glsl (100%) rename code/{rend2 => renderergl2}/glsl/lightall_fp.glsl (54%) rename code/{rend2 => renderergl2}/glsl/lightall_vp.glsl (71%) rename code/{rend2 => renderergl2}/glsl/pshadow_fp.glsl (100%) rename code/{rend2 => renderergl2}/glsl/pshadow_vp.glsl (100%) rename code/{rend2 => renderergl2}/glsl/shadowfill_fp.glsl (100%) rename code/{rend2 => renderergl2}/glsl/shadowfill_vp.glsl (100%) rename code/{rend2 => renderergl2}/glsl/shadowmask_fp.glsl (99%) rename code/{rend2 => renderergl2}/glsl/shadowmask_vp.glsl (100%) rename code/{rend2 => renderergl2}/glsl/ssao_fp.glsl (100%) rename code/{rend2 => renderergl2}/glsl/ssao_vp.glsl (100%) rename code/{rend2 => renderergl2}/glsl/texturecolor_fp.glsl (100%) rename code/{rend2 => renderergl2}/glsl/texturecolor_vp.glsl (100%) rename code/{rend2 => renderergl2}/glsl/tonemap_fp.glsl (100%) rename code/{rend2 => renderergl2}/glsl/tonemap_vp.glsl (100%) rename code/{rend2 => renderergl2}/tr_animation.c (99%) rename code/{rend2 => renderergl2}/tr_backend.c (80%) rename code/{rend2 => renderergl2}/tr_bsp.c (93%) rename code/{rend2 => renderergl2}/tr_cmds.c (86%) rename code/{rend2 => renderergl2}/tr_curve.c (100%) rename code/{rend2 => renderergl2}/tr_extensions.c (100%) rename code/{rend2 => renderergl2}/tr_extramath.c (100%) rename code/{rend2 => renderergl2}/tr_extramath.h (98%) rename code/{rend2 => renderergl2}/tr_extratypes.h (92%) rename code/{rend2 => renderergl2}/tr_fbo.c (95%) rename code/{rend2 => renderergl2}/tr_fbo.h (100%) rename code/{rend2 => renderergl2}/tr_flares.c (99%) rename code/{rend2 => renderergl2}/tr_glsl.c (65%) rename code/{rend2 => renderergl2}/tr_image.c (96%) rename code/{rend2 => renderergl2}/tr_init.c (96%) rename code/{rend2 => renderergl2}/tr_light.c (97%) rename code/{rend2 => renderergl2}/tr_local.h (87%) rename code/{rend2 => renderergl2}/tr_main.c (99%) rename code/{rend2 => renderergl2}/tr_marks.c (99%) rename code/{rend2 => renderergl2}/tr_mesh.c (99%) rename code/{rend2 => renderergl2}/tr_model.c (96%) rename code/{rend2 => renderergl2}/tr_model_iqm.c (84%) rename code/{rend2 => renderergl2}/tr_postprocess.c (79%) rename code/{rend2 => renderergl2}/tr_postprocess.h (80%) rename code/{rend2 => renderergl2}/tr_scene.c (87%) rename code/{rend2 => renderergl2}/tr_shade.c (73%) rename code/{rend2 => renderergl2}/tr_shade_calc.c (99%) rename code/{rend2 => renderergl2}/tr_shader.c (96%) rename code/{renderer => renderergl2}/tr_shadows.c (100%) rename code/{rend2 => renderergl2}/tr_sky.c (88%) rename code/{renderer => renderergl2}/tr_subs.c (100%) rename code/{rend2 => renderergl2}/tr_surface.c (89%) rename code/{rend2 => renderergl2}/tr_vbo.c (96%) rename code/{rend2 => renderergl2}/tr_world.c (94%) delete mode 100644 code/ui/make-ui.bat delete mode 100644 code/ui/ui.q3asm delete mode 100755 cross-make-mingw.sh delete mode 100755 cross-make-mingw64.sh create mode 100755 jenkins-ci-build.sh create mode 100755 make-macosx-app.sh delete mode 100644 misc/sdl-win32-fixes.diff rename rend2-readme.txt => opengl2-readme.txt (94%) create mode 100755 travis-ci-build.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..b1758f67 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +build +*.swp +*tags + +# OS X +#################### +.Spotlight-V100/ +.Trashes/ +._* +.AppleDouble +.DS_Store +.LSOverride +Icon? + +# Xcode +#################### +*.mode1v3 +*.mode2v3 +*.pbxuser +*.perspectivev3 +*.user +*.xcuserstate +*.moved-aside +*~.nib +.idea/ +DerivedData/ +project.xcworkspace/ +xcuserdata/ +profile +!default.pbxuser +!default.mode1v3 +!default.mode2v3 +!default.perspectivev3 diff --git a/BUGS b/BUGS new file mode 100644 index 00000000..081c55dc --- /dev/null +++ b/BUGS @@ -0,0 +1,4 @@ +- On Solaris/SPARC gcc optimizations higher than -O0 currently lead + to a segfault + +https://bugzilla.icculus.org/ for more. diff --git a/Makefile b/Makefile index dd871f1e..3e7786a1 100644 --- a/Makefile +++ b/Makefile @@ -6,24 +6,15 @@ COMPILE_PLATFORM=$(shell uname|sed -e s/_.*//|tr '[:upper:]' '[:lower:]'|sed -e 's/\//_/g') -COMPILE_ARCH=$(shell uname -m | sed -e s/i.86/i386/) +COMPILE_ARCH=$(shell uname -m | sed -e s/i.86/x86/) ifeq ($(COMPILE_PLATFORM),sunos) # Solaris uname and GNU uname differ - COMPILE_ARCH=$(shell uname -p | sed -e s/i.86/i386/) + COMPILE_ARCH=$(shell uname -p | sed -e s/i.86/x86/) endif ifeq ($(COMPILE_PLATFORM),darwin) # Apple does some things a little differently... - COMPILE_ARCH=$(shell uname -p | sed -e s/i.86/i386/) -endif - -ifeq ($(COMPILE_PLATFORM),mingw32) - ifeq ($(COMPILE_ARCH),i386) - COMPILE_ARCH=x86 - endif - ifeq ($(COMPILE_ARCH),x86_64) - COMPILE_ARCH=x64 - endif + COMPILE_ARCH=$(shell uname -p | sed -e s/i.86/x86/) endif ifndef BUILD_STANDALONE @@ -32,9 +23,6 @@ endif ifndef BUILD_CLIENT BUILD_CLIENT = endif -ifndef BUILD_CLIENT_SMP - BUILD_CLIENT_SMP = -endif ifndef BUILD_SERVER BUILD_SERVER = endif @@ -50,12 +38,8 @@ endif ifndef BUILD_MISSIONPACK BUILD_MISSIONPACK= endif -ifndef BUILD_RENDERER_REND2 - BUILD_RENDERER_REND2= -endif - -ifneq ($(PLATFORM),darwin) - BUILD_CLIENT_SMP = 0 +ifndef BUILD_RENDERER_OPENGL2 + BUILD_RENDERER_OPENGL2= endif ############################################################################# @@ -73,6 +57,17 @@ PLATFORM=$(COMPILE_PLATFORM) endif export PLATFORM +ifeq ($(COMPILE_ARCH),i86pc) + COMPILE_ARCH=x86 +endif + +ifeq ($(COMPILE_ARCH),amd64) + COMPILE_ARCH=x86_64 +endif +ifeq ($(COMPILE_ARCH),x64) + COMPILE_ARCH=x86_64 +endif + ifeq ($(COMPILE_ARCH),powerpc) COMPILE_ARCH=ppc endif @@ -80,6 +75,10 @@ ifeq ($(COMPILE_ARCH),powerpc64) COMPILE_ARCH=ppc64 endif +ifeq ($(COMPILE_ARCH),axp) + COMPILE_ARCH=alpha +endif + ifndef ARCH ARCH=$(COMPILE_ARCH) endif @@ -172,6 +171,10 @@ ifndef USE_CODEC_VORBIS USE_CODEC_VORBIS=0 endif +ifndef USE_CODEC_OPUS +USE_CODEC_OPUS=1 +endif + ifndef USE_MUMBLE USE_MUMBLE=1 endif @@ -188,6 +191,14 @@ ifndef USE_INTERNAL_SPEEX USE_INTERNAL_SPEEX=1 endif +ifndef USE_INTERNAL_OGG +USE_INTERNAL_OGG=1 +endif + +ifndef USE_INTERNAL_OPUS +USE_INTERNAL_OPUS=1 +endif + ifndef USE_INTERNAL_ZLIB USE_INTERNAL_ZLIB=1 endif @@ -208,18 +219,15 @@ ifndef DEBUG_CFLAGS DEBUG_CFLAGS=-g -O0 endif -ifndef USE_OLD_VM64 -USE_OLD_VM64=0 -endif - ############################################################################# BD=$(BUILD_DIR)/debug-$(PLATFORM)-$(ARCH) BR=$(BUILD_DIR)/release-$(PLATFORM)-$(ARCH) CDIR=$(MOUNT_DIR)/client SDIR=$(MOUNT_DIR)/server -RDIR=$(MOUNT_DIR)/renderer -R2DIR=$(MOUNT_DIR)/rend2 +RCOMMONDIR=$(MOUNT_DIR)/renderercommon +RGL1DIR=$(MOUNT_DIR)/renderergl1 +RGL2DIR=$(MOUNT_DIR)/renderergl2 CMDIR=$(MOUNT_DIR)/qcommon SDLDIR=$(MOUNT_DIR)/sdl ASMDIR=$(MOUNT_DIR)/asm @@ -232,6 +240,9 @@ UIDIR=$(MOUNT_DIR)/ui Q3UIDIR=$(MOUNT_DIR)/ui JPDIR=$(MOUNT_DIR)/jpeg-8c SPEEXDIR=$(MOUNT_DIR)/libspeex +OGGDIR=$(MOUNT_DIR)/libogg-1.3.0 +OPUSDIR=$(MOUNT_DIR)/opus-1.0.2 +OPUSFILEDIR=$(MOUNT_DIR)/opusfile-0.2 ZDIR=$(MOUNT_DIR)/zlib Q3ASMDIR=$(MOUNT_DIR)/tools/asm LBURGDIR=$(MOUNT_DIR)/tools/lcc/lburg @@ -267,21 +278,14 @@ ifneq ($(BUILD_CLIENT),0) endif endif -# Add svn version info -USE_SVN= -ifeq ($(wildcard .svn),.svn) - SVN_REV=$(shell LANG=C svnversion .) - ifneq ($(SVN_REV),) - VERSION:=$(VERSION)_SVN$(SVN_REV) - USE_SVN=1 +# Add git version info +USE_GIT= +ifeq ($(wildcard .git),.git) + GIT_REV=$(shell git show -s --pretty=format:%h-%ad --date=short) + ifneq ($(GIT_REV),) + VERSION:=$(VERSION)_GIT_$(GIT_REV) + USE_GIT=1 endif -else -ifeq ($(wildcard .git/svn/.metadata),.git/svn/.metadata) - SVN_REV=$(shell LANG=C git svn info | awk '$$1 == "Revision:" {print $$2; exit 0}') - ifneq ($(SVN_REV),) - VERSION:=$(VERSION)_SVN$(SVN_REV) - endif -endif endif @@ -297,9 +301,6 @@ MKDIR=mkdir ifneq (,$(findstring "$(PLATFORM)", "linux" "gnu_kfreebsd" "kfreebsd-gnu")) - ifeq ($(ARCH),axp) - ARCH=alpha - else ifeq ($(ARCH),x86_64) LIB=lib64 else @@ -311,7 +312,6 @@ ifneq (,$(findstring "$(PLATFORM)", "linux" "gnu_kfreebsd" "kfreebsd-gnu")) endif endif endif - endif BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes \ -pipe -DUSE_ICON -DREACTION @@ -327,7 +327,7 @@ ifneq (,$(findstring "$(PLATFORM)", "linux" "gnu_kfreebsd" "kfreebsd-gnu")) OPTIMIZE = $(OPTIMIZEVM) -ffast-math HAVE_VM_COMPILED = true else - ifeq ($(ARCH),i386) + ifeq ($(ARCH),x86) OPTIMIZEVM = -O3 -march=i586 -fomit-frame-pointer \ -funroll-loops -falign-loops=2 -falign-jumps=2 \ -falign-functions=2 -fstrength-reduce @@ -377,10 +377,6 @@ ifneq (,$(findstring "$(PLATFORM)", "linux" "gnu_kfreebsd" "kfreebsd-gnu")) endif endif - ifeq ($(USE_CODEC_VORBIS),1) - CLIENT_LIBS += -lvorbisfile -lvorbis -logg - endif - ifeq ($(USE_MUMBLE),1) CLIENT_LIBS += -lrt endif @@ -389,7 +385,7 @@ ifneq (,$(findstring "$(PLATFORM)", "linux" "gnu_kfreebsd" "kfreebsd-gnu")) BASE_CFLAGS += $(FREETYPE_CFLAGS) endif - ifeq ($(ARCH),i386) + ifeq ($(ARCH),x86) # linux32 make ... BASE_CFLAGS += -m32 else @@ -405,11 +401,11 @@ else # ifeq Linux ifeq ($(PLATFORM),darwin) HAVE_VM_COMPILED=true - LIBS = -framework Cocoa -framework SDL + LIBS = -framework Cocoa CLIENT_LIBS= RENDERER_LIBS= OPTIMIZEVM= - + BASE_CFLAGS = -Wall -Wimplicit -Wstrict-prototypes -DREACTION ifeq ($(ARCH),ppc) @@ -419,7 +415,7 @@ ifeq ($(PLATFORM),darwin) ifeq ($(ARCH),ppc64) BASE_CFLAGS += -arch ppc64 -faltivec -mmacosx-version-min=10.2 endif - ifeq ($(ARCH),i386) + ifeq ($(ARCH),x86) OPTIMIZEVM += -march=prescott -mfpmath=sse # x86 vm will crash without -mstackrealign since MMX instructions will be # used no matter what and they corrupt the frame pointer in VM calls @@ -429,6 +425,29 @@ ifeq ($(PLATFORM),darwin) OPTIMIZEVM += -arch x86_64 -mfpmath=sse endif + # When compiling on OSX for OSX, we're not cross compiling as far as the + # Makefile is concerned, as target architecture is specified as a compiler + # argument + ifeq ($(COMPILE_PLATFORM),darwin) + CROSS_COMPILING=0 + endif + + ifeq ($(CROSS_COMPILING),1) + ifeq ($(ARCH),ppc) + CC=powerpc-apple-darwin10-gcc + RANLIB=powerpc-apple-darwin10-ranlib + else + ifeq ($(ARCH),x86) + CC=i686-apple-darwin10-gcc + RANLIB=i686-apple-darwin10-ranlib + else + $(error Architecture $(ARCH) is not supported when cross compiling) + endif + endif + else + TOOLS_CFLAGS += -DMACOS_X + endif + BASE_CFLAGS += -fno-strict-aliasing -DMACOS_X -fno-common -pipe ifeq ($(USE_OPENAL),1) @@ -447,10 +466,6 @@ ifeq ($(PLATFORM),darwin) BASE_CFLAGS += $(FREETYPE_CFLAGS) endif - ifeq ($(USE_CODEC_VORBIS),1) - CLIENT_LIBS += -lvorbisfile -lvorbis -logg - endif - BASE_CFLAGS += -D_THREAD_SAFE=1 ifeq ($(USE_LOCAL_HEADERS),1) @@ -462,8 +477,8 @@ ifeq ($(PLATFORM),darwin) LIBSDLMAIN=$(B)/libSDLmain.a LIBSDLMAINSRC=$(LIBSDIR)/macosx/libSDLmain.a CLIENT_LIBS += -framework IOKit \ - -framework SDL - RENDERER_LIBS += -framework OpenGL -framework SDL + $(LIBSDIR)/macosx/libSDL-1.2.0.dylib + RENDERER_LIBS += -framework OpenGL $(LIBSDIR)/macosx/libSDL-1.2.0.dylib OPTIMIZEVM += -falign-loops=16 OPTIMIZE = $(OPTIMIZEVM) -ffast-math @@ -474,8 +489,6 @@ ifeq ($(PLATFORM),darwin) NOTSHLIBCFLAGS=-mdynamic-no-pic - TOOLS_CFLAGS += -DMACOS_X - else # ifeq darwin @@ -485,14 +498,40 @@ else # ifeq darwin ifeq ($(PLATFORM),mingw32) - # Some MinGW installations define CC to cc, but don't actually provide cc, - # so explicitly use gcc instead (which is the only option anyway) - ifeq ($(call bin_path, $(CC)),) - CC=gcc - endif + ifeq ($(CROSS_COMPILING),1) + # If CC is already set to something generic, we probably want to use + # something more specific + ifneq ($(findstring $(strip $(CC)),cc gcc),) + CC= + endif - ifndef WINDRES - WINDRES=windres + # We need to figure out the correct gcc and windres + ifeq ($(ARCH),x86_64) + MINGW_PREFIXES=amd64-mingw32msvc x86_64-w64-mingw32 + endif + ifeq ($(ARCH),x86) + MINGW_PREFIXES=i586-mingw32msvc i686-w64-mingw32 + endif + + ifndef CC + CC=$(strip $(foreach MINGW_PREFIX, $(MINGW_PREFIXES), \ + $(call bin_path, $(MINGW_PREFIX)-gcc))) + endif + + ifndef WINDRES + WINDRES=$(strip $(foreach MINGW_PREFIX, $(MINGW_PREFIXES), \ + $(call bin_path, $(MINGW_PREFIX)-windres))) + endif + else + # Some MinGW installations define CC to cc, but don't actually provide cc, + # so check that CC points to a real binary and use gcc if it doesn't + ifeq ($(call bin_path, $(CC)),) + CC=gcc + endif + + ifndef WINDRES + WINDRES=windres + endif endif BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes \ @@ -509,8 +548,8 @@ ifeq ($(PLATFORM),mingw32) CLIENT_LDFLAGS += $(OPENAL_LDFLAGS) endif endif - - ifeq ($(ARCH),x64) + + ifeq ($(ARCH),x86_64) OPTIMIZEVM = -O3 -fno-omit-frame-pointer \ -falign-loops=2 -funroll-loops -falign-jumps=2 -falign-functions=2 \ -fstrength-reduce @@ -527,15 +566,19 @@ ifeq ($(PLATFORM),mingw32) SHLIBEXT=dll SHLIBCFLAGS= - SHLIBLDFLAGS=-shared $(LDFLAGS) + SHLIBLDFLAGS=-shared -static-libgcc $(LDFLAGS) BINEXT=.exe + ifeq ($(CROSS_COMPILING),0) + TOOLS_BINEXT=.exe + endif + LIBS= -lws2_32 -lwinmm -lpsapi CLIENT_LDFLAGS += -mwindows CLIENT_LIBS = -lgdi32 -lole32 RENDERER_LIBS = -lgdi32 -lole32 -lopengl32 - + ifeq ($(USE_FREETYPE),1) BASE_CFLAGS += -Ifreetype2 endif @@ -545,7 +588,7 @@ ifeq ($(PLATFORM),mingw32) ifneq ($(USE_CURL_DLOPEN),1) ifeq ($(USE_LOCAL_HEADERS),1) CLIENT_CFLAGS += -DCURL_STATICLIB - ifeq ($(ARCH),x64) + ifeq ($(ARCH),x86_64) CLIENT_LIBS += $(LIBSDIR)/win64/libcurl.a else CLIENT_LIBS += $(LIBSDIR)/win32/libcurl.a @@ -556,10 +599,6 @@ ifeq ($(PLATFORM),mingw32) endif endif - ifeq ($(USE_CODEC_VORBIS),1) - CLIENT_LIBS += -lvorbisfile -lvorbis -logg - endif - ifeq ($(ARCH),x86) # build 32bit BASE_CFLAGS += -m32 @@ -570,10 +609,10 @@ ifeq ($(PLATFORM),mingw32) # libmingw32 must be linked before libSDLmain CLIENT_LIBS += -lmingw32 RENDERER_LIBS += -lmingw32 - + ifeq ($(USE_LOCAL_HEADERS),1) CLIENT_CFLAGS += -I$(SDLHDIR)/include - ifeq ($(ARCH), x86) + ifeq ($(ARCH),x86) CLIENT_LIBS += $(LIBSDIR)/win32/libSDLmain.a \ $(LIBSDIR)/win32/libSDL.dll.a RENDERER_LIBS += $(LIBSDIR)/win32/libSDLmain.a \ @@ -593,8 +632,6 @@ ifeq ($(PLATFORM),mingw32) SDLDLL=SDL.dll endif - BUILD_CLIENT_SMP = 0 - else # ifeq mingw32 ############################################################################# @@ -639,22 +676,17 @@ ifeq ($(PLATFORM),freebsd) endif endif - ifeq ($(USE_CODEC_VORBIS),1) - CLIENT_LIBS += -lvorbisfile -lvorbis -logg - endif - # cross-compiling tweaks - ifeq ($(ARCH),i386) + ifeq ($(ARCH),x86) ifeq ($(CROSS_COMPILING),1) BASE_CFLAGS += -m32 endif endif - ifeq ($(ARCH),amd64) + ifeq ($(ARCH),x86_64) ifeq ($(CROSS_COMPILING),1) BASE_CFLAGS += -m64 endif endif - else # ifeq freebsd ############################################################################# @@ -663,12 +695,48 @@ else # ifeq freebsd ifeq ($(PLATFORM),openbsd) - ARCH=$(shell uname -m) - BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes \ - -DUSE_ICON -DMAP_ANONYMOUS=MAP_ANON -DREACTION + -pipe -DUSE_ICON -DMAP_ANONYMOUS=MAP_ANON -DREACTION CLIENT_CFLAGS += $(SDL_CFLAGS) + OPTIMIZEVM = -O3 -funroll-loops -fomit-frame-pointer + OPTIMIZE = $(OPTIMIZEVM) -ffast-math + + ifeq ($(ARCH),x86_64) + OPTIMIZEVM = -O3 -fomit-frame-pointer -funroll-loops \ + -falign-loops=2 -falign-jumps=2 -falign-functions=2 \ + -fstrength-reduce + OPTIMIZE = $(OPTIMIZEVM) -ffast-math + HAVE_VM_COMPILED = true + else + ifeq ($(ARCH),x86) + OPTIMIZEVM = -O3 -march=i586 -fomit-frame-pointer \ + -funroll-loops -falign-loops=2 -falign-jumps=2 \ + -falign-functions=2 -fstrength-reduce + OPTIMIZE = $(OPTIMIZEVM) -ffast-math + HAVE_VM_COMPILED=true + else + ifeq ($(ARCH),ppc) + BASE_CFLAGS += -maltivec + HAVE_VM_COMPILED=true + endif + ifeq ($(ARCH),ppc64) + BASE_CFLAGS += -maltivec + HAVE_VM_COMPILED=true + endif + ifeq ($(ARCH),sparc64) + OPTIMIZE += -mtune=ultrasparc3 -mv8plus + OPTIMIZEVM += -mtune=ultrasparc3 -mv8plus + HAVE_VM_COMPILED=true + endif + ifeq ($(ARCH),alpha) + # According to http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=410555 + # -ffast-math will cause the client to die with SIGFPE on Alpha + OPTIMIZE = $(OPTIMIZEVM) + endif + endif + endif + ifeq ($(USE_CURL),1) CLIENT_CFLAGS += $(CURL_CFLAGS) USE_CURL_DLOPEN=0 @@ -681,7 +749,7 @@ ifeq ($(PLATFORM),openbsd) SHLIBCFLAGS=-fPIC SHLIBLDFLAGS=-shared $(LDFLAGS) - THREAD_LIBS=-pthread + THREAD_LIBS=-lpthread LIBS=-lm CLIENT_LIBS = @@ -691,20 +759,15 @@ ifeq ($(PLATFORM),openbsd) ifeq ($(USE_OPENAL),1) ifneq ($(USE_OPENAL_DLOPEN),1) - CLIENT_LIBS += $(THREAD_LIBS) -lossaudio -lopenal + CLIENT_LIBS += $(THREAD_LIBS) -lopenal endif endif - ifeq ($(USE_CODEC_VORBIS),1) - CLIENT_LIBS += -lvorbisfile -lvorbis -logg - endif - - ifeq ($(USE_CURL),1) + ifeq ($(USE_CURL),1) ifneq ($(USE_CURL_DLOPEN),1) CLIENT_LIBS += -lcurl endif endif - else # ifeq openbsd ############################################################################# @@ -713,10 +776,6 @@ else # ifeq openbsd ifeq ($(PLATFORM),netbsd) - ifeq ($(shell uname -m),i386) - ARCH=i386 - endif - LIBS=-lm SHLIBEXT=so SHLIBCFLAGS=-fPIC @@ -725,12 +784,11 @@ ifeq ($(PLATFORM),netbsd) BASE_CFLAGS = -Wall -fno-strict-aliasing -Wimplicit -Wstrict-prototypes -DREACTION - ifeq ($(ARCH),i386) + ifeq ($(ARCH),x86) HAVE_VM_COMPILED=true endif BUILD_CLIENT = 0 - else # ifeq netbsd ############################################################################# @@ -748,7 +806,7 @@ ifeq ($(PLATFORM),irix64) -I. -I$(ROOT)/usr/include -DREACTION CLIENT_CFLAGS += $(SDL_CFLAGS) OPTIMIZE = -O3 - + SHLIBEXT=so SHLIBCFLAGS= SHLIBLDFLAGS=-shared @@ -772,13 +830,7 @@ ifeq ($(PLATFORM),sunos) MKDIR=gmkdir COPYDIR="/usr/local/share/games/quake3" - ifneq (,$(findstring i86pc,$(shell uname -m))) - ARCH=i386 - else #default to sparc - ARCH=sparc - endif - - ifneq ($(ARCH),i386) + ifneq ($(ARCH),x86) ifneq ($(ARCH),sparc) $(error arch $(ARCH) is currently not supported) endif @@ -796,7 +848,7 @@ ifeq ($(PLATFORM),sunos) -mtune=ultrasparc3 -mv8plus -mno-faster-structs HAVE_VM_COMPILED=true else - ifeq ($(ARCH),i386) + ifeq ($(ARCH),x86) OPTIMIZEVM += -march=i586 -fomit-frame-pointer \ -falign-loops=2 -falign-jumps=2 \ -falign-functions=2 -fstrength-reduce @@ -806,7 +858,7 @@ ifeq ($(PLATFORM),sunos) CLIENT_LDFLAGS += -L/usr/X11/lib/NVIDIA -R/usr/X11/lib/NVIDIA endif endif - + OPTIMIZE = $(OPTIMIZEVM) -ffast-math SHLIBEXT=so @@ -842,6 +894,14 @@ endif #NetBSD endif #IRIX endif #SunOS +ifndef CC + CC=gcc +endif + +ifndef RANLIB + RANLIB=ranlib +endif + ifneq ($(HAVE_VM_COMPILED),true) BASE_CFLAGS += -DNO_VM_COMPILED BUILD_GAME_QVM=0 @@ -868,25 +928,13 @@ endif ifneq ($(BUILD_CLIENT),0) ifneq ($(USE_RENDERER_DLOPEN),0) TARGETS += $(B)/$(CLIENTBIN)$(FULLBINEXT) $(B)/renderer_opengl1_$(SHLIBNAME) - ifneq ($(BUILD_CLIENT_SMP),0) - TARGETS += $(B)/renderer_opengl1_smp_$(SHLIBNAME) - endif - ifneq ($(BUILD_RENDERER_REND2), 0) - TARGETS += $(B)/renderer_rend2_$(SHLIBNAME) - ifneq ($(BUILD_CLIENT_SMP),0) - TARGETS += $(B)/renderer_rend2_smp_$(SHLIBNAME) - endif + ifneq ($(BUILD_RENDERER_OPENGL2), 0) + TARGETS += $(B)/renderer_opengl2_$(SHLIBNAME) endif else TARGETS += $(B)/$(CLIENTBIN)$(FULLBINEXT) - ifneq ($(BUILD_RENDERER_REND2), 0) - TARGETS += $(B)/$(CLIENTBIN)_rend2$(FULLBINEXT) - endif - ifneq ($(BUILD_CLIENT_SMP),0) - TARGETS += $(B)/$(CLIENTBIN)-smp$(FULLBINEXT) - ifneq ($(BUILD_RENDERER_REND2), 0) - TARGETS += $(B)/$(CLIENTBIN)_rend2-smp$(FULLBINEXT) - endif + ifneq ($(BUILD_RENDERER_OPENGL2), 0) + TARGETS += $(B)/$(CLIENTBIN)_opengl2$(FULLBINEXT) endif endif endif @@ -894,32 +942,30 @@ endif ifneq ($(BUILD_GAME_SO),0) ifneq ($(BUILD_BASEGAME),0) TARGETS += \ - $(B)/$(BASEGAME)/cgame$(SHLIBNAME) \ - $(B)/$(BASEGAME)/qagame$(SHLIBNAME) \ - $(B)/$(BASEGAME)/ui$(SHLIBNAME) + $(B)/$(BASEGAME)/cgame$(SHLIBNAME) \ + $(B)/$(BASEGAME)/qagame$(SHLIBNAME) \ + $(B)/$(BASEGAME)/ui$(SHLIBNAME) endif ifneq ($(BUILD_MISSIONPACK),0) TARGETS += \ - $(B)/$(MISSIONPACK)/cgame$(SHLIBNAME) \ - $(B)/$(MISSIONPACK)/qagame$(SHLIBNAME) \ - $(B)/$(MISSIONPACK)/ui$(SHLIBNAME) + $(B)/$(MISSIONPACK)/cgame$(SHLIBNAME) \ + $(B)/$(MISSIONPACK)/qagame$(SHLIBNAME) \ + $(B)/$(MISSIONPACK)/ui$(SHLIBNAME) endif endif ifneq ($(BUILD_GAME_QVM),0) - ifneq ($(CROSS_COMPILING),1) - ifneq ($(BUILD_BASEGAME),0) - TARGETS += \ + ifneq ($(BUILD_BASEGAME),0) + TARGETS += \ $(B)/$(BASEGAME)/vm/cgame.qvm \ $(B)/$(BASEGAME)/vm/qagame.qvm \ $(B)/$(BASEGAME)/vm/ui.qvm - endif - ifneq ($(BUILD_MISSIONPACK),0) - TARGETS += \ - $(B)/$(MISSIONPACK)/vm/qagame.qvm \ + endif + ifneq ($(BUILD_MISSIONPACK),0) + TARGETS += \ $(B)/$(MISSIONPACK)/vm/cgame.qvm \ + $(B)/$(MISSIONPACK)/vm/qagame.qvm \ $(B)/$(MISSIONPACK)/vm/ui.qvm - endif endif endif @@ -939,6 +985,30 @@ endif ifeq ($(USE_CODEC_VORBIS),1) CLIENT_CFLAGS += -DUSE_CODEC_VORBIS + CLIENT_LIBS += -lvorbisfile -lvorbis + NEED_OGG=1 +endif + +ifeq ($(USE_CODEC_OPUS),1) + CLIENT_CFLAGS += -DUSE_CODEC_OPUS + ifeq ($(USE_INTERNAL_OPUS),1) + CLIENT_CFLAGS += -DOPUS_BUILD -DHAVE_LRINTF -DFLOATING_POINT -DUSE_ALLOCA \ + -I$(OPUSDIR)/include -I$(OPUSDIR)/celt -I$(OPUSDIR)/silk \ + -I$(OPUSDIR)/silk/float + + CLIENT_CFLAGS += -I$(OPUSFILEDIR)/include + else + CLIENT_LIBS += -lopusfile -lopus + endif + NEED_OGG=1 +endif + +ifeq ($(NEED_OGG),1) + ifeq ($(USE_INTERNAL_OGG),1) + CLIENT_CFLAGS += -I$(OGGDIR)/include + else + CLIENT_LIBS += -logg + endif endif ifeq ($(USE_RENDERER_DLOPEN),1) @@ -1037,11 +1107,6 @@ $(Q)cat $< | sed 's/^/\"/;s/$$/\\n\"/' >> $@ $(Q)echo ";" >> $@ endef -define DO_SMP_CC -$(echo_cmd) "SMP_CC $<" -$(Q)$(CC) $(SHLIBCFLAGS) $(CFLAGS) $(CLIENT_CFLAGS) $(OPTIMIZE) -DSMP -o $@ -c $< -endef - define DO_BOT_CC $(echo_cmd) "BOT_CC $<" $(Q)$(CC) $(NOTSHLIBCFLAGS) $(CFLAGS) $(BOTCFLAGS) $(OPTIMIZE) -DBOTLIB -o $@ -c $< @@ -1132,76 +1197,88 @@ release: OPTIMIZE="-DNDEBUG $(OPTIMIZE)" OPTIMIZEVM="-DNDEBUG $(OPTIMIZEVM)" \ CLIENT_CFLAGS="$(CLIENT_CFLAGS)" SERVER_CFLAGS="$(SERVER_CFLAGS)" V=$(V) +ifneq ($(call bin_path, tput),) + TERM_COLUMNS=$(shell echo $$((`tput cols`-4))) +else + TERM_COLUMNS=76 +endif + +NAKED_TARGETS=$(shell echo $(TARGETS) | sed -e "s!$(B)/!!g") + +print_list=@for i in $(1); \ + do \ + echo " $$i"; \ + done + +ifneq ($(call bin_path, fmt),) + print_wrapped=@echo $(1) | fmt -w $(TERM_COLUMNS) | sed -e "s/^\(.*\)$$/ \1/" +else + print_wrapped=$(print_list) +endif + # Create the build directories, check libraries and print out # an informational message, then start building targets: makedirs @echo "" - @echo "Building $(CLIENTBIN) in $(B):" + @echo "Building in $(B):" @echo " PLATFORM: $(PLATFORM)" @echo " ARCH: $(ARCH)" @echo " VERSION: $(VERSION)" @echo " COMPILE_PLATFORM: $(COMPILE_PLATFORM)" @echo " COMPILE_ARCH: $(COMPILE_ARCH)" @echo " CC: $(CC)" +ifeq ($(PLATFORM),mingw32) + @echo " WINDRES: $(WINDRES)" +endif @echo "" @echo " CFLAGS:" - -@for i in $(CFLAGS); \ - do \ - echo " $$i"; \ - done - -@for i in $(OPTIMIZE); \ - do \ - echo " $$i"; \ - done + $(call print_wrapped, $(CFLAGS) $(OPTIMIZE)) @echo "" @echo " CLIENT_CFLAGS:" - -@for i in $(CLIENT_CFLAGS); \ - do \ - echo " $$i"; \ - done + $(call print_wrapped, $(CLIENT_CFLAGS)) @echo "" @echo " SERVER_CFLAGS:" - -@for i in $(SERVER_CFLAGS); \ - do \ - echo " $$i"; \ - done + $(call print_wrapped, $(SERVER_CFLAGS)) @echo "" @echo " LDFLAGS:" - -@for i in $(LDFLAGS); \ - do \ - echo " $$i"; \ - done + $(call print_wrapped, $(LDFLAGS)) @echo "" @echo " LIBS:" - -@for i in $(LIBS); \ - do \ - echo " $$i"; \ - done + $(call print_wrapped, $(LIBS)) @echo "" @echo " CLIENT_LIBS:" - -@for i in $(CLIENT_LIBS); \ - do \ - echo " $$i"; \ - done + $(call print_wrapped, $(CLIENT_LIBS)) @echo "" @echo " Output:" - -@for i in $(TARGETS); \ - do \ - echo " $$i"; \ - done + $(call print_list, $(NAKED_TARGETS)) @echo "" ifneq ($(TARGETS),) - @$(MAKE) $(TARGETS) V=$(V) + ifndef DEBUG_MAKEFILE + @$(MAKE) $(TARGETS) $(B).zip V=$(V) + endif +endif + +$(B).zip: $(TARGETS) +ifeq ($(PLATFORM),darwin) + ifdef ARCHIVE + @("./make-macosx-app.sh" release $(ARCH); if [ "$$?" -eq 0 ] && [ -d "$(B)/ioquake3.app" ]; then rm -f $@; cd $(B) && zip --symlinks -r9 ../../$@ `find "ioquake3.app" -print | sed -e "s!$(B)/!!g"`; else rm -f $@; cd $(B) && zip -r9 ../../$@ $(NAKED_TARGETS); fi) + endif +endif +ifneq ($(PLATFORM),darwin) + ifdef ARCHIVE + @rm -f $@ + @(cd $(B) && zip -r9 ../../$@ $(NAKED_TARGETS)) + endif endif makedirs: @if [ ! -d $(BUILD_DIR) ];then $(MKDIR) $(BUILD_DIR);fi @if [ ! -d $(B) ];then $(MKDIR) $(B);fi @if [ ! -d $(B)/client ];then $(MKDIR) $(B)/client;fi - @if [ ! -d $(B)/renderer ];then $(MKDIR) $(B)/renderer;fi - @if [ ! -d $(B)/rend2 ];then $(MKDIR) $(B)/rend2;fi - @if [ ! -d $(B)/rend2/glsl ];then $(MKDIR) $(B)/rend2/glsl;fi - @if [ ! -d $(B)/renderersmp ];then $(MKDIR) $(B)/renderersmp;fi + @if [ ! -d $(B)/client/opus ];then $(MKDIR) $(B)/client/opus;fi + @if [ ! -d $(B)/renderergl1 ];then $(MKDIR) $(B)/renderergl1;fi + @if [ ! -d $(B)/renderergl2 ];then $(MKDIR) $(B)/renderergl2;fi + @if [ ! -d $(B)/renderergl2/glsl ];then $(MKDIR) $(B)/renderergl2/glsl;fi @if [ ! -d $(B)/ded ];then $(MKDIR) $(B)/ded;fi @if [ ! -d $(B)/$(BASEGAME) ];then $(MKDIR) $(B)/$(BASEGAME);fi @if [ ! -d $(B)/$(BASEGAME)/cgame ];then $(MKDIR) $(B)/$(BASEGAME)/cgame;fi @@ -1226,6 +1303,11 @@ makedirs: # QVM BUILD TOOLS ############################################################################# +ifndef TOOLS_CC + # A compiler which probably produces native binaries + TOOLS_CC = gcc +endif + TOOLS_OPTIMIZE = -g -Wall -fno-strict-aliasing TOOLS_CFLAGS += $(TOOLS_OPTIMIZE) \ -DTEMPDIR=\"$(TEMPDIR)\" -DSYSTEM=\"\" \ @@ -1235,36 +1317,36 @@ TOOLS_LIBS = TOOLS_LDFLAGS = ifeq ($(GENERATE_DEPENDENCIES),1) - TOOLS_CFLAGS += -MMD + TOOLS_CFLAGS += -MMD endif define DO_TOOLS_CC $(echo_cmd) "TOOLS_CC $<" -$(Q)$(CC) $(TOOLS_CFLAGS) -o $@ -c $< +$(Q)$(TOOLS_CC) $(TOOLS_CFLAGS) -o $@ -c $< endef define DO_TOOLS_CC_DAGCHECK $(echo_cmd) "TOOLS_CC_DAGCHECK $<" -$(Q)$(CC) $(TOOLS_CFLAGS) -Wno-unused -o $@ -c $< +$(Q)$(TOOLS_CC) $(TOOLS_CFLAGS) -Wno-unused -o $@ -c $< endef -LBURG = $(B)/tools/lburg/lburg$(BINEXT) +LBURG = $(B)/tools/lburg/lburg$(TOOLS_BINEXT) DAGCHECK_C = $(B)/tools/rcc/dagcheck.c -Q3RCC = $(B)/tools/q3rcc$(BINEXT) -Q3CPP = $(B)/tools/q3cpp$(BINEXT) -Q3LCC = $(B)/tools/q3lcc$(BINEXT) -Q3ASM = $(B)/tools/q3asm$(BINEXT) +Q3RCC = $(B)/tools/q3rcc$(TOOLS_BINEXT) +Q3CPP = $(B)/tools/q3cpp$(TOOLS_BINEXT) +Q3LCC = $(B)/tools/q3lcc$(TOOLS_BINEXT) +Q3ASM = $(B)/tools/q3asm$(TOOLS_BINEXT) LBURGOBJ= \ - $(B)/tools/lburg/lburg.o \ - $(B)/tools/lburg/gram.o + $(B)/tools/lburg/lburg.o \ + $(B)/tools/lburg/gram.o $(B)/tools/lburg/%.o: $(LBURGDIR)/%.c $(DO_TOOLS_CC) $(LBURG): $(LBURGOBJ) $(echo_cmd) "LD $@" - $(Q)$(CC) $(TOOLS_CFLAGS) $(TOOLS_LDFLAGS) -o $@ $^ $(TOOLS_LIBS) + $(Q)$(TOOLS_CC) $(TOOLS_CFLAGS) $(TOOLS_LDFLAGS) -o $@ $^ $(TOOLS_LIBS) Q3RCCOBJ = \ $(B)/tools/rcc/alloc.o \ @@ -1309,26 +1391,26 @@ $(B)/tools/rcc/%.o: $(Q3LCCSRCDIR)/%.c $(Q3RCC): $(Q3RCCOBJ) $(echo_cmd) "LD $@" - $(Q)$(CC) $(TOOLS_CFLAGS) $(TOOLS_LDFLAGS) -o $@ $^ $(TOOLS_LIBS) + $(Q)$(TOOLS_CC) $(TOOLS_CFLAGS) $(TOOLS_LDFLAGS) -o $@ $^ $(TOOLS_LIBS) Q3CPPOBJ = \ - $(B)/tools/cpp/cpp.o \ - $(B)/tools/cpp/lex.o \ - $(B)/tools/cpp/nlist.o \ - $(B)/tools/cpp/tokens.o \ - $(B)/tools/cpp/macro.o \ - $(B)/tools/cpp/eval.o \ - $(B)/tools/cpp/include.o \ - $(B)/tools/cpp/hideset.o \ - $(B)/tools/cpp/getopt.o \ - $(B)/tools/cpp/unix.o + $(B)/tools/cpp/cpp.o \ + $(B)/tools/cpp/lex.o \ + $(B)/tools/cpp/nlist.o \ + $(B)/tools/cpp/tokens.o \ + $(B)/tools/cpp/macro.o \ + $(B)/tools/cpp/eval.o \ + $(B)/tools/cpp/include.o \ + $(B)/tools/cpp/hideset.o \ + $(B)/tools/cpp/getopt.o \ + $(B)/tools/cpp/unix.o $(B)/tools/cpp/%.o: $(Q3CPPDIR)/%.c $(DO_TOOLS_CC) $(Q3CPP): $(Q3CPPOBJ) $(echo_cmd) "LD $@" - $(Q)$(CC) $(TOOLS_CFLAGS) $(TOOLS_LDFLAGS) -o $@ $^ $(TOOLS_LIBS) + $(Q)$(TOOLS_CC) $(TOOLS_CFLAGS) $(TOOLS_LDFLAGS) -o $@ $^ $(TOOLS_LIBS) Q3LCCOBJ = \ $(B)/tools/etc/lcc.o \ @@ -1339,7 +1421,7 @@ $(B)/tools/etc/%.o: $(Q3LCCETCDIR)/%.c $(Q3LCC): $(Q3LCCOBJ) $(Q3RCC) $(Q3CPP) $(echo_cmd) "LD $@" - $(Q)$(CC) $(TOOLS_CFLAGS) $(TOOLS_LDFLAGS) -o $@ $(Q3LCCOBJ) $(TOOLS_LIBS) + $(Q)$(TOOLS_CC) $(TOOLS_CFLAGS) $(TOOLS_LDFLAGS) -o $@ $(Q3LCCOBJ) $(TOOLS_LIBS) define DO_Q3LCC $(echo_cmd) "Q3LCC $<" @@ -1391,7 +1473,7 @@ $(B)/tools/asm/%.o: $(Q3ASMDIR)/%.c $(Q3ASM): $(Q3ASMOBJ) $(echo_cmd) "LD $@" - $(Q)$(CC) $(TOOLS_CFLAGS) $(TOOLS_LDFLAGS) -o $@ $^ $(TOOLS_LIBS) + $(Q)$(TOOLS_CC) $(TOOLS_CFLAGS) $(TOOLS_LDFLAGS) -o $@ $^ $(TOOLS_LIBS) ############################################################################# @@ -1438,6 +1520,7 @@ Q3OBJ = \ $(B)/client/snd_codec.o \ $(B)/client/snd_codec_wav.o \ $(B)/client/snd_codec_ogg.o \ + $(B)/client/snd_codec_opus.o \ \ $(B)/client/qal.o \ $(B)/client/snd_openal.o \ @@ -1500,191 +1583,180 @@ Q3OBJ = \ ifeq ($(PLATFORM),mingw32) Q3OBJ += \ - $(B)/client/con_passive.o + $(B)/client/con_passive.o else Q3OBJ += \ - $(B)/client/con_tty.o + $(B)/client/con_tty.o endif Q3R2OBJ = \ - $(B)/rend2/tr_animation.o \ - $(B)/rend2/tr_backend.o \ - $(B)/rend2/tr_bsp.o \ - $(B)/rend2/tr_cmds.o \ - $(B)/rend2/tr_curve.o \ - $(B)/rend2/tr_extramath.o \ - $(B)/rend2/tr_extensions.o \ - $(B)/rend2/tr_fbo.o \ - $(B)/rend2/tr_flares.o \ - $(B)/rend2/tr_font.o \ - $(B)/rend2/tr_glsl.o \ - $(B)/rend2/tr_image.o \ - $(B)/rend2/tr_image_png.o \ - $(B)/rend2/tr_image_jpg.o \ - $(B)/rend2/tr_image_bmp.o \ - $(B)/rend2/tr_image_tga.o \ - $(B)/rend2/tr_image_pcx.o \ - $(B)/rend2/tr_init.o \ - $(B)/rend2/tr_light.o \ - $(B)/rend2/tr_main.o \ - $(B)/rend2/tr_marks.o \ - $(B)/rend2/tr_mesh.o \ - $(B)/rend2/tr_model.o \ - $(B)/rend2/tr_model_iqm.o \ - $(B)/rend2/tr_noise.o \ - $(B)/rend2/tr_postprocess.o \ - $(B)/rend2/tr_scene.o \ - $(B)/rend2/tr_shade.o \ - $(B)/rend2/tr_shade_calc.o \ - $(B)/rend2/tr_shader.o \ - $(B)/rend2/tr_shadows.o \ - $(B)/rend2/tr_sky.o \ - $(B)/rend2/tr_surface.o \ - $(B)/rend2/tr_vbo.o \ - $(B)/rend2/tr_world.o \ + $(B)/renderergl2/tr_animation.o \ + $(B)/renderergl2/tr_backend.o \ + $(B)/renderergl2/tr_bsp.o \ + $(B)/renderergl2/tr_cmds.o \ + $(B)/renderergl2/tr_curve.o \ + $(B)/renderergl2/tr_extramath.o \ + $(B)/renderergl2/tr_extensions.o \ + $(B)/renderergl2/tr_fbo.o \ + $(B)/renderergl2/tr_flares.o \ + $(B)/renderergl2/tr_font.o \ + $(B)/renderergl2/tr_glsl.o \ + $(B)/renderergl2/tr_image.o \ + $(B)/renderergl2/tr_image_png.o \ + $(B)/renderergl2/tr_image_jpg.o \ + $(B)/renderergl2/tr_image_bmp.o \ + $(B)/renderergl2/tr_image_tga.o \ + $(B)/renderergl2/tr_image_pcx.o \ + $(B)/renderergl2/tr_init.o \ + $(B)/renderergl2/tr_light.o \ + $(B)/renderergl2/tr_main.o \ + $(B)/renderergl2/tr_marks.o \ + $(B)/renderergl2/tr_mesh.o \ + $(B)/renderergl2/tr_model.o \ + $(B)/renderergl2/tr_model_iqm.o \ + $(B)/renderergl2/tr_noise.o \ + $(B)/renderergl2/tr_postprocess.o \ + $(B)/renderergl2/tr_scene.o \ + $(B)/renderergl2/tr_shade.o \ + $(B)/renderergl2/tr_shade_calc.o \ + $(B)/renderergl2/tr_shader.o \ + $(B)/renderergl2/tr_shadows.o \ + $(B)/renderergl2/tr_sky.o \ + $(B)/renderergl2/tr_surface.o \ + $(B)/renderergl2/tr_vbo.o \ + $(B)/renderergl2/tr_world.o \ \ - $(B)/renderer/sdl_gamma.o - + $(B)/renderergl1/sdl_gamma.o \ + $(B)/renderergl1/sdl_glimp.o + Q3R2STRINGOBJ = \ - $(B)/rend2/glsl/bokeh_fp.o \ - $(B)/rend2/glsl/bokeh_vp.o \ - $(B)/rend2/glsl/calclevels4x_fp.o \ - $(B)/rend2/glsl/calclevels4x_vp.o \ - $(B)/rend2/glsl/depthblur_fp.o \ - $(B)/rend2/glsl/depthblur_vp.o \ - $(B)/rend2/glsl/dlight_fp.o \ - $(B)/rend2/glsl/dlight_vp.o \ - $(B)/rend2/glsl/down4x_fp.o \ - $(B)/rend2/glsl/down4x_vp.o \ - $(B)/rend2/glsl/fogpass_fp.o \ - $(B)/rend2/glsl/fogpass_vp.o \ - $(B)/rend2/glsl/generic_fp.o \ - $(B)/rend2/glsl/generic_vp.o \ - $(B)/rend2/glsl/lightall_fp.o \ - $(B)/rend2/glsl/lightall_vp.o \ - $(B)/rend2/glsl/pshadow_fp.o \ - $(B)/rend2/glsl/pshadow_vp.o \ - $(B)/rend2/glsl/shadowfill_fp.o \ - $(B)/rend2/glsl/shadowfill_vp.o \ - $(B)/rend2/glsl/shadowmask_fp.o \ - $(B)/rend2/glsl/shadowmask_vp.o \ - $(B)/rend2/glsl/ssao_fp.o \ - $(B)/rend2/glsl/ssao_vp.o \ - $(B)/rend2/glsl/texturecolor_fp.o \ - $(B)/rend2/glsl/texturecolor_vp.o \ - $(B)/rend2/glsl/tonemap_fp.o \ - $(B)/rend2/glsl/tonemap_vp.o + $(B)/renderergl2/glsl/bokeh_fp.o \ + $(B)/renderergl2/glsl/bokeh_vp.o \ + $(B)/renderergl2/glsl/calclevels4x_fp.o \ + $(B)/renderergl2/glsl/calclevels4x_vp.o \ + $(B)/renderergl2/glsl/depthblur_fp.o \ + $(B)/renderergl2/glsl/depthblur_vp.o \ + $(B)/renderergl2/glsl/dlight_fp.o \ + $(B)/renderergl2/glsl/dlight_vp.o \ + $(B)/renderergl2/glsl/down4x_fp.o \ + $(B)/renderergl2/glsl/down4x_vp.o \ + $(B)/renderergl2/glsl/fogpass_fp.o \ + $(B)/renderergl2/glsl/fogpass_vp.o \ + $(B)/renderergl2/glsl/generic_fp.o \ + $(B)/renderergl2/glsl/generic_vp.o \ + $(B)/renderergl2/glsl/lightall_fp.o \ + $(B)/renderergl2/glsl/lightall_vp.o \ + $(B)/renderergl2/glsl/pshadow_fp.o \ + $(B)/renderergl2/glsl/pshadow_vp.o \ + $(B)/renderergl2/glsl/shadowfill_fp.o \ + $(B)/renderergl2/glsl/shadowfill_vp.o \ + $(B)/renderergl2/glsl/shadowmask_fp.o \ + $(B)/renderergl2/glsl/shadowmask_vp.o \ + $(B)/renderergl2/glsl/ssao_fp.o \ + $(B)/renderergl2/glsl/ssao_vp.o \ + $(B)/renderergl2/glsl/texturecolor_fp.o \ + $(B)/renderergl2/glsl/texturecolor_vp.o \ + $(B)/renderergl2/glsl/tonemap_fp.o \ + $(B)/renderergl2/glsl/tonemap_vp.o Q3ROBJ = \ - $(B)/renderer/tr_animation.o \ - $(B)/renderer/tr_backend.o \ - $(B)/renderer/tr_bsp.o \ - $(B)/renderer/tr_cmds.o \ - $(B)/renderer/tr_curve.o \ - $(B)/renderer/tr_flares.o \ - $(B)/renderer/tr_font.o \ - $(B)/renderer/tr_image.o \ - $(B)/renderer/tr_image_png.o \ - $(B)/renderer/tr_image_jpg.o \ - $(B)/renderer/tr_image_bmp.o \ - $(B)/renderer/tr_image_tga.o \ - $(B)/renderer/tr_image_pcx.o \ - $(B)/renderer/tr_init.o \ - $(B)/renderer/tr_light.o \ - $(B)/renderer/tr_main.o \ - $(B)/renderer/tr_marks.o \ - $(B)/renderer/tr_mesh.o \ - $(B)/renderer/tr_model.o \ - $(B)/renderer/tr_model_iqm.o \ - $(B)/renderer/tr_noise.o \ - $(B)/renderer/tr_scene.o \ - $(B)/renderer/tr_shade.o \ - $(B)/renderer/tr_shade_calc.o \ - $(B)/renderer/tr_shader.o \ - $(B)/renderer/tr_shadows.o \ - $(B)/renderer/tr_sky.o \ - $(B)/renderer/tr_surface.o \ - $(B)/renderer/tr_world.o \ + $(B)/renderergl1/tr_animation.o \ + $(B)/renderergl1/tr_backend.o \ + $(B)/renderergl1/tr_bsp.o \ + $(B)/renderergl1/tr_cmds.o \ + $(B)/renderergl1/tr_curve.o \ + $(B)/renderergl1/tr_flares.o \ + $(B)/renderergl1/tr_font.o \ + $(B)/renderergl1/tr_image.o \ + $(B)/renderergl1/tr_image_png.o \ + $(B)/renderergl1/tr_image_jpg.o \ + $(B)/renderergl1/tr_image_bmp.o \ + $(B)/renderergl1/tr_image_tga.o \ + $(B)/renderergl1/tr_image_pcx.o \ + $(B)/renderergl1/tr_init.o \ + $(B)/renderergl1/tr_light.o \ + $(B)/renderergl1/tr_main.o \ + $(B)/renderergl1/tr_marks.o \ + $(B)/renderergl1/tr_mesh.o \ + $(B)/renderergl1/tr_model.o \ + $(B)/renderergl1/tr_model_iqm.o \ + $(B)/renderergl1/tr_noise.o \ + $(B)/renderergl1/tr_scene.o \ + $(B)/renderergl1/tr_shade.o \ + $(B)/renderergl1/tr_shade_calc.o \ + $(B)/renderergl1/tr_shader.o \ + $(B)/renderergl1/tr_shadows.o \ + $(B)/renderergl1/tr_sky.o \ + $(B)/renderergl1/tr_surface.o \ + $(B)/renderergl1/tr_world.o \ \ - $(B)/renderer/sdl_gamma.o - -Q3RPOBJ_UP = \ - $(B)/renderer/sdl_glimp.o - -Q3RPOBJ_SMP = \ - $(B)/renderersmp/sdl_glimp.o + $(B)/renderergl1/sdl_gamma.o \ + $(B)/renderergl1/sdl_glimp.o ifneq ($(USE_RENDERER_DLOPEN), 0) Q3ROBJ += \ - $(B)/renderer/q_shared.o \ - $(B)/renderer/puff.o \ - $(B)/renderer/q_math.o \ - $(B)/renderer/tr_subs.o + $(B)/renderergl1/q_shared.o \ + $(B)/renderergl1/puff.o \ + $(B)/renderergl1/q_math.o \ + $(B)/renderergl1/tr_subs.o Q3R2OBJ += \ - $(B)/renderer/q_shared.o \ - $(B)/renderer/puff.o \ - $(B)/renderer/q_math.o \ - $(B)/renderer/tr_subs.o + $(B)/renderergl1/q_shared.o \ + $(B)/renderergl1/puff.o \ + $(B)/renderergl1/q_math.o \ + $(B)/renderergl1/tr_subs.o endif ifneq ($(USE_INTERNAL_JPEG),0) JPGOBJ = \ - $(B)/renderer/jaricom.o \ - $(B)/renderer/jcapimin.o \ - $(B)/renderer/jcapistd.o \ - $(B)/renderer/jcarith.o \ - $(B)/renderer/jccoefct.o \ - $(B)/renderer/jccolor.o \ - $(B)/renderer/jcdctmgr.o \ - $(B)/renderer/jchuff.o \ - $(B)/renderer/jcinit.o \ - $(B)/renderer/jcmainct.o \ - $(B)/renderer/jcmarker.o \ - $(B)/renderer/jcmaster.o \ - $(B)/renderer/jcomapi.o \ - $(B)/renderer/jcparam.o \ - $(B)/renderer/jcprepct.o \ - $(B)/renderer/jcsample.o \ - $(B)/renderer/jctrans.o \ - $(B)/renderer/jdapimin.o \ - $(B)/renderer/jdapistd.o \ - $(B)/renderer/jdarith.o \ - $(B)/renderer/jdatadst.o \ - $(B)/renderer/jdatasrc.o \ - $(B)/renderer/jdcoefct.o \ - $(B)/renderer/jdcolor.o \ - $(B)/renderer/jddctmgr.o \ - $(B)/renderer/jdhuff.o \ - $(B)/renderer/jdinput.o \ - $(B)/renderer/jdmainct.o \ - $(B)/renderer/jdmarker.o \ - $(B)/renderer/jdmaster.o \ - $(B)/renderer/jdmerge.o \ - $(B)/renderer/jdpostct.o \ - $(B)/renderer/jdsample.o \ - $(B)/renderer/jdtrans.o \ - $(B)/renderer/jerror.o \ - $(B)/renderer/jfdctflt.o \ - $(B)/renderer/jfdctfst.o \ - $(B)/renderer/jfdctint.o \ - $(B)/renderer/jidctflt.o \ - $(B)/renderer/jidctfst.o \ - $(B)/renderer/jidctint.o \ - $(B)/renderer/jmemmgr.o \ - $(B)/renderer/jmemnobs.o \ - $(B)/renderer/jquant1.o \ - $(B)/renderer/jquant2.o \ - $(B)/renderer/jutils.o + $(B)/renderergl1/jaricom.o \ + $(B)/renderergl1/jcapimin.o \ + $(B)/renderergl1/jcapistd.o \ + $(B)/renderergl1/jcarith.o \ + $(B)/renderergl1/jccoefct.o \ + $(B)/renderergl1/jccolor.o \ + $(B)/renderergl1/jcdctmgr.o \ + $(B)/renderergl1/jchuff.o \ + $(B)/renderergl1/jcinit.o \ + $(B)/renderergl1/jcmainct.o \ + $(B)/renderergl1/jcmarker.o \ + $(B)/renderergl1/jcmaster.o \ + $(B)/renderergl1/jcomapi.o \ + $(B)/renderergl1/jcparam.o \ + $(B)/renderergl1/jcprepct.o \ + $(B)/renderergl1/jcsample.o \ + $(B)/renderergl1/jctrans.o \ + $(B)/renderergl1/jdapimin.o \ + $(B)/renderergl1/jdapistd.o \ + $(B)/renderergl1/jdarith.o \ + $(B)/renderergl1/jdatadst.o \ + $(B)/renderergl1/jdatasrc.o \ + $(B)/renderergl1/jdcoefct.o \ + $(B)/renderergl1/jdcolor.o \ + $(B)/renderergl1/jddctmgr.o \ + $(B)/renderergl1/jdhuff.o \ + $(B)/renderergl1/jdinput.o \ + $(B)/renderergl1/jdmainct.o \ + $(B)/renderergl1/jdmarker.o \ + $(B)/renderergl1/jdmaster.o \ + $(B)/renderergl1/jdmerge.o \ + $(B)/renderergl1/jdpostct.o \ + $(B)/renderergl1/jdsample.o \ + $(B)/renderergl1/jdtrans.o \ + $(B)/renderergl1/jerror.o \ + $(B)/renderergl1/jfdctflt.o \ + $(B)/renderergl1/jfdctfst.o \ + $(B)/renderergl1/jfdctint.o \ + $(B)/renderergl1/jidctflt.o \ + $(B)/renderergl1/jidctfst.o \ + $(B)/renderergl1/jidctint.o \ + $(B)/renderergl1/jmemmgr.o \ + $(B)/renderergl1/jmemnobs.o \ + $(B)/renderergl1/jquant1.o \ + $(B)/renderergl1/jquant2.o \ + $(B)/renderergl1/jutils.o endif -ifeq ($(ARCH),i386) - Q3OBJ += \ - $(B)/client/snd_mixa.o \ - $(B)/client/matha.o \ - $(B)/client/snapvector.o \ - $(B)/client/ftola.o -endif ifeq ($(ARCH),x86) Q3OBJ += \ $(B)/client/snd_mixa.o \ @@ -1697,16 +1769,6 @@ ifeq ($(ARCH),x86_64) $(B)/client/snapvector.o \ $(B)/client/ftola.o endif -ifeq ($(ARCH),amd64) - Q3OBJ += \ - $(B)/client/snapvector.o \ - $(B)/client/ftola.o -endif -ifeq ($(ARCH),x64) - Q3OBJ += \ - $(B)/client/snapvector.o \ - $(B)/client/ftola.o -endif ifeq ($(USE_VOIP),1) ifeq ($(USE_INTERNAL_SPEEX),1) @@ -1754,6 +1816,157 @@ Q3OBJ += \ endif endif +ifeq ($(USE_CODEC_OPUS),1) +ifeq ($(USE_INTERNAL_OPUS),1) +Q3OBJ += \ + $(B)/client/opus/opus.o \ + $(B)/client/opus/opus_decoder.o \ + $(B)/client/opus/opus_encoder.o \ + $(B)/client/opus/opus_multistream.o \ + $(B)/client/opus/repacketizer.o \ + \ + $(B)/client/opus/bands.o \ + $(B)/client/opus/celt.o \ + $(B)/client/opus/cwrs.o \ + $(B)/client/opus/entcode.o \ + $(B)/client/opus/entdec.o \ + $(B)/client/opus/entenc.o \ + $(B)/client/opus/kiss_fft.o \ + $(B)/client/opus/laplace.o \ + $(B)/client/opus/mathops.o \ + $(B)/client/opus/mdct.o \ + $(B)/client/opus/modes.o \ + $(B)/client/opus/pitch.o \ + $(B)/client/opus/celt_lpc.o \ + $(B)/client/opus/quant_bands.o \ + $(B)/client/opus/rate.o \ + $(B)/client/opus/vq.o \ + \ + $(B)/client/opus/CNG.o \ + $(B)/client/opus/code_signs.o \ + $(B)/client/opus/init_decoder.o \ + $(B)/client/opus/decode_core.o \ + $(B)/client/opus/decode_frame.o \ + $(B)/client/opus/decode_parameters.o \ + $(B)/client/opus/decode_indices.o \ + $(B)/client/opus/decode_pulses.o \ + $(B)/client/opus/decoder_set_fs.o \ + $(B)/client/opus/dec_API.o \ + $(B)/client/opus/enc_API.o \ + $(B)/client/opus/encode_indices.o \ + $(B)/client/opus/encode_pulses.o \ + $(B)/client/opus/gain_quant.o \ + $(B)/client/opus/interpolate.o \ + $(B)/client/opus/LP_variable_cutoff.o \ + $(B)/client/opus/NLSF_decode.o \ + $(B)/client/opus/NSQ.o \ + $(B)/client/opus/NSQ_del_dec.o \ + $(B)/client/opus/PLC.o \ + $(B)/client/opus/shell_coder.o \ + $(B)/client/opus/tables_gain.o \ + $(B)/client/opus/tables_LTP.o \ + $(B)/client/opus/tables_NLSF_CB_NB_MB.o \ + $(B)/client/opus/tables_NLSF_CB_WB.o \ + $(B)/client/opus/tables_other.o \ + $(B)/client/opus/tables_pitch_lag.o \ + $(B)/client/opus/tables_pulses_per_block.o \ + $(B)/client/opus/VAD.o \ + $(B)/client/opus/control_audio_bandwidth.o \ + $(B)/client/opus/quant_LTP_gains.o \ + $(B)/client/opus/VQ_WMat_EC.o \ + $(B)/client/opus/HP_variable_cutoff.o \ + $(B)/client/opus/NLSF_encode.o \ + $(B)/client/opus/NLSF_VQ.o \ + $(B)/client/opus/NLSF_unpack.o \ + $(B)/client/opus/NLSF_del_dec_quant.o \ + $(B)/client/opus/process_NLSFs.o \ + $(B)/client/opus/stereo_LR_to_MS.o \ + $(B)/client/opus/stereo_MS_to_LR.o \ + $(B)/client/opus/check_control_input.o \ + $(B)/client/opus/control_SNR.o \ + $(B)/client/opus/init_encoder.o \ + $(B)/client/opus/control_codec.o \ + $(B)/client/opus/A2NLSF.o \ + $(B)/client/opus/ana_filt_bank_1.o \ + $(B)/client/opus/biquad_alt.o \ + $(B)/client/opus/bwexpander_32.o \ + $(B)/client/opus/bwexpander.o \ + $(B)/client/opus/debug.o \ + $(B)/client/opus/decode_pitch.o \ + $(B)/client/opus/inner_prod_aligned.o \ + $(B)/client/opus/lin2log.o \ + $(B)/client/opus/log2lin.o \ + $(B)/client/opus/LPC_analysis_filter.o \ + $(B)/client/opus/LPC_inv_pred_gain.o \ + $(B)/client/opus/table_LSF_cos.o \ + $(B)/client/opus/NLSF2A.o \ + $(B)/client/opus/NLSF_stabilize.o \ + $(B)/client/opus/NLSF_VQ_weights_laroia.o \ + $(B)/client/opus/pitch_est_tables.o \ + $(B)/client/opus/resampler.o \ + $(B)/client/opus/resampler_down2_3.o \ + $(B)/client/opus/resampler_down2.o \ + $(B)/client/opus/resampler_private_AR2.o \ + $(B)/client/opus/resampler_private_down_FIR.o \ + $(B)/client/opus/resampler_private_IIR_FIR.o \ + $(B)/client/opus/resampler_private_up2_HQ.o \ + $(B)/client/opus/resampler_rom.o \ + $(B)/client/opus/sigm_Q15.o \ + $(B)/client/opus/sort.o \ + $(B)/client/opus/sum_sqr_shift.o \ + $(B)/client/opus/stereo_decode_pred.o \ + $(B)/client/opus/stereo_encode_pred.o \ + $(B)/client/opus/stereo_find_predictor.o \ + $(B)/client/opus/stereo_quant_pred.o \ + \ + $(B)/client/opus/apply_sine_window_FLP.o \ + $(B)/client/opus/corrMatrix_FLP.o \ + $(B)/client/opus/encode_frame_FLP.o \ + $(B)/client/opus/find_LPC_FLP.o \ + $(B)/client/opus/find_LTP_FLP.o \ + $(B)/client/opus/find_pitch_lags_FLP.o \ + $(B)/client/opus/find_pred_coefs_FLP.o \ + $(B)/client/opus/LPC_analysis_filter_FLP.o \ + $(B)/client/opus/LTP_analysis_filter_FLP.o \ + $(B)/client/opus/LTP_scale_ctrl_FLP.o \ + $(B)/client/opus/noise_shape_analysis_FLP.o \ + $(B)/client/opus/prefilter_FLP.o \ + $(B)/client/opus/process_gains_FLP.o \ + $(B)/client/opus/regularize_correlations_FLP.o \ + $(B)/client/opus/residual_energy_FLP.o \ + $(B)/client/opus/solve_LS_FLP.o \ + $(B)/client/opus/warped_autocorrelation_FLP.o \ + $(B)/client/opus/wrappers_FLP.o \ + $(B)/client/opus/autocorrelation_FLP.o \ + $(B)/client/opus/burg_modified_FLP.o \ + $(B)/client/opus/bwexpander_FLP.o \ + $(B)/client/opus/energy_FLP.o \ + $(B)/client/opus/inner_product_FLP.o \ + $(B)/client/opus/k2a_FLP.o \ + $(B)/client/opus/levinsondurbin_FLP.o \ + $(B)/client/opus/LPC_inv_pred_gain_FLP.o \ + $(B)/client/opus/pitch_analysis_core_FLP.o \ + $(B)/client/opus/scale_copy_vector_FLP.o \ + $(B)/client/opus/scale_vector_FLP.o \ + $(B)/client/opus/schur_FLP.o \ + $(B)/client/opus/sort_FLP.o \ + \ + $(B)/client/http.o \ + $(B)/client/info.o \ + $(B)/client/internal.o \ + $(B)/client/opusfile.o \ + $(B)/client/stream.o +endif +endif + +ifeq ($(NEED_OGG),1) +ifeq ($(USE_INTERNAL_OGG),1) +Q3OBJ += \ + $(B)/client/bitwise.o \ + $(B)/client/framing.o +endif +endif + ifeq ($(USE_INTERNAL_ZLIB),1) Q3OBJ += \ $(B)/client/adler32.o \ @@ -1765,48 +1978,11 @@ Q3OBJ += \ endif ifeq ($(HAVE_VM_COMPILED),true) - ifeq ($(ARCH),i386) + ifneq ($(findstring $(ARCH),x86 x86_64),) Q3OBJ += \ $(B)/client/vm_x86.o endif - ifeq ($(ARCH),x86) - Q3OBJ += \ - $(B)/client/vm_x86.o - endif - ifeq ($(ARCH),x86_64) - ifeq ($(USE_OLD_VM64),1) - Q3OBJ += \ - $(B)/client/vm_x86_64.o \ - $(B)/client/vm_x86_64_assembler.o - else - Q3OBJ += \ - $(B)/client/vm_x86.o - endif - endif - ifeq ($(ARCH),amd64) - ifeq ($(USE_OLD_VM64),1) - Q3OBJ += \ - $(B)/client/vm_x86_64.o \ - $(B)/client/vm_x86_64_assembler.o - else - Q3OBJ += \ - $(B)/client/vm_x86.o - endif - endif - ifeq ($(ARCH),x64) - ifeq ($(USE_OLD_VM64),1) - Q3OBJ += \ - $(B)/client/vm_x86_64.o \ - $(B)/client/vm_x86_64_assembler.o - else - Q3OBJ += \ - $(B)/client/vm_x86.o - endif - endif - ifeq ($(ARCH),ppc) - Q3OBJ += $(B)/client/vm_powerpc.o $(B)/client/vm_powerpc_asm.o - endif - ifeq ($(ARCH),ppc64) + ifneq ($(findstring $(ARCH),ppc ppc64),) Q3OBJ += $(B)/client/vm_powerpc.o $(B)/client/vm_powerpc_asm.o endif ifeq ($(ARCH),sparc) @@ -1840,57 +2016,34 @@ $(B)/$(CLIENTBIN)$(FULLBINEXT): $(Q3OBJ) $(LIBSDLMAIN) -o $@ $(Q3OBJ) \ $(LIBSDLMAIN) $(CLIENT_LIBS) $(LIBS) -$(B)/renderer_opengl1_$(SHLIBNAME): $(Q3ROBJ) $(Q3RPOBJ_UP) $(JPGOBJ) +$(B)/renderer_opengl1_$(SHLIBNAME): $(Q3ROBJ) $(JPGOBJ) $(echo_cmd) "LD $@" - $(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(Q3ROBJ) $(Q3RPOBJ_UP) $(JPGOBJ) \ + $(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(Q3ROBJ) $(JPGOBJ) \ $(THREAD_LIBS) $(LIBSDLMAIN) $(RENDERER_LIBS) $(LIBS) -$(B)/renderer_opengl1_smp_$(SHLIBNAME): $(Q3ROBJ) $(Q3RPOBJ_SMP) $(JPGOBJ) +$(B)/renderer_opengl2_$(SHLIBNAME): $(Q3R2OBJ) $(Q3R2STRINGOBJ) $(JPGOBJ) $(echo_cmd) "LD $@" - $(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(Q3ROBJ) $(Q3RPOBJ_SMP) $(JPGOBJ) \ + $(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(Q3R2OBJ) $(Q3R2STRINGOBJ) $(JPGOBJ) \ $(THREAD_LIBS) $(LIBSDLMAIN) $(RENDERER_LIBS) $(LIBS) - -$(B)/renderer_rend2_$(SHLIBNAME): $(Q3R2OBJ) $(Q3R2STRINGOBJ) $(Q3RPOBJ_UP) $(JPGOBJ) - $(echo_cmd) "LD $@" - $(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(Q3R2OBJ) $(Q3R2STRINGOBJ) $(Q3RPOBJ_UP) $(JPGOBJ) \ - $(THREAD_LIBS) $(LIBSDLMAIN) $(RENDERER_LIBS) $(LIBS) - -$(B)/renderer_rend2_smp_$(SHLIBNAME): $(Q3R2OBJ) $(Q3R2STRINGOBJ) $(Q3RPOBJ_SMP) $(JPGOBJ) - $(echo_cmd) "LD $@" - $(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(Q3R2OBJ) $(Q3R2STRINGOBJ) $(Q3RPOBJ_SMP) $(JPGOBJ) \ - $(THREAD_LIBS) $(LIBSDLMAIN) $(RENDERER_LIBS) $(LIBS) - else -$(B)/$(CLIENTBIN)$(FULLBINEXT): $(Q3OBJ) $(Q3ROBJ) $(Q3RPOBJ_UP) $(JPGOBJ) $(LIBSDLMAIN) +$(B)/$(CLIENTBIN)$(FULLBINEXT): $(Q3OBJ) $(Q3ROBJ) $(JPGOBJ) $(LIBSDLMAIN) $(echo_cmd) "LD $@" $(Q)$(CC) $(CLIENT_CFLAGS) $(CFLAGS) $(CLIENT_LDFLAGS) $(LDFLAGS) \ - -o $@ $(Q3OBJ) $(Q3ROBJ) $(Q3RPOBJ_UP) $(JPGOBJ) \ + -o $@ $(Q3OBJ) $(Q3ROBJ) $(JPGOBJ) \ $(LIBSDLMAIN) $(CLIENT_LIBS) $(RENDERER_LIBS) $(LIBS) -$(B)/$(CLIENTBIN)-smp$(FULLBINEXT): $(Q3OBJ) $(Q3ROBJ) $(Q3RPOBJ_SMP) $(JPGOBJ) $(LIBSDLMAIN) - $(echo_cmd) "LD $@" - $(Q)$(CC) $(CLIENT_CFLAGS) $(CFLAGS) $(CLIENT_LDFLAGS) $(LDFLAGS) $(THREAD_LDFLAGS) \ - -o $@ $(Q3OBJ) $(Q3ROBJ) $(Q3RPOBJ_SMP) $(JPGOBJ) \ - $(THREAD_LIBS) $(LIBSDLMAIN) $(CLIENT_LIBS) $(RENDERER_LIBS) $(LIBS) - -$(B)/$(CLIENTBIN)_rend2$(FULLBINEXT): $(Q3OBJ) $(Q3R2OBJ) $(Q3R2STRINGOBJ) $(Q3RPOBJ_UP) $(JPGOBJ) $(LIBSDLMAIN) +$(B)/$(CLIENTBIN)_opengl2$(FULLBINEXT): $(Q3OBJ) $(Q3R2OBJ) $(Q3R2STRINGOBJ) $(JPGOBJ) $(LIBSDLMAIN) $(echo_cmd) "LD $@" $(Q)$(CC) $(CLIENT_CFLAGS) $(CFLAGS) $(CLIENT_LDFLAGS) $(LDFLAGS) \ - -o $@ $(Q3OBJ) $(Q3R2OBJ) $(Q3R2STRINGOBJ) $(Q3RPOBJ_UP) $(JPGOBJ) \ + -o $@ $(Q3OBJ) $(Q3R2OBJ) $(Q3R2STRINGOBJ) $(JPGOBJ) \ $(LIBSDLMAIN) $(CLIENT_LIBS) $(RENDERER_LIBS) $(LIBS) - -$(B)/$(CLIENTBIN)_rend2-smp$(FULLBINEXT): $(Q3OBJ) $(Q3R2OBJ) $(Q3R2STRINGOBJ) $(Q3RPOBJ_SMP) $(JPGOBJ) $(LIBSDLMAIN) - $(echo_cmd) "LD $@" - $(Q)$(CC) $(CLIENT_CFLAGS) $(CFLAGS) $(CLIENT_LDFLAGS) $(LDFLAGS) $(THREAD_LDFLAGS) \ - -o $@ $(Q3OBJ) $(Q3R2OBJ) $(Q3R2STRINGOBJ) $(Q3RPOBJ_SMP) $(JPGOBJ) \ - $(THREAD_LIBS) $(LIBSDLMAIN) $(CLIENT_LIBS) $(RENDERER_LIBS) $(LIBS) endif ifneq ($(strip $(LIBSDLMAIN)),) ifneq ($(strip $(LIBSDLMAINSRC)),) $(LIBSDLMAIN) : $(LIBSDLMAINSRC) cp $< $@ - ranlib $@ + $(RANLIB) $@ endif endif @@ -1970,32 +2123,16 @@ Q3DOBJ = \ $(B)/ded/con_log.o \ $(B)/ded/sys_main.o -ifeq ($(ARCH),i386) +ifeq ($(ARCH),x86) Q3DOBJ += \ $(B)/ded/matha.o \ $(B)/ded/snapvector.o \ $(B)/ded/ftola.o endif -ifeq ($(ARCH),x86) - Q3DOBJ += \ - $(B)/ded/matha.o \ - $(B)/ded/snapvector.o \ - $(B)/ded/ftola.o -endif ifeq ($(ARCH),x86_64) Q3DOBJ += \ $(B)/ded/snapvector.o \ - $(B)/ded/ftola.o -endif -ifeq ($(ARCH),amd64) - Q3DOBJ += \ - $(B)/ded/snapvector.o \ - $(B)/ded/ftola.o -endif -ifeq ($(ARCH),x64) - Q3DOBJ += \ - $(B)/ded/snapvector.o \ - $(B)/ded/ftola.o + $(B)/ded/ftola.o endif ifeq ($(USE_INTERNAL_ZLIB),1) @@ -2009,48 +2146,11 @@ Q3DOBJ += \ endif ifeq ($(HAVE_VM_COMPILED),true) - ifeq ($(ARCH),i386) + ifneq ($(findstring $(ARCH),x86 x86_64),) Q3DOBJ += \ $(B)/ded/vm_x86.o endif - ifeq ($(ARCH),x86) - Q3DOBJ += \ - $(B)/ded/vm_x86.o - endif - ifeq ($(ARCH),x86_64) - ifeq ($(USE_OLD_VM64),1) - Q3DOBJ += \ - $(B)/ded/vm_x86_64.o \ - $(B)/ded/vm_x86_64_assembler.o - else - Q3DOBJ += \ - $(B)/ded/vm_x86.o - endif - endif - ifeq ($(ARCH),amd64) - ifeq ($(USE_OLD_VM64),1) - Q3DOBJ += \ - $(B)/ded/vm_x86_64.o \ - $(B)/ded/vm_x86_64_assembler.o - else - Q3DOBJ += \ - $(B)/ded/vm_x86.o - endif - endif - ifeq ($(ARCH),x64) - ifeq ($(USE_OLD_VM64),1) - Q3DOBJ += \ - $(B)/ded/vm_x86_64.o \ - $(B)/ded/vm_x86_64_assembler.o - else - Q3DOBJ += \ - $(B)/ded/vm_x86.o - endif - endif - ifeq ($(ARCH),ppc) - Q3DOBJ += $(B)/ded/vm_powerpc.o $(B)/ded/vm_powerpc_asm.o - endif - ifeq ($(ARCH),ppc64) + ifneq ($(findstring $(ARCH),ppc ppc64),) Q3DOBJ += $(B)/ded/vm_powerpc.o $(B)/ded/vm_powerpc_asm.o endif ifeq ($(ARCH),sparc) @@ -2367,15 +2467,30 @@ $(B)/client/%.o: $(BLIBDIR)/%.c $(B)/client/%.o: $(SPEEXDIR)/%.c $(DO_CC) +$(B)/client/%.o: $(OGGDIR)/src/%.c + $(DO_CC) + +$(B)/client/opus/%.o: $(OPUSDIR)/src/%.c + $(DO_CC) + +$(B)/client/opus/%.o: $(OPUSDIR)/celt/%.c + $(DO_CC) + +$(B)/client/opus/%.o: $(OPUSDIR)/silk/%.c + $(DO_CC) + +$(B)/client/opus/%.o: $(OPUSDIR)/silk/float/%.c + $(DO_CC) + +$(B)/client/%.o: $(OPUSFILEDIR)/src/%.c + $(DO_CC) + $(B)/client/%.o: $(ZDIR)/%.c $(DO_CC) $(B)/client/%.o: $(SDLDIR)/%.c $(DO_CC) -$(B)/renderersmp/%.o: $(SDLDIR)/%.c - $(DO_SMP_CC) - $(B)/client/%.o: $(SYSDIR)/%.c $(DO_CC) @@ -2386,25 +2501,31 @@ $(B)/client/%.o: $(SYSDIR)/%.rc $(DO_WINDRES) -$(B)/renderer/%.o: $(CMDIR)/%.c +$(B)/renderergl1/%.o: $(CMDIR)/%.c $(DO_REF_CC) -$(B)/renderer/%.o: $(SDLDIR)/%.c +$(B)/renderergl1/%.o: $(SDLDIR)/%.c $(DO_REF_CC) -$(B)/renderer/%.o: $(JPDIR)/%.c +$(B)/renderergl1/%.o: $(JPDIR)/%.c $(DO_REF_CC) -$(B)/renderer/%.o: $(RDIR)/%.c +$(B)/renderergl1/%.o: $(RCOMMONDIR)/%.c $(DO_REF_CC) -$(B)/rend2/glsl/%.c: $(R2DIR)/glsl/%.glsl +$(B)/renderergl1/%.o: $(RGL1DIR)/%.c + $(DO_REF_CC) + +$(B)/renderergl2/glsl/%.c: $(RGL2DIR)/glsl/%.glsl $(DO_REF_STR) -$(B)/rend2/glsl/%.o: $(B)/rend2/glsl/%.c +$(B)/renderergl2/glsl/%.o: $(B)/renderergl2/glsl/%.c $(DO_REF_CC) -$(B)/rend2/%.o: $(R2DIR)/%.c +$(B)/renderergl2/%.o: $(RCOMMONDIR)/%.c + $(DO_REF_CC) + +$(B)/renderergl2/%.o: $(RGL2DIR)/%.c $(DO_REF_CC) @@ -2439,11 +2560,11 @@ $(B)/ded/%.o: $(SYSDIR)/%.rc $(B)/ded/%.o: $(NDIR)/%.c $(DO_DED_CC) -# Extra dependencies to ensure the SVN version is incorporated -ifeq ($(USE_SVN),1) - $(B)/client/cl_console.o : .svn/entries - $(B)/client/common.o : .svn/entries - $(B)/ded/common.o : .svn/entries +# Extra dependencies to ensure the git version is incorporated +ifeq ($(USE_GIT),1) + $(B)/client/cl_console.o : .git/index + $(B)/client/common.o : .git/index + $(B)/ded/common.o : .git/index endif @@ -2531,7 +2652,7 @@ $(B)/$(MISSIONPACK)/qcommon/%.asm: $(CMDIR)/%.c $(Q3LCC) # MISC ############################################################################# -OBJ = $(Q3OBJ) $(Q3ROBJ) $(Q3R2OBJ) $(Q3RPOBJ_UP) $(Q3RPOBJ_SMP) $(Q3DOBJ) $(JPGOBJ) \ +OBJ = $(Q3OBJ) $(Q3ROBJ) $(Q3R2OBJ) $(Q3DOBJ) $(JPGOBJ) \ $(MPGOBJ) $(Q3GOBJ) $(Q3CGOBJ) $(MPCGOBJ) $(Q3UIOBJ) $(MPUIOBJ) \ $(MPGVMOBJ) $(Q3GVMOBJ) $(Q3CGVMOBJ) $(MPCGVMOBJ) $(Q3UIVMOBJ) $(MPUIVMOBJ) TOOLSOBJ = $(LBURGOBJ) $(Q3CPPOBJ) $(Q3RCCOBJ) $(Q3LCCOBJ) $(Q3ASMOBJ) @@ -2553,21 +2674,12 @@ ifneq ($(BUILD_CLIENT),0) $(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/$(CLIENTBIN)$(FULLBINEXT) $(COPYBINDIR)/$(CLIENTBIN)$(FULLBINEXT) ifneq ($(USE_RENDERER_DLOPEN),0) $(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/renderer_opengl1_$(SHLIBNAME) $(COPYBINDIR)/renderer_opengl1_$(SHLIBNAME) - ifneq ($(BUILD_RENDERER_REND2),0) - $(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/renderer_rend2_$(SHLIBNAME) $(COPYBINDIR)/renderer_rend2_$(SHLIBNAME) + ifneq ($(BUILD_RENDERER_OPENGL2),0) + $(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/renderer_opengl2_$(SHLIBNAME) $(COPYBINDIR)/renderer_opengl2_$(SHLIBNAME) endif endif endif -# Don't copy the SMP until it's working together with SDL. -ifneq ($(BUILD_CLIENT_SMP),0) - ifneq ($(USE_RENDERER_DLOPEN),0) - $(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/renderer_opengl1_smp_$(SHLIBNAME) $(COPYBINDIR)/renderer_opengl1_smp_$(SHLIBNAME) - else - $(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/$(CLIENTBIN)-smp$(FULLBINEXT) $(COPYBINDIR)/$(CLIENTBIN)-smp$(FULLBINEXT) - endif -endif - ifneq ($(BUILD_SERVER),0) @if [ -f $(BR)/$(SERVERBIN)$(FULLBINEXT) ]; then \ $(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/$(SERVERBIN)$(FULLBINEXT) $(COPYBINDIR)/$(SERVERBIN)$(FULLBINEXT); \ @@ -2637,6 +2749,7 @@ ifeq ($(PLATFORM),mingw32) USE_RENDERER_DLOPEN=$(USE_RENDERER_DLOPEN) \ USE_OPENAL_DLOPEN=$(USE_OPENAL_DLOPEN) \ USE_CURL_DLOPEN=$(USE_CURL_DLOPEN) \ + USE_INTERNAL_OPUS=$(USE_INTERNAL_OPUS) \ USE_INTERNAL_SPEEX=$(USE_INTERNAL_SPEEX) \ USE_INTERNAL_ZLIB=$(USE_INTERNAL_ZLIB) \ USE_INTERNAL_JPEG=$(USE_INTERNAL_JPEG) @@ -2645,10 +2758,7 @@ else endif dist: - rm -rf $(CLIENTBIN)-$(VERSION) - svn export . $(CLIENTBIN)-$(VERSION) - tar --owner=root --group=root --force-local -cjf $(CLIENTBIN)-$(VERSION).tar.bz2 $(CLIENTBIN)-$(VERSION) - rm -rf $(CLIENTBIN)-$(VERSION) + git archive --format zip --output $(CLIENTBIN)-$(VERSION).zip HEAD ############################################################################# # DEPENDENCIES @@ -2665,3 +2775,8 @@ endif release targets \ toolsclean toolsclean2 toolsclean-debug toolsclean-release \ $(OBJ_D_FILES) $(TOOLSOBJ_D_FILES) + +# If the target name contains "clean", don't do a parallel build +ifneq ($(findstring clean, $(MAKECMDGOALS)),) +.NOTPARALLEL: +endif diff --git a/NOTTODO b/NOTTODO new file mode 100644 index 00000000..0db15474 --- /dev/null +++ b/NOTTODO @@ -0,0 +1 @@ +http://wiki.ioquake3.org/NotToDo diff --git a/README b/README index d8fd12af..1f4cf49c 100644 --- a/README +++ b/README @@ -32,7 +32,7 @@ Some of the major features currently implemented are: * Many, many bug fixes The map editor and associated compiling tools are not included. We suggest you -use a modern copy from http://www.qeradiant.com/. +use a modern copy from http://icculus.org/gtkradiant/. The original id software readme that accompanied the Q3 source release has been renamed to id-readme.txt so as to prevent confusion. Please refer to the @@ -64,15 +64,11 @@ Installation, for *nix point releases. 2. Run 'make copyfiles'. -It is also possible to cross compile for Windows under *nix using MinGW. A -script is available to build a cross compilation environment from -http://www.libsdl.org/extras/win32/cross/build-cross.sh. The gcc/binutils -version numbers that the script downloads may need to be altered. -Alternatively, your distribution may have mingw32 packages available. On -debian/Ubuntu, these are mingw32, mingw32-runtime and mingw32-binutils. Cross -compiling is simply a case of using './cross-make-mingw.sh' in place of 'make', -though you may find you need to change the value of the variables in this -script to match your environment. +It is also possible to cross compile for Windows under *nix using MinGW. Your +distribution may have mingw32 packages available. On debian/Ubuntu, you need to +install 'mingw-w64'. Thereafter cross compiling is simply a case running +'PLATFORM=mingw32 ARCH=x86 make' in place of 'make'. ARCH may also be set to +x86_64. The following variables may be set, either on the command line or in Makefile.local: @@ -82,7 +78,6 @@ Makefile.local: DEFAULT_BASEDIR - extra path to search for baseq3 and such BUILD_SERVER - build the 'ioq3ded' server binary BUILD_CLIENT - build the 'ioquake3' client binary - BUILD_CLIENT_SMP - build the 'ioquake3-smp' client binary BUILD_BASEGAME - build the 'baseq3' binaries BUILD_MISSIONPACK - build the 'missionpack' binaries BUILD_GAME_SO - build the game shared libraries @@ -99,15 +94,16 @@ Makefile.local: USE_CURL - use libcurl for http/ftp download support USE_CURL_DLOPEN - link with libcurl at runtime USE_CODEC_VORBIS - enable Ogg Vorbis support + USE_CODEC_OPUS - enable Ogg Opus support USE_MUMBLE - enable Mumble support USE_VOIP - enable built-in VoIP support USE_INTERNAL_SPEEX - build internal speex library instead of dynamically linking against system libspeex USE_FREETYPE - enable FreeType support for rendering fonts - USE_OLD_VM64 - use Ludwig Nussel's old JIT compiler implementation - for x86_64 USE_INTERNAL_ZLIB - build and link against internal zlib USE_INTERNAL_JPEG - build and link against internal JPEG library + USE_INTERNAL_OGG - build and link against internal ogg library + USE_INTERNAL_OPUS - build and link against internal opus/opusfile libraries USE_LOCAL_HEADERS - use headers local to ioq3 instead of system ones DEBUG_CFLAGS - C compiler flags to use for building debug version COPYDIR - the target installation directory @@ -281,6 +277,8 @@ New commands stopvideo - stop video capture stopmusic - stop background music minimize - Minimize the game and show desktop + togglemenu - causes escape key event for opening/closing menu, or + going to a previous menu. works in binds, even in UI print - print out the contents of a cvar unset - unset a user created cvar @@ -495,6 +493,12 @@ QuakeLive mouse acceleration (patch and this text written by TTimo from id) ---------------------------------------------------- README for Developers ----- +pk3dir + ioquake3 has a useful new feature for mappers. Paths in a game directory with + the extension ".pk3dir" are treated like pk3 files. This means you can keep + all files specific to your map in one directory tree and easily zip this + folder for distribution. + 64bit mods If you wish to compile external mods as shared libraries on a 64bit platform, and the mod source is derived from the id Q3 SDK, you will need to modify the diff --git a/Reaction-ChangeLog b/Reaction-ChangeLog index cffb55d6..4d577102 100644 --- a/Reaction-ChangeLog +++ b/Reaction-ChangeLog @@ -1,3 +1,5 @@ +- Temporarily disabled the Sun flares. +- Updated the ioq3 base Reaction is based on to ioq3 git dated Jul 21 2013 - Updated the ioq3 base Reaction is based on to ioq3 svn version 2378 - Added UI options for Cascaded Shadow Maps - Changed com_zoneMegs to 128 (from 64) diff --git a/build/README b/build/README deleted file mode 100644 index e9f09ecc..00000000 --- a/build/README +++ /dev/null @@ -1 +0,0 @@ -Target folder for Reaction builds. This file placed here because git rules! diff --git a/code/AL/VERSION b/code/AL/VERSION index 1af4e3fb..eb4f04d8 100644 --- a/code/AL/VERSION +++ b/code/AL/VERSION @@ -2,15 +2,4 @@ This file identifies the version of the AL headers in this directory. If you change or update the AL headers in any way, please make sure you also update this file. -SVN revision >= 402 -------------------- -Headers are from OpenAL CVS 6th August 2005: -$ cvs -d:pserver:guest@opensource.creative.com:/usr/local/cvs-repository -login -(use password "guest") -$ cvs -d:pserver:guest@opensource.creative.com:/usr/local/cvs-repository -co -D "6 Aug 2005" openal - -SVN revision >= 374 -------------------- -Standard OpenAL 1.0 headers +openal-soft-1.15.1 diff --git a/code/AL/al.h b/code/AL/al.h index fd9a5375..413b3833 100644 --- a/code/AL/al.h +++ b/code/AL/al.h @@ -1,506 +1,656 @@ -#ifndef __al_h_ -#define __al_h_ +#ifndef AL_AL_H +#define AL_AL_H -/** - * OpenAL cross platform audio library - * Copyright (C) 1999-2000 by authors. - * 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. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ -#include "altypes.h" - -#ifdef __cplusplus +#if defined(__cplusplus) extern "C" { #endif -/* WIN32, not Xbox */ -#ifdef _WIN32 -#ifndef _XBOX -#ifdef _OPENAL32LIB -#define ALAPI __declspec(dllexport) +#ifndef AL_API + #if defined(AL_LIBTYPE_STATIC) + #define AL_API + #elif defined(_WIN32) + #define AL_API __declspec(dllimport) + #else + #define AL_API extern + #endif +#endif + +#if defined(_WIN32) + #define AL_APIENTRY __cdecl #else -#define ALAPI __declspec(dllimport) -#endif -#define ALAPIENTRY __cdecl -#define AL_CALLBACK -#endif + #define AL_APIENTRY #endif -#ifdef TARGET_OS_MAC -#if TARGET_OS_MAC -#pragma export on -#endif -#endif - -#ifndef ALAPI -#define ALAPI -#endif - -#ifndef ALAPIENTRY -#define ALAPIENTRY -#endif - -#ifndef CALLBACK -#define AL_CALLBACK -#endif +/** Deprecated macro. */ #define OPENAL +#define ALAPI AL_API +#define ALAPIENTRY AL_APIENTRY +#define AL_INVALID (-1) +#define AL_ILLEGAL_ENUM AL_INVALID_ENUM +#define AL_ILLEGAL_COMMAND AL_INVALID_OPERATION -#ifndef AL_NO_PROTOTYPES +/** Supported AL version. */ +#define AL_VERSION_1_0 +#define AL_VERSION_1_1 -/* - * Renderer State management +/** 8-bit boolean */ +typedef char ALboolean; + +/** character */ +typedef char ALchar; + +/** signed 8-bit 2's complement integer */ +typedef signed char ALbyte; + +/** unsigned 8-bit integer */ +typedef unsigned char ALubyte; + +/** signed 16-bit 2's complement integer */ +typedef short ALshort; + +/** unsigned 16-bit integer */ +typedef unsigned short ALushort; + +/** signed 32-bit 2's complement integer */ +typedef int ALint; + +/** unsigned 32-bit integer */ +typedef unsigned int ALuint; + +/** non-negative 32-bit binary integer size */ +typedef int ALsizei; + +/** enumerated 32-bit value */ +typedef int ALenum; + +/** 32-bit IEEE754 floating-point */ +typedef float ALfloat; + +/** 64-bit IEEE754 floating-point */ +typedef double ALdouble; + +/** void type (for opaque pointers only) */ +typedef void ALvoid; + + +/* Enumerant values begin at column 50. No tabs. */ + +/** "no distance model" or "no buffer" */ +#define AL_NONE 0 + +/** Boolean False. */ +#define AL_FALSE 0 + +/** Boolean True. */ +#define AL_TRUE 1 + + +/** + * Relative source. + * Type: ALboolean + * Range: [AL_TRUE, AL_FALSE] + * Default: AL_FALSE + * + * Specifies if the Source has relative coordinates. */ -ALAPI void ALAPIENTRY alEnable( ALenum capability ); - -ALAPI void ALAPIENTRY alDisable( ALenum capability ); - -ALAPI ALboolean ALAPIENTRY alIsEnabled( ALenum capability ); +#define AL_SOURCE_RELATIVE 0x202 -/* - * State retrieval +/** + * Inner cone angle, in degrees. + * Type: ALint, ALfloat + * Range: [0 - 360] + * Default: 360 + * + * The angle covered by the inner cone, where the source will not attenuate. */ -ALAPI const ALchar* ALAPIENTRY alGetString( ALenum param ); +#define AL_CONE_INNER_ANGLE 0x1001 -ALAPI void ALAPIENTRY alGetBooleanv( ALenum param, ALboolean* data ); - -ALAPI void ALAPIENTRY alGetIntegerv( ALenum param, ALint* data ); - -ALAPI void ALAPIENTRY alGetFloatv( ALenum param, ALfloat* data ); - -ALAPI void ALAPIENTRY alGetDoublev( ALenum param, ALdouble* data ); - -ALAPI ALboolean ALAPIENTRY alGetBoolean( ALenum param ); - -ALAPI ALint ALAPIENTRY alGetInteger( ALenum param ); - -ALAPI ALfloat ALAPIENTRY alGetFloat( ALenum param ); - -ALAPI ALdouble ALAPIENTRY alGetDouble( ALenum param ); - - -/* - * Error support. - * Obtain the most recent error generated in the AL state machine. +/** + * Outer cone angle, in degrees. + * Range: [0 - 360] + * Default: 360 + * + * The angle covered by the outer cone, where the source will be fully + * attenuated. */ -ALAPI ALenum ALAPIENTRY alGetError( ALvoid ); +#define AL_CONE_OUTER_ANGLE 0x1002 + +/** + * Source pitch. + * Type: ALfloat + * Range: [0.5 - 2.0] + * Default: 1.0 + * + * A multiplier for the frequency (sample rate) of the source's buffer. + */ +#define AL_PITCH 0x1003 + +/** + * Source or listener position. + * Type: ALfloat[3], ALint[3] + * Default: {0, 0, 0} + * + * The source or listener location in three dimensional space. + * + * OpenAL, like OpenGL, uses a right handed coordinate system, where in a + * frontal default view X (thumb) points right, Y points up (index finger), and + * Z points towards the viewer/camera (middle finger). + * + * To switch from a left handed coordinate system, flip the sign on the Z + * coordinate. + */ +#define AL_POSITION 0x1004 + +/** + * Source direction. + * Type: ALfloat[3], ALint[3] + * Default: {0, 0, 0} + * + * Specifies the current direction in local space. + * A zero-length vector specifies an omni-directional source (cone is ignored). + */ +#define AL_DIRECTION 0x1005 + +/** + * Source or listener velocity. + * Type: ALfloat[3], ALint[3] + * Default: {0, 0, 0} + * + * Specifies the current velocity in local space. + */ +#define AL_VELOCITY 0x1006 + +/** + * Source looping. + * Type: ALboolean + * Range: [AL_TRUE, AL_FALSE] + * Default: AL_FALSE + * + * Specifies whether source is looping. + */ +#define AL_LOOPING 0x1007 + +/** + * Source buffer. + * Type: ALuint + * Range: any valid Buffer. + * + * Specifies the buffer to provide sound samples. + */ +#define AL_BUFFER 0x1009 + +/** + * Source or listener gain. + * Type: ALfloat + * Range: [0.0 - ] + * + * A value of 1.0 means unattenuated. Each division by 2 equals an attenuation + * of about -6dB. Each multiplicaton by 2 equals an amplification of about + * +6dB. + * + * A value of 0.0 is meaningless with respect to a logarithmic scale; it is + * silent. + */ +#define AL_GAIN 0x100A + +/** + * Minimum source gain. + * Type: ALfloat + * Range: [0.0 - 1.0] + * + * The minimum gain allowed for a source, after distance and cone attenation is + * applied (if applicable). + */ +#define AL_MIN_GAIN 0x100D + +/** + * Maximum source gain. + * Type: ALfloat + * Range: [0.0 - 1.0] + * + * The maximum gain allowed for a source, after distance and cone attenation is + * applied (if applicable). + */ +#define AL_MAX_GAIN 0x100E + +/** + * Listener orientation. + * Type: ALfloat[6] + * Default: {0.0, 0.0, -1.0, 0.0, 1.0, 0.0} + * + * Effectively two three dimensional vectors. The first vector is the front (or + * "at") and the second is the top (or "up"). + * + * Both vectors are in local space. + */ +#define AL_ORIENTATION 0x100F + +/** + * Source state (query only). + * Type: ALint + * Range: [AL_INITIAL, AL_PLAYING, AL_PAUSED, AL_STOPPED] + */ +#define AL_SOURCE_STATE 0x1010 + +/** Source state value. */ +#define AL_INITIAL 0x1011 +#define AL_PLAYING 0x1012 +#define AL_PAUSED 0x1013 +#define AL_STOPPED 0x1014 + +/** + * Source Buffer Queue size (query only). + * Type: ALint + * + * The number of buffers queued using alSourceQueueBuffers, minus the buffers + * removed with alSourceUnqueueBuffers. + */ +#define AL_BUFFERS_QUEUED 0x1015 + +/** + * Source Buffer Queue processed count (query only). + * Type: ALint + * + * The number of queued buffers that have been fully processed, and can be + * removed with alSourceUnqueueBuffers. + * + * Looping sources will never fully process buffers because they will be set to + * play again for when the source loops. + */ +#define AL_BUFFERS_PROCESSED 0x1016 + +/** + * Source reference distance. + * Type: ALfloat + * Range: [0.0 - ] + * Default: 1.0 + * + * The distance in units that no attenuation occurs. + * + * At 0.0, no distance attenuation ever occurs on non-linear attenuation models. + */ +#define AL_REFERENCE_DISTANCE 0x1020 + +/** + * Source rolloff factor. + * Type: ALfloat + * Range: [0.0 - ] + * Default: 1.0 + * + * Multiplier to exaggerate or diminish distance attenuation. + * + * At 0.0, no distance attenuation ever occurs. + */ +#define AL_ROLLOFF_FACTOR 0x1021 + +/** + * Outer cone gain. + * Type: ALfloat + * Range: [0.0 - 1.0] + * Default: 0.0 + * + * The gain attenuation applied when the listener is outside of the source's + * outer cone. + */ +#define AL_CONE_OUTER_GAIN 0x1022 + +/** + * Source maximum distance. + * Type: ALfloat + * Range: [0.0 - ] + * Default: +inf + * + * The distance above which the source is not attenuated any further with a + * clamped distance model, or where attenuation reaches 0.0 gain for linear + * distance models with a default rolloff factor. + */ +#define AL_MAX_DISTANCE 0x1023 + +/** Source buffer position, in seconds */ +#define AL_SEC_OFFSET 0x1024 +/** Source buffer position, in sample frames */ +#define AL_SAMPLE_OFFSET 0x1025 +/** Source buffer position, in bytes */ +#define AL_BYTE_OFFSET 0x1026 + +/** + * Source type (query only). + * Type: ALint + * Range: [AL_STATIC, AL_STREAMING, AL_UNDETERMINED] + * + * A Source is Static if a Buffer has been attached using AL_BUFFER. + * + * A Source is Streaming if one or more Buffers have been attached using + * alSourceQueueBuffers. + * + * A Source is Undetermined when it has the NULL buffer attached using + * AL_BUFFER. + */ +#define AL_SOURCE_TYPE 0x1027 + +/** Source type value. */ +#define AL_STATIC 0x1028 +#define AL_STREAMING 0x1029 +#define AL_UNDETERMINED 0x1030 + +/** Buffer format specifier. */ +#define AL_FORMAT_MONO8 0x1100 +#define AL_FORMAT_MONO16 0x1101 +#define AL_FORMAT_STEREO8 0x1102 +#define AL_FORMAT_STEREO16 0x1103 + +/** Buffer frequency (query only). */ +#define AL_FREQUENCY 0x2001 +/** Buffer bits per sample (query only). */ +#define AL_BITS 0x2002 +/** Buffer channel count (query only). */ +#define AL_CHANNELS 0x2003 +/** Buffer data size (query only). */ +#define AL_SIZE 0x2004 + +/** + * Buffer state. + * + * Not for public use. + */ +#define AL_UNUSED 0x2010 +#define AL_PENDING 0x2011 +#define AL_PROCESSED 0x2012 -/* +/** No error. */ +#define AL_NO_ERROR 0 + +/** Invalid name paramater passed to AL call. */ +#define AL_INVALID_NAME 0xA001 + +/** Invalid enum parameter passed to AL call. */ +#define AL_INVALID_ENUM 0xA002 + +/** Invalid value parameter passed to AL call. */ +#define AL_INVALID_VALUE 0xA003 + +/** Illegal AL call. */ +#define AL_INVALID_OPERATION 0xA004 + +/** Not enough memory. */ +#define AL_OUT_OF_MEMORY 0xA005 + + +/** Context string: Vendor ID. */ +#define AL_VENDOR 0xB001 +/** Context string: Version. */ +#define AL_VERSION 0xB002 +/** Context string: Renderer ID. */ +#define AL_RENDERER 0xB003 +/** Context string: Space-separated extension list. */ +#define AL_EXTENSIONS 0xB004 + + +/** + * Doppler scale. + * Type: ALfloat + * Range: [0.0 - ] + * Default: 1.0 + * + * Scale for source and listener velocities. + */ +#define AL_DOPPLER_FACTOR 0xC000 +AL_API void AL_APIENTRY alDopplerFactor(ALfloat value); + +/** + * Doppler velocity (deprecated). + * + * A multiplier applied to the Speed of Sound. + */ +#define AL_DOPPLER_VELOCITY 0xC001 +AL_API void AL_APIENTRY alDopplerVelocity(ALfloat value); + +/** + * Speed of Sound, in units per second. + * Type: ALfloat + * Range: [0.0001 - ] + * Default: 343.3 + * + * The speed at which sound waves are assumed to travel, when calculating the + * doppler effect. + */ +#define AL_SPEED_OF_SOUND 0xC003 +AL_API void AL_APIENTRY alSpeedOfSound(ALfloat value); + +/** + * Distance attenuation model. + * Type: ALint + * Range: [AL_NONE, AL_INVERSE_DISTANCE, AL_INVERSE_DISTANCE_CLAMPED, + * AL_LINEAR_DISTANCE, AL_LINEAR_DISTANCE_CLAMPED, + * AL_EXPONENT_DISTANCE, AL_EXPONENT_DISTANCE_CLAMPED] + * Default: AL_INVERSE_DISTANCE_CLAMPED + * + * The model by which sources attenuate with distance. + * + * None - No distance attenuation. + * Inverse - Doubling the distance halves the source gain. + * Linear - Linear gain scaling between the reference and max distances. + * Exponent - Exponential gain dropoff. + * + * Clamped variations work like the non-clamped counterparts, except the + * distance calculated is clamped between the reference and max distances. + */ +#define AL_DISTANCE_MODEL 0xD000 +AL_API void AL_APIENTRY alDistanceModel(ALenum distanceModel); + +/** Distance model value. */ +#define AL_INVERSE_DISTANCE 0xD001 +#define AL_INVERSE_DISTANCE_CLAMPED 0xD002 +#define AL_LINEAR_DISTANCE 0xD003 +#define AL_LINEAR_DISTANCE_CLAMPED 0xD004 +#define AL_EXPONENT_DISTANCE 0xD005 +#define AL_EXPONENT_DISTANCE_CLAMPED 0xD006 + +/** Renderer State management. */ +AL_API void AL_APIENTRY alEnable(ALenum capability); +AL_API void AL_APIENTRY alDisable(ALenum capability); +AL_API ALboolean AL_APIENTRY alIsEnabled(ALenum capability); + +/** State retrieval. */ +AL_API const ALchar* AL_APIENTRY alGetString(ALenum param); +AL_API void AL_APIENTRY alGetBooleanv(ALenum param, ALboolean *values); +AL_API void AL_APIENTRY alGetIntegerv(ALenum param, ALint *values); +AL_API void AL_APIENTRY alGetFloatv(ALenum param, ALfloat *values); +AL_API void AL_APIENTRY alGetDoublev(ALenum param, ALdouble *values); +AL_API ALboolean AL_APIENTRY alGetBoolean(ALenum param); +AL_API ALint AL_APIENTRY alGetInteger(ALenum param); +AL_API ALfloat AL_APIENTRY alGetFloat(ALenum param); +AL_API ALdouble AL_APIENTRY alGetDouble(ALenum param); + +/** + * Error retrieval. + * + * Obtain the first error generated in the AL context since the last check. + */ +AL_API ALenum AL_APIENTRY alGetError(void); + +/** * Extension support. - * Query for the presence of an extension, and obtain any appropriate - * function pointers and enum values. - */ -ALAPI ALboolean ALAPIENTRY alIsExtensionPresent( const ALchar* extname ); - -ALAPI void* ALAPIENTRY alGetProcAddress( const ALchar* fname ); - -ALAPI ALenum ALAPIENTRY alGetEnumValue( const ALchar* ename ); - - -/* - * LISTENER - * Listener represents the location and orientation of the - * 'user' in 3D-space. * - * Properties include: - - * - * Gain AL_GAIN ALfloat - * Position AL_POSITION ALfloat[3] - * Velocity AL_VELOCITY ALfloat[3] - * Orientation AL_ORIENTATION ALfloat[6] (Forward then Up vectors) -*/ - -/* - * Set Listener parameters + * Query for the presence of an extension, and obtain any appropriate function + * pointers and enum values. */ -ALAPI void ALAPIENTRY alListenerf( ALenum param, ALfloat value ); - -ALAPI void ALAPIENTRY alListener3f( ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 ); - -ALAPI void ALAPIENTRY alListenerfv( ALenum param, const ALfloat* values ); - -ALAPI void ALAPIENTRY alListeneri( ALenum param, ALint value ); - -ALAPI void ALAPIENTRY alListener3i( ALenum param, ALint value1, ALint value2, ALint value3 ); - -ALAPI void ALAPIENTRY alListeneriv( ALenum param, const ALint* values ); - -/* - * Get Listener parameters - */ -ALAPI void ALAPIENTRY alGetListenerf( ALenum param, ALfloat* value ); - -ALAPI void ALAPIENTRY alGetListener3f( ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3 ); - -ALAPI void ALAPIENTRY alGetListenerfv( ALenum param, ALfloat* values ); - -ALAPI void ALAPIENTRY alGetListeneri( ALenum param, ALint* value ); - -ALAPI void ALAPIENTRY alGetListener3i( ALenum param, ALint *value1, ALint *value2, ALint *value3 ); - -ALAPI void ALAPIENTRY alGetListeneriv( ALenum param, ALint* values ); - - -/** - * SOURCE - * Sources represent individual sound objects in 3D-space. - * Sources take the PCM data provided in the specified Buffer, - * apply Source-specific modifications, and then - * submit them to be mixed according to spatial arrangement etc. - * - * Properties include: - - * - * Gain AL_GAIN ALfloat - * Min Gain AL_MIN_GAIN ALfloat - * Max Gain AL_MAX_GAIN ALfloat - * Position AL_POSITION ALfloat[3] - * Velocity AL_VELOCITY ALfloat[3] - * Direction AL_DIRECTION ALfloat[3] - * Head Relative Mode AL_SOURCE_RELATIVE ALint (AL_TRUE or AL_FALSE) - * Reference Distance AL_REFERENCE_DISTANCE ALfloat - * Max Distance AL_MAX_DISTANCE ALfloat - * RollOff Factor AL_ROLLOFF_FACTOR ALfloat - * Inner Angle AL_CONE_INNER_ANGLE ALint or ALfloat - * Outer Angle AL_CONE_OUTER_ANGLE ALint or ALfloat - * Cone Outer Gain AL_CONE_OUTER_GAIN ALint or ALfloat - * Pitch AL_PITCH ALfloat - * Looping AL_LOOPING ALint (AL_TRUE or AL_FALSE) - * MS Offset AL_MSEC_OFFSET ALint or ALfloat - * Byte Offset AL_BYTE_OFFSET ALint or ALfloat - * Sample Offset AL_SAMPLE_OFFSET ALint or ALfloat - * Attached Buffer AL_BUFFER ALint - * State (Query only) AL_SOURCE_STATE ALint - * Buffers Queued (Query only) AL_BUFFERS_QUEUED ALint - * Buffers Processed (Query only) AL_BUFFERS_PROCESSED ALint - */ - -/* Create Source objects */ -ALAPI void ALAPIENTRY alGenSources( ALsizei n, ALuint* sources ); - -/* Delete Source objects */ -ALAPI void ALAPIENTRY alDeleteSources( ALsizei n, const ALuint* sources ); - -/* Verify a handle is a valid Source */ -ALAPI ALboolean ALAPIENTRY alIsSource( ALuint sid ); - -/* - * Set Source parameters - */ -ALAPI void ALAPIENTRY alSourcef( ALuint sid, ALenum param, ALfloat value ); - -ALAPI void ALAPIENTRY alSource3f( ALuint sid, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 ); - -ALAPI void ALAPIENTRY alSourcefv( ALuint sid, ALenum param, const ALfloat* values ); - -ALAPI void ALAPIENTRY alSourcei( ALuint sid, ALenum param, ALint value ); - -ALAPI void ALAPIENTRY alSource3i( ALuint sid, ALenum param, ALint value1, ALint value2, ALint value3 ); - -ALAPI void ALAPIENTRY alSourceiv( ALuint sid, ALenum param, const ALint* values ); - -/* - * Get Source parameters - */ -ALAPI void ALAPIENTRY alGetSourcef( ALuint sid, ALenum param, ALfloat* value ); - -ALAPI void ALAPIENTRY alGetSource3f( ALuint sid, ALenum param, ALfloat* value1, ALfloat* value2, ALfloat* value3); - -ALAPI void ALAPIENTRY alGetSourcefv( ALuint sid, ALenum param, ALfloat* values ); - -ALAPI void ALAPIENTRY alGetSourcei( ALuint sid, ALenum param, ALint* value ); - -ALAPI void ALAPIENTRY alGetSource3i( ALuint sid, ALenum param, ALint* value1, ALint* value2, ALint* value3); - -ALAPI void ALAPIENTRY alGetSourceiv( ALuint sid, ALenum param, ALint* values ); - - -/* - * Source vector based playback calls - */ - -/* Play, replay, or resume (if paused) a list of Sources */ -ALAPI void ALAPIENTRY alSourcePlayv( ALsizei ns, const ALuint *sids ); - -/* Stop a list of Sources */ -ALAPI void ALAPIENTRY alSourceStopv( ALsizei ns, const ALuint *sids ); - -/* Rewind a list of Sources */ -ALAPI void ALAPIENTRY alSourceRewindv( ALsizei ns, const ALuint *sids ); - -/* Pause a list of Sources */ -ALAPI void ALAPIENTRY alSourcePausev( ALsizei ns, const ALuint *sids ); - -/* - * Source based playback calls - */ - -/* Play, replay, or resume a Source */ -ALAPI void ALAPIENTRY alSourcePlay( ALuint sid ); - -/* Stop a Source */ -ALAPI void ALAPIENTRY alSourceStop( ALuint sid ); - -/* Rewind a Source (set playback postiton to beginning) */ -ALAPI void ALAPIENTRY alSourceRewind( ALuint sid ); - -/* Pause a Source */ -ALAPI void ALAPIENTRY alSourcePause( ALuint sid ); - -/* - * Source Queuing - */ -ALAPI void ALAPIENTRY alSourceQueueBuffers( ALuint sid, ALsizei numEntries, const ALuint *bids ); - -ALAPI void ALAPIENTRY alSourceUnqueueBuffers( ALuint sid, ALsizei numEntries, ALuint *bids ); - - -/** - * BUFFER - * Buffer objects are storage space for sample data. - * Buffers are referred to by Sources. One Buffer can be used - * by multiple Sources. - * - * Properties include: - - * - * Frequency (Query only) AL_FREQUENCY ALint - * Size (Query only) AL_SIZE ALint - * Bits (Query only) AL_BITS ALint - * Channels (Query only) AL_CHANNELS ALint - */ - -/* Create Buffer objects */ -ALAPI void ALAPIENTRY alGenBuffers( ALsizei n, ALuint* buffers ); - -/* Delete Buffer objects */ -ALAPI void ALAPIENTRY alDeleteBuffers( ALsizei n, const ALuint* buffers ); - -/* Verify a handle is a valid Buffer */ -ALAPI ALboolean ALAPIENTRY alIsBuffer( ALuint bid ); - -/* Specify the data to be copied into a buffer */ -ALAPI void ALAPIENTRY alBufferData( ALuint bid, ALenum format, const ALvoid* data, ALsizei size, ALsizei freq ); - -/* - * Set Buffer parameters - */ -ALAPI void ALAPIENTRY alBufferf( ALuint bid, ALenum param, ALfloat value ); - -ALAPI void ALAPIENTRY alBuffer3f( ALuint bid, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 ); - -ALAPI void ALAPIENTRY alBufferfv( ALuint bid, ALenum param, const ALfloat* values ); - -ALAPI void ALAPIENTRY alBufferi( ALuint bid, ALenum param, ALint value ); - -ALAPI void ALAPIENTRY alBuffer3i( ALuint bid, ALenum param, ALint value1, ALint value2, ALint value3 ); - -ALAPI void ALAPIENTRY alBufferiv( ALuint bid, ALenum param, const ALint* values ); - -/* - * Get Buffer parameters - */ -ALAPI void ALAPIENTRY alGetBufferf( ALuint bid, ALenum param, ALfloat* value ); - -ALAPI void ALAPIENTRY alGetBuffer3f( ALuint bid, ALenum param, ALfloat* value1, ALfloat* value2, ALfloat* value3); - -ALAPI void ALAPIENTRY alGetBufferfv( ALuint bid, ALenum param, ALfloat* values ); - -ALAPI void ALAPIENTRY alGetBufferi( ALuint bid, ALenum param, ALint* value ); - -ALAPI void ALAPIENTRY alGetBuffer3i( ALuint bid, ALenum param, ALint* value1, ALint* value2, ALint* value3); - -ALAPI void ALAPIENTRY alGetBufferiv( ALuint bid, ALenum param, ALint* values ); - - -/* - * Global Parameters - */ -ALAPI void ALAPIENTRY alDopplerFactor( ALfloat value ); - -ALAPI void ALAPIENTRY alDopplerVelocity( ALfloat value ); - -ALAPI void ALAPIENTRY alSpeedOfSound( ALfloat value ); - -ALAPI void ALAPIENTRY alDistanceModel( ALenum distanceModel ); - -#else /* AL_NO_PROTOTYPES */ - -/* -void (ALAPIENTRY *alEnable)( ALenum capability ); -void (ALAPIENTRY *alDisable)( ALenum capability ); -ALboolean (ALAPIENTRY *alIsEnabled)( ALenum capability ); -const ALchar* (ALAPIENTRY *alGetString)( ALenum param ); -void (ALAPIENTRY *alGetBooleanv)( ALenum param, ALboolean* data ); -void (ALAPIENTRY *alGetIntegerv)( ALenum param, ALint* data ); -void (ALAPIENTRY *alGetFloatv)( ALenum param, ALfloat* data ); -void (ALAPIENTRY *alGetDoublev)( ALenum param, ALdouble* data ); -ALboolean (ALAPIENTRY *alGetBoolean)( ALenum param ); -ALint (ALAPIENTRY *alGetInteger)( ALenum param ); -ALfloat (ALAPIENTRY *alGetFloat)( ALenum param ); -ALdouble (ALAPIENTRY *alGetDouble)( ALenum param ); -ALenum (ALAPIENTRY *alGetError)( ALvoid ); -ALboolean (ALAPIENTRY *alIsExtensionPresent)(const ALchar* extname ); -void* (ALAPIENTRY *alGetProcAddress)( const ALchar* fname ); -ALenum (ALAPIENTRY *alGetEnumValue)( const ALchar* ename ); -void (ALAPIENTRY *alListenerf)( ALenum param, ALfloat value ); -void (ALAPIENTRY *alListener3f)( ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 ); -void (ALAPIENTRY *alListenerfv)( ALenum param, const ALfloat* values ); -void (ALAPIENTRY *alListeneri)( ALenum param, ALint value ); -void (ALAPIENTRY *alListener3i)( ALenum param, ALint value1, ALint value2, ALint value3 ); -void (ALAPIENTRY *alListeneriv)( ALenum param, const ALint* values ); -void (ALAPIENTRY *alGetListenerf)( ALenum param, ALfloat* value ); -void (ALAPIENTRY *alGetListener3f)( ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3 ); -void (ALAPIENTRY *alGetListenerfv)( ALenum param, ALfloat* values ); -void (ALAPIENTRY *alGetListeneri)( ALenum param, ALint* value ); -void (ALAPIENTRY *alGetListener3i)( ALenum param, ALint *value1, ALint *value2, ALint *value3 ); -void (ALAPIENTRY *alGetListeneriv)( ALenum param, ALint* values ); -void (ALAPIENTRY *alGenSources)( ALsizei n, ALuint* sources ); -void (ALAPIENTRY *alDeleteSources)( ALsizei n, const ALuint* sources ); -ALboolean (ALAPIENTRY *alIsSource)( ALuint sid ); -void (ALAPIENTRY *alSourcef)( ALuint sid, ALenum param, ALfloat value); -void (ALAPIENTRY *alSource3f)( ALuint sid, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 ); -void (ALAPIENTRY *alSourcefv)( ALuint sid, ALenum param, const ALfloat* values ); -void (ALAPIENTRY *alSourcei)( ALuint sid, ALenum param, ALint value); -void (ALAPIENTRY *alSource3i)( ALuint sid, ALenum param, ALint value1, ALint value2, ALint value3 ); -void (ALAPIENTRY *alSourceiv)( ALuint sid, ALenum param, const ALint* values ); -void (ALAPIENTRY *alGetSourcef)( ALuint sid, ALenum param, ALfloat* value ); -void (ALAPIENTRY *alGetSource3f)( ALuint sid, ALenum param, ALfloat* value1, ALfloat* value2, ALfloat* value3); -void (ALAPIENTRY *alGetSourcefv)( ALuint sid, ALenum param, ALfloat* values ); -void (ALAPIENTRY *alGetSourcei)( ALuint sid, ALenum param, ALint* value ); -void (ALAPIENTRY *alGetSource3i)( ALuint sid, ALenum param, ALint* value1, ALint* value2, ALint* value3); -void (ALAPIENTRY *alGetSourceiv)( ALuint sid, ALenum param, ALint* values ); -void (ALAPIENTRY *alSourcePlayv)( ALsizei ns, const ALuint *sids ); -void (ALAPIENTRY *alSourceStopv)( ALsizei ns, const ALuint *sids ); -void (ALAPIENTRY *alSourceRewindv)( ALsizei ns, const ALuint *sids ); -void (ALAPIENTRY *alSourcePausev)( ALsizei ns, const ALuint *sids ); -void (ALAPIENTRY *alSourcePlay)( ALuint sid ); -void (ALAPIENTRY *alSourceStop)( ALuint sid ); -void (ALAPIENTRY *alSourceRewind)( ALuint sid ); -void (ALAPIENTRY *alSourcePause)( ALuint sid ); -void (ALAPIENTRY *alSourceQueueBuffers)( ALuint sid, ALsizei numEntries, const ALuint *bids ); -void (ALAPIENTRY *alSourceUnqueueBuffers)( ALuint sid, ALsizei numEntries, ALuint *bids ); -void (ALAPIENTRY *alGenBuffers)( ALsizei n, ALuint* buffers ); -void (ALAPIENTRY *alDeleteBuffers)( ALsizei n, const ALuint* buffers ); -ALboolean (ALAPIENTRY *alIsBuffer)( ALuint bid ); -void (ALAPIENTRY *alBufferData)( ALuint bid, ALenum format, const ALvoid* data, ALsizei size, ALsizei freq ); -void (ALAPIENTRY *alBufferf)( ALuint bid, ALenum param, ALfloat value); -void (ALAPIENTRY *alBuffer3f)( ALuint bid, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 ); -void (ALAPIENTRY *alBufferfv)( ALuint bid, ALenum param, const ALfloat* values ); -void (ALAPIENTRY *alBufferi)( ALuint bid, ALenum param, ALint value); -void (ALAPIENTRY *alBuffer3i)( ALuint bid, ALenum param, ALint value1, ALint value2, ALint value3 ); -void (ALAPIENTRY *alBufferiv)( ALuint bid, ALenum param, const ALint* values ); -void (ALAPIENTRY *alGetBufferf)( ALuint bid, ALenum param, ALfloat* value ); -void (ALAPIENTRY *alGetBuffer3f)( ALuint bid, ALenum param, ALfloat* value1, ALfloat* value2, ALfloat* value3); -void (ALAPIENTRY *alGetBufferfv)( ALuint bid, ALenum param, ALfloat* values ); -void (ALAPIENTRY *alGetBufferi)( ALuint bid, ALenum param, ALint* value ); -void (ALAPIENTRY *alGetBuffer3i)( ALuint bid, ALenum param, ALint* value1, ALint* value2, ALint* value3); -void (ALAPIENTRY *alGetBufferiv)( ALuint bid, ALenum param, ALint* values ); -void (ALAPIENTRY *alDopplerFactor)( ALfloat value ); -void (ALAPIENTRY *alDopplerVelocity)( ALfloat value ); -void (ALAPIENTRY *alSpeedOfSound)( ALfloat value ); -void (ALAPIENTRY *alDistanceModel)( ALenum distanceModel ); -*/ -/* Type Definitions */ - -typedef void (ALAPIENTRY *LPALENABLE)( ALenum capability ); -typedef void (ALAPIENTRY *LPALDISABLE)( ALenum capability ); -typedef ALboolean (ALAPIENTRY *LPALISENABLED)( ALenum capability ); -typedef const ALchar* (ALAPIENTRY *LPALGETSTRING)( ALenum param ); -typedef void (ALAPIENTRY *LPALGETBOOLEANV)( ALenum param, ALboolean* data ); -typedef void (ALAPIENTRY *LPALGETINTEGERV)( ALenum param, ALint* data ); -typedef void (ALAPIENTRY *LPALGETFLOATV)( ALenum param, ALfloat* data ); -typedef void (ALAPIENTRY *LPALGETDOUBLEV)( ALenum param, ALdouble* data ); -typedef ALboolean (ALAPIENTRY *LPALGETBOOLEAN)( ALenum param ); -typedef ALint (ALAPIENTRY *LPALGETINTEGER)( ALenum param ); -typedef ALfloat (ALAPIENTRY *LPALGETFLOAT)( ALenum param ); -typedef ALdouble (ALAPIENTRY *LPALGETDOUBLE)( ALenum param ); -typedef ALenum (ALAPIENTRY *LPALGETERROR)( ALvoid ); -typedef ALboolean (ALAPIENTRY *LPALISEXTENSIONPRESENT)(const ALchar* extname ); -typedef void* (ALAPIENTRY *LPALGETPROCADDRESS)( const ALchar* fname ); -typedef ALenum (ALAPIENTRY *LPALGETENUMVALUE)( const ALchar* ename ); -typedef void (ALAPIENTRY *LPALLISTENERF)( ALenum param, ALfloat value ); -typedef void (ALAPIENTRY *LPALLISTENER3F)( ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 ); -typedef void (ALAPIENTRY *LPALLISTENERFV)( ALenum param, const ALfloat* values ); -typedef void (ALAPIENTRY *LPALLISTENERI)( ALenum param, ALint value ); -typedef void (ALAPIENTRY *LPALLISTENER3I)( ALenum param, ALint value1, ALint value2, ALint value3 ); -typedef void (ALAPIENTRY *LPALLISTENERIV)( ALenum param, const ALint* values ); -typedef void (ALAPIENTRY *LPALGETLISTENERF)( ALenum param, ALfloat* value ); -typedef void (ALAPIENTRY *LPALGETLISTENER3F)( ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3 ); -typedef void (ALAPIENTRY *LPALGETLISTENERFV)( ALenum param, ALfloat* values ); -typedef void (ALAPIENTRY *LPALGETLISTENERI)( ALenum param, ALint* value ); -typedef void (ALAPIENTRY *LPALGETLISTENER3I)( ALenum param, ALint *value1, ALint *value2, ALint *value3 ); -typedef void (ALAPIENTRY *LPALGETLISTENERIV)( ALenum param, ALint* values ); -typedef void (ALAPIENTRY *LPALGENSOURCES)( ALsizei n, ALuint* sources ); -typedef void (ALAPIENTRY *LPALDELETESOURCES)( ALsizei n, const ALuint* sources ); -typedef ALboolean (ALAPIENTRY *LPALISSOURCE)( ALuint sid ); -typedef void (ALAPIENTRY *LPALSOURCEF)( ALuint sid, ALenum param, ALfloat value); -typedef void (ALAPIENTRY *LPALSOURCE3F)( ALuint sid, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 ); -typedef void (ALAPIENTRY *LPALSOURCEFV)( ALuint sid, ALenum param, const ALfloat* values ); -typedef void (ALAPIENTRY *LPALSOURCEI)( ALuint sid, ALenum param, ALint value); -typedef void (ALAPIENTRY *LPALSOURCE3I)( ALuint sid, ALenum param, ALint value1, ALint value2, ALint value3 ); -typedef void (ALAPIENTRY *LPALSOURCEIV)( ALuint sid, ALenum param, const ALint* values ); -typedef void (ALAPIENTRY *LPALGETSOURCEF)( ALuint sid, ALenum param, ALfloat* value ); -typedef void (ALAPIENTRY *LPALGETSOURCE3F)( ALuint sid, ALenum param, ALfloat* value1, ALfloat* value2, ALfloat* value3); -typedef void (ALAPIENTRY *LPALGETSOURCEFV)( ALuint sid, ALenum param, ALfloat* values ); -typedef void (ALAPIENTRY *LPALGETSOURCEI)( ALuint sid, ALenum param, ALint* value ); -typedef void (ALAPIENTRY *LPALGETSOURCE3I)( ALuint sid, ALenum param, ALint* value1, ALint* value2, ALint* value3); -typedef void (ALAPIENTRY *LPALGETSOURCEIV)( ALuint sid, ALenum param, ALint* values ); -typedef void (ALAPIENTRY *LPALSOURCEPLAYV)( ALsizei ns, const ALuint *sids ); -typedef void (ALAPIENTRY *LPALSOURCESTOPV)( ALsizei ns, const ALuint *sids ); -typedef void (ALAPIENTRY *LPALSOURCEREWINDV)( ALsizei ns, const ALuint *sids ); -typedef void (ALAPIENTRY *LPALSOURCEPAUSEV)( ALsizei ns, const ALuint *sids ); -typedef void (ALAPIENTRY *LPALSOURCEPLAY)( ALuint sid ); -typedef void (ALAPIENTRY *LPALSOURCESTOP)( ALuint sid ); -typedef void (ALAPIENTRY *LPALSOURCEREWIND)( ALuint sid ); -typedef void (ALAPIENTRY *LPALSOURCEPAUSE)( ALuint sid ); -typedef void (ALAPIENTRY *LPALSOURCEQUEUEBUFFERS)(ALuint sid, ALsizei numEntries, const ALuint *bids ); -typedef void (ALAPIENTRY *LPALSOURCEUNQUEUEBUFFERS)(ALuint sid, ALsizei numEntries, ALuint *bids ); -typedef void (ALAPIENTRY *LPALGENBUFFERS)( ALsizei n, ALuint* buffers ); -typedef void (ALAPIENTRY *LPALDELETEBUFFERS)( ALsizei n, const ALuint* buffers ); -typedef ALboolean (ALAPIENTRY *LPALISBUFFER)( ALuint bid ); -typedef void (ALAPIENTRY *LPALBUFFERDATA)( ALuint bid, ALenum format, const ALvoid* data, ALsizei size, ALsizei freq ); -typedef void (ALAPIENTRY *LPALBUFFERF)( ALuint bid, ALenum param, ALfloat value); -typedef void (ALAPIENTRY *LPALBUFFER3F)( ALuint bid, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3 ); -typedef void (ALAPIENTRY *LPALBUFFERFV)( ALuint bid, ALenum param, const ALfloat* values ); -typedef void (ALAPIENTRY *LPALBUFFERI)( ALuint bid, ALenum param, ALint value); -typedef void (ALAPIENTRY *LPALBUFFER3I)( ALuint bid, ALenum param, ALint value1, ALint value2, ALint value3 ); -typedef void (ALAPIENTRY *LPALBUFFERIV)( ALuint bid, ALenum param, const ALint* values ); -typedef void (ALAPIENTRY *LPALGETBUFFERF)( ALuint bid, ALenum param, ALfloat* value ); -typedef void (ALAPIENTRY *LPALGETBUFFER3F)( ALuint bid, ALenum param, ALfloat* value1, ALfloat* value2, ALfloat* value3); -typedef void (ALAPIENTRY *LPALGETBUFFERFV)( ALuint bid, ALenum param, ALfloat* values ); -typedef void (ALAPIENTRY *LPALGETBUFFERI)( ALuint bid, ALenum param, ALint* value ); -typedef void (ALAPIENTRY *LPALGETBUFFER3I)( ALuint bid, ALenum param, ALint* value1, ALint* value2, ALint* value3); -typedef void (ALAPIENTRY *LPALGETBUFFERIV)( ALuint bid, ALenum param, ALint* values ); -typedef void (ALAPIENTRY *LPALDOPPLERFACTOR)( ALfloat value ); -typedef void (ALAPIENTRY *LPALDOPPLERVELOCITY)( ALfloat value ); -typedef void (ALAPIENTRY *LPALSPEEDOFSOUND)( ALfloat value ); -typedef void (ALAPIENTRY *LPALDISTANCEMODEL)( ALenum distanceModel ); - -#endif /* AL_NO_PROTOTYPES */ - -#ifdef TARGET_OS_MAC -#if TARGET_OS_MAC -#pragma export off -#endif /* TARGET_OS_MAC */ -#endif /* TARGET_OS_MAC */ - - -#ifdef __cplusplus +AL_API ALboolean AL_APIENTRY alIsExtensionPresent(const ALchar *extname); +AL_API void* AL_APIENTRY alGetProcAddress(const ALchar *fname); +AL_API ALenum AL_APIENTRY alGetEnumValue(const ALchar *ename); + + +/** Set Listener parameters */ +AL_API void AL_APIENTRY alListenerf(ALenum param, ALfloat value); +AL_API void AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat value2, ALfloat value3); +AL_API void AL_APIENTRY alListenerfv(ALenum param, const ALfloat *values); +AL_API void AL_APIENTRY alListeneri(ALenum param, ALint value); +AL_API void AL_APIENTRY alListener3i(ALenum param, ALint value1, ALint value2, ALint value3); +AL_API void AL_APIENTRY alListeneriv(ALenum param, const ALint *values); + +/** Get Listener parameters */ +AL_API void AL_APIENTRY alGetListenerf(ALenum param, ALfloat *value); +AL_API void AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3); +AL_API void AL_APIENTRY alGetListenerfv(ALenum param, ALfloat *values); +AL_API void AL_APIENTRY alGetListeneri(ALenum param, ALint *value); +AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *value2, ALint *value3); +AL_API void AL_APIENTRY alGetListeneriv(ALenum param, ALint *values); + + +/** Create Source objects. */ +AL_API void AL_APIENTRY alGenSources(ALsizei n, ALuint *sources); +/** Delete Source objects. */ +AL_API void AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources); +/** Verify a handle is a valid Source. */ +AL_API ALboolean AL_APIENTRY alIsSource(ALuint source); + +/** Set Source parameters. */ +AL_API void AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value); +AL_API void AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3); +AL_API void AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values); +AL_API void AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value); +AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3); +AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values); + +/** Get Source parameters. */ +AL_API void AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value); +AL_API void AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3); +AL_API void AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values); +AL_API void AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value); +AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3); +AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values); + + +/** Play, replay, or resume (if paused) a list of Sources */ +AL_API void AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources); +/** Stop a list of Sources */ +AL_API void AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources); +/** Rewind a list of Sources */ +AL_API void AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources); +/** Pause a list of Sources */ +AL_API void AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources); + +/** Play, replay, or resume a Source */ +AL_API void AL_APIENTRY alSourcePlay(ALuint source); +/** Stop a Source */ +AL_API void AL_APIENTRY alSourceStop(ALuint source); +/** Rewind a Source (set playback postiton to beginning) */ +AL_API void AL_APIENTRY alSourceRewind(ALuint source); +/** Pause a Source */ +AL_API void AL_APIENTRY alSourcePause(ALuint source); + +/** Queue buffers onto a source */ +AL_API void AL_APIENTRY alSourceQueueBuffers(ALuint source, ALsizei nb, const ALuint *buffers); +/** Unqueue processed buffers from a source */ +AL_API void AL_APIENTRY alSourceUnqueueBuffers(ALuint source, ALsizei nb, ALuint *buffers); + + +/** Create Buffer objects */ +AL_API void AL_APIENTRY alGenBuffers(ALsizei n, ALuint *buffers); +/** Delete Buffer objects */ +AL_API void AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers); +/** Verify a handle is a valid Buffer */ +AL_API ALboolean AL_APIENTRY alIsBuffer(ALuint buffer); + +/** Specifies the data to be copied into a buffer */ +AL_API void AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq); + +/** Set Buffer parameters, */ +AL_API void AL_APIENTRY alBufferf(ALuint buffer, ALenum param, ALfloat value); +AL_API void AL_APIENTRY alBuffer3f(ALuint buffer, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3); +AL_API void AL_APIENTRY alBufferfv(ALuint buffer, ALenum param, const ALfloat *values); +AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value); +AL_API void AL_APIENTRY alBuffer3i(ALuint buffer, ALenum param, ALint value1, ALint value2, ALint value3); +AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *values); + +/** Get Buffer parameters. */ +AL_API void AL_APIENTRY alGetBufferf(ALuint buffer, ALenum param, ALfloat *value); +AL_API void AL_APIENTRY alGetBuffer3f(ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3); +AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum param, ALfloat *values); +AL_API void AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value); +AL_API void AL_APIENTRY alGetBuffer3i(ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3); +AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values); + +/** Pointer-to-function type, useful for dynamically getting AL entry points. */ +typedef void (AL_APIENTRY *LPALENABLE)(ALenum capability); +typedef void (AL_APIENTRY *LPALDISABLE)(ALenum capability); +typedef ALboolean (AL_APIENTRY *LPALISENABLED)(ALenum capability); +typedef const ALchar* (AL_APIENTRY *LPALGETSTRING)(ALenum param); +typedef void (AL_APIENTRY *LPALGETBOOLEANV)(ALenum param, ALboolean *values); +typedef void (AL_APIENTRY *LPALGETINTEGERV)(ALenum param, ALint *values); +typedef void (AL_APIENTRY *LPALGETFLOATV)(ALenum param, ALfloat *values); +typedef void (AL_APIENTRY *LPALGETDOUBLEV)(ALenum param, ALdouble *values); +typedef ALboolean (AL_APIENTRY *LPALGETBOOLEAN)(ALenum param); +typedef ALint (AL_APIENTRY *LPALGETINTEGER)(ALenum param); +typedef ALfloat (AL_APIENTRY *LPALGETFLOAT)(ALenum param); +typedef ALdouble (AL_APIENTRY *LPALGETDOUBLE)(ALenum param); +typedef ALenum (AL_APIENTRY *LPALGETERROR)(void); +typedef ALboolean (AL_APIENTRY *LPALISEXTENSIONPRESENT)(const ALchar *extname); +typedef void* (AL_APIENTRY *LPALGETPROCADDRESS)(const ALchar *fname); +typedef ALenum (AL_APIENTRY *LPALGETENUMVALUE)(const ALchar *ename); +typedef void (AL_APIENTRY *LPALLISTENERF)(ALenum param, ALfloat value); +typedef void (AL_APIENTRY *LPALLISTENER3F)(ALenum param, ALfloat value1, ALfloat value2, ALfloat value3); +typedef void (AL_APIENTRY *LPALLISTENERFV)(ALenum param, const ALfloat *values); +typedef void (AL_APIENTRY *LPALLISTENERI)(ALenum param, ALint value); +typedef void (AL_APIENTRY *LPALLISTENER3I)(ALenum param, ALint value1, ALint value2, ALint value3); +typedef void (AL_APIENTRY *LPALLISTENERIV)(ALenum param, const ALint *values); +typedef void (AL_APIENTRY *LPALGETLISTENERF)(ALenum param, ALfloat *value); +typedef void (AL_APIENTRY *LPALGETLISTENER3F)(ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3); +typedef void (AL_APIENTRY *LPALGETLISTENERFV)(ALenum param, ALfloat *values); +typedef void (AL_APIENTRY *LPALGETLISTENERI)(ALenum param, ALint *value); +typedef void (AL_APIENTRY *LPALGETLISTENER3I)(ALenum param, ALint *value1, ALint *value2, ALint *value3); +typedef void (AL_APIENTRY *LPALGETLISTENERIV)(ALenum param, ALint *values); +typedef void (AL_APIENTRY *LPALGENSOURCES)(ALsizei n, ALuint *sources); +typedef void (AL_APIENTRY *LPALDELETESOURCES)(ALsizei n, const ALuint *sources); +typedef ALboolean (AL_APIENTRY *LPALISSOURCE)(ALuint source); +typedef void (AL_APIENTRY *LPALSOURCEF)(ALuint source, ALenum param, ALfloat value); +typedef void (AL_APIENTRY *LPALSOURCE3F)(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3); +typedef void (AL_APIENTRY *LPALSOURCEFV)(ALuint source, ALenum param, const ALfloat *values); +typedef void (AL_APIENTRY *LPALSOURCEI)(ALuint source, ALenum param, ALint value); +typedef void (AL_APIENTRY *LPALSOURCE3I)(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3); +typedef void (AL_APIENTRY *LPALSOURCEIV)(ALuint source, ALenum param, const ALint *values); +typedef void (AL_APIENTRY *LPALGETSOURCEF)(ALuint source, ALenum param, ALfloat *value); +typedef void (AL_APIENTRY *LPALGETSOURCE3F)(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3); +typedef void (AL_APIENTRY *LPALGETSOURCEFV)(ALuint source, ALenum param, ALfloat *values); +typedef void (AL_APIENTRY *LPALGETSOURCEI)(ALuint source, ALenum param, ALint *value); +typedef void (AL_APIENTRY *LPALGETSOURCE3I)(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3); +typedef void (AL_APIENTRY *LPALGETSOURCEIV)(ALuint source, ALenum param, ALint *values); +typedef void (AL_APIENTRY *LPALSOURCEPLAYV)(ALsizei n, const ALuint *sources); +typedef void (AL_APIENTRY *LPALSOURCESTOPV)(ALsizei n, const ALuint *sources); +typedef void (AL_APIENTRY *LPALSOURCEREWINDV)(ALsizei n, const ALuint *sources); +typedef void (AL_APIENTRY *LPALSOURCEPAUSEV)(ALsizei n, const ALuint *sources); +typedef void (AL_APIENTRY *LPALSOURCEPLAY)(ALuint source); +typedef void (AL_APIENTRY *LPALSOURCESTOP)(ALuint source); +typedef void (AL_APIENTRY *LPALSOURCEREWIND)(ALuint source); +typedef void (AL_APIENTRY *LPALSOURCEPAUSE)(ALuint source); +typedef void (AL_APIENTRY *LPALSOURCEQUEUEBUFFERS)(ALuint source, ALsizei nb, const ALuint *buffers); +typedef void (AL_APIENTRY *LPALSOURCEUNQUEUEBUFFERS)(ALuint source, ALsizei nb, ALuint *buffers); +typedef void (AL_APIENTRY *LPALGENBUFFERS)(ALsizei n, ALuint *buffers); +typedef void (AL_APIENTRY *LPALDELETEBUFFERS)(ALsizei n, const ALuint *buffers); +typedef ALboolean (AL_APIENTRY *LPALISBUFFER)(ALuint buffer); +typedef void (AL_APIENTRY *LPALBUFFERDATA)(ALuint buffer, ALenum format, const ALvoid *data, ALsizei size, ALsizei freq); +typedef void (AL_APIENTRY *LPALBUFFERF)(ALuint buffer, ALenum param, ALfloat value); +typedef void (AL_APIENTRY *LPALBUFFER3F)(ALuint buffer, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3); +typedef void (AL_APIENTRY *LPALBUFFERFV)(ALuint buffer, ALenum param, const ALfloat *values); +typedef void (AL_APIENTRY *LPALBUFFERI)(ALuint buffer, ALenum param, ALint value); +typedef void (AL_APIENTRY *LPALBUFFER3I)(ALuint buffer, ALenum param, ALint value1, ALint value2, ALint value3); +typedef void (AL_APIENTRY *LPALBUFFERIV)(ALuint buffer, ALenum param, const ALint *values); +typedef void (AL_APIENTRY *LPALGETBUFFERF)(ALuint buffer, ALenum param, ALfloat *value); +typedef void (AL_APIENTRY *LPALGETBUFFER3F)(ALuint buffer, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3); +typedef void (AL_APIENTRY *LPALGETBUFFERFV)(ALuint buffer, ALenum param, ALfloat *values); +typedef void (AL_APIENTRY *LPALGETBUFFERI)(ALuint buffer, ALenum param, ALint *value); +typedef void (AL_APIENTRY *LPALGETBUFFER3I)(ALuint buffer, ALenum param, ALint *value1, ALint *value2, ALint *value3); +typedef void (AL_APIENTRY *LPALGETBUFFERIV)(ALuint buffer, ALenum param, ALint *values); +typedef void (AL_APIENTRY *LPALDOPPLERFACTOR)(ALfloat value); +typedef void (AL_APIENTRY *LPALDOPPLERVELOCITY)(ALfloat value); +typedef void (AL_APIENTRY *LPALSPEEDOFSOUND)(ALfloat value); +typedef void (AL_APIENTRY *LPALDISTANCEMODEL)(ALenum distanceModel); + +#if defined(__cplusplus) } /* extern "C" */ #endif -#endif /* __al_h_ */ +#endif /* AL_AL_H */ diff --git a/code/AL/alc.h b/code/AL/alc.h index f3a41bce..294e8b33 100644 --- a/code/AL/alc.h +++ b/code/AL/alc.h @@ -1,166 +1,237 @@ -#ifndef ALC_CONTEXT_H_ -#define ALC_CONTEXT_H_ +#ifndef AL_ALC_H +#define AL_ALC_H -#include "altypes.h" -#include "alctypes.h" - -#ifdef __cplusplus +#if defined(__cplusplus) extern "C" { #endif -#define ALC_VERSION_0_1 1 - -#ifdef _WIN32 - typedef struct ALCdevice_struct ALCdevice; - typedef struct ALCcontext_struct ALCcontext; - #ifndef _XBOX - #ifdef _OPENAL32LIB - #define ALCAPI __declspec(dllexport) - #else - #define ALCAPI __declspec(dllimport) - #endif - #define ALCAPIENTRY __cdecl +#ifndef ALC_API + #if defined(AL_LIBTYPE_STATIC) + #define ALC_API + #elif defined(_WIN32) + #define ALC_API __declspec(dllimport) + #else + #define ALC_API extern #endif #endif -#ifdef TARGET_OS_MAC - #if TARGET_OS_MAC - #pragma export on - #endif -#endif - -#ifndef ALCAPI - #define ALCAPI -#endif - -#ifndef ALCAPIENTRY - #define ALCAPIENTRY +#if defined(_WIN32) + #define ALC_APIENTRY __cdecl +#else + #define ALC_APIENTRY #endif -#ifndef ALC_NO_PROTOTYPES +/** Deprecated macro. */ +#define ALCAPI ALC_API +#define ALCAPIENTRY ALC_APIENTRY +#define ALC_INVALID 0 -/* - * Context Management +/** Supported ALC version? */ +#define ALC_VERSION_0_1 1 + +/** Opaque device handle */ +typedef struct ALCdevice_struct ALCdevice; +/** Opaque context handle */ +typedef struct ALCcontext_struct ALCcontext; + +/** 8-bit boolean */ +typedef char ALCboolean; + +/** character */ +typedef char ALCchar; + +/** signed 8-bit 2's complement integer */ +typedef signed char ALCbyte; + +/** unsigned 8-bit integer */ +typedef unsigned char ALCubyte; + +/** signed 16-bit 2's complement integer */ +typedef short ALCshort; + +/** unsigned 16-bit integer */ +typedef unsigned short ALCushort; + +/** signed 32-bit 2's complement integer */ +typedef int ALCint; + +/** unsigned 32-bit integer */ +typedef unsigned int ALCuint; + +/** non-negative 32-bit binary integer size */ +typedef int ALCsizei; + +/** enumerated 32-bit value */ +typedef int ALCenum; + +/** 32-bit IEEE754 floating-point */ +typedef float ALCfloat; + +/** 64-bit IEEE754 floating-point */ +typedef double ALCdouble; + +/** void type (for opaque pointers only) */ +typedef void ALCvoid; + + +/* Enumerant values begin at column 50. No tabs. */ + +/** Boolean False. */ +#define ALC_FALSE 0 + +/** Boolean True. */ +#define ALC_TRUE 1 + +/** Context attribute: Hz. */ +#define ALC_FREQUENCY 0x1007 + +/** Context attribute: Hz. */ +#define ALC_REFRESH 0x1008 + +/** Context attribute: AL_TRUE or AL_FALSE. */ +#define ALC_SYNC 0x1009 + +/** Context attribute: requested Mono (3D) Sources. */ +#define ALC_MONO_SOURCES 0x1010 + +/** Context attribute: requested Stereo Sources. */ +#define ALC_STEREO_SOURCES 0x1011 + +/** No error. */ +#define ALC_NO_ERROR 0 + +/** Invalid device handle. */ +#define ALC_INVALID_DEVICE 0xA001 + +/** Invalid context handle. */ +#define ALC_INVALID_CONTEXT 0xA002 + +/** Invalid enum parameter passed to an ALC call. */ +#define ALC_INVALID_ENUM 0xA003 + +/** Invalid value parameter passed to an ALC call. */ +#define ALC_INVALID_VALUE 0xA004 + +/** Out of memory. */ +#define ALC_OUT_OF_MEMORY 0xA005 + + +/** Runtime ALC version. */ +#define ALC_MAJOR_VERSION 0x1000 +#define ALC_MINOR_VERSION 0x1001 + +/** Context attribute list properties. */ +#define ALC_ATTRIBUTES_SIZE 0x1002 +#define ALC_ALL_ATTRIBUTES 0x1003 + +/** String for the default device specifier. */ +#define ALC_DEFAULT_DEVICE_SPECIFIER 0x1004 +/** + * String for the given device's specifier. + * + * If device handle is NULL, it is instead a null-char separated list of + * strings of known device specifiers (list ends with an empty string). */ -ALCAPI ALCcontext * ALCAPIENTRY alcCreateContext( ALCdevice *device, const ALCint* attrlist ); - -ALCAPI ALCboolean ALCAPIENTRY alcMakeContextCurrent( ALCcontext *context ); - -ALCAPI void ALCAPIENTRY alcProcessContext( ALCcontext *context ); - -ALCAPI void ALCAPIENTRY alcSuspendContext( ALCcontext *context ); - -ALCAPI void ALCAPIENTRY alcDestroyContext( ALCcontext *context ); - -ALCAPI ALCcontext * ALCAPIENTRY alcGetCurrentContext( ALCvoid ); - -ALCAPI ALCdevice* ALCAPIENTRY alcGetContextsDevice( ALCcontext *context ); +#define ALC_DEVICE_SPECIFIER 0x1005 +/** String for space-separated list of ALC extensions. */ +#define ALC_EXTENSIONS 0x1006 -/* - * Device Management +/** Capture extension */ +#define ALC_EXT_CAPTURE 1 +/** + * String for the given capture device's specifier. + * + * If device handle is NULL, it is instead a null-char separated list of + * strings of known capture device specifiers (list ends with an empty string). */ -ALCAPI ALCdevice * ALCAPIENTRY alcOpenDevice( const ALchar *devicename ); - -ALCAPI ALCboolean ALCAPIENTRY alcCloseDevice( ALCdevice *device ); +#define ALC_CAPTURE_DEVICE_SPECIFIER 0x310 +/** String for the default capture device specifier. */ +#define ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER 0x311 +/** Number of sample frames available for capture. */ +#define ALC_CAPTURE_SAMPLES 0x312 -/* +/** Enumerate All extension */ +#define ALC_ENUMERATE_ALL_EXT 1 +/** String for the default extended device specifier. */ +#define ALC_DEFAULT_ALL_DEVICES_SPECIFIER 0x1012 +/** + * String for the given extended device's specifier. + * + * If device handle is NULL, it is instead a null-char separated list of + * strings of known extended device specifiers (list ends with an empty string). + */ +#define ALC_ALL_DEVICES_SPECIFIER 0x1013 + + +/** Context management. */ +ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCint* attrlist); +ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context); +ALC_API void ALC_APIENTRY alcProcessContext(ALCcontext *context); +ALC_API void ALC_APIENTRY alcSuspendContext(ALCcontext *context); +ALC_API void ALC_APIENTRY alcDestroyContext(ALCcontext *context); +ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void); +ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *context); + +/** Device management. */ +ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *devicename); +ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device); + + +/** * Error support. - * Obtain the most recent Context error + * + * Obtain the most recent Device error. */ -ALCAPI ALCenum ALCAPIENTRY alcGetError( ALCdevice *device ); +ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device); - -/* +/** * Extension support. + * * Query for the presence of an extension, and obtain any appropriate * function pointers and enum values. */ -ALCAPI ALCboolean ALCAPIENTRY alcIsExtensionPresent( ALCdevice *device, const ALCchar *extname ); +ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extname); +ALC_API void* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcname); +ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumname); -ALCAPI void * ALCAPIENTRY alcGetProcAddress( ALCdevice *device, const ALCchar *funcname ); +/** Query function. */ +ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum param); +ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values); -ALCAPI ALCenum ALCAPIENTRY alcGetEnumValue( ALCdevice *device, const ALCchar *enumname ); +/** Capture function. */ +ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize); +ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device); +ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device); +ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device); +ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples); +/** Pointer-to-function type, useful for dynamically getting ALC entry points. */ +typedef ALCcontext* (ALC_APIENTRY *LPALCCREATECONTEXT)(ALCdevice *device, const ALCint *attrlist); +typedef ALCboolean (ALC_APIENTRY *LPALCMAKECONTEXTCURRENT)(ALCcontext *context); +typedef void (ALC_APIENTRY *LPALCPROCESSCONTEXT)(ALCcontext *context); +typedef void (ALC_APIENTRY *LPALCSUSPENDCONTEXT)(ALCcontext *context); +typedef void (ALC_APIENTRY *LPALCDESTROYCONTEXT)(ALCcontext *context); +typedef ALCcontext* (ALC_APIENTRY *LPALCGETCURRENTCONTEXT)(void); +typedef ALCdevice* (ALC_APIENTRY *LPALCGETCONTEXTSDEVICE)(ALCcontext *context); +typedef ALCdevice* (ALC_APIENTRY *LPALCOPENDEVICE)(const ALCchar *devicename); +typedef ALCboolean (ALC_APIENTRY *LPALCCLOSEDEVICE)(ALCdevice *device); +typedef ALCenum (ALC_APIENTRY *LPALCGETERROR)(ALCdevice *device); +typedef ALCboolean (ALC_APIENTRY *LPALCISEXTENSIONPRESENT)(ALCdevice *device, const ALCchar *extname); +typedef void* (ALC_APIENTRY *LPALCGETPROCADDRESS)(ALCdevice *device, const ALCchar *funcname); +typedef ALCenum (ALC_APIENTRY *LPALCGETENUMVALUE)(ALCdevice *device, const ALCchar *enumname); +typedef const ALCchar* (ALC_APIENTRY *LPALCGETSTRING)(ALCdevice *device, ALCenum param); +typedef void (ALC_APIENTRY *LPALCGETINTEGERV)(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values); +typedef ALCdevice* (ALC_APIENTRY *LPALCCAPTUREOPENDEVICE)(const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize); +typedef ALCboolean (ALC_APIENTRY *LPALCCAPTURECLOSEDEVICE)(ALCdevice *device); +typedef void (ALC_APIENTRY *LPALCCAPTURESTART)(ALCdevice *device); +typedef void (ALC_APIENTRY *LPALCCAPTURESTOP)(ALCdevice *device); +typedef void (ALC_APIENTRY *LPALCCAPTURESAMPLES)(ALCdevice *device, ALCvoid *buffer, ALCsizei samples); -/* - * Query functions - */ -ALCAPI const ALCchar * ALCAPIENTRY alcGetString( ALCdevice *device, ALCenum param ); - -ALCAPI void ALCAPIENTRY alcGetIntegerv( ALCdevice *device, ALCenum param, ALCsizei size, ALCint *data ); - - -/* - * Capture functions - */ -ALCAPI ALCdevice* ALCAPIENTRY alcCaptureOpenDevice( const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize ); - -ALCAPI ALCboolean ALCAPIENTRY alcCaptureCloseDevice( ALCdevice *device ); - -ALCAPI void ALCAPIENTRY alcCaptureStart( ALCdevice *device ); - -ALCAPI void ALCAPIENTRY alcCaptureStop( ALCdevice *device ); - -ALCAPI void ALCAPIENTRY alcCaptureSamples( ALCdevice *device, ALCvoid *buffer, ALCsizei samples ); - -#else /* ALC_NO_PROTOTYPES */ -/* -ALCAPI ALCcontext * (ALCAPIENTRY *alcCreateContext)( ALCdevice *device, const ALCint* attrlist ); -ALCAPI ALCboolean (ALCAPIENTRY *alcMakeContextCurrent)( ALCcontext *context ); -ALCAPI void (ALCAPIENTRY *alcProcessContext)( ALCcontext *context ); -ALCAPI void (ALCAPIENTRY *alcSuspendContext)( ALCcontext *context ); -ALCAPI void (ALCAPIENTRY *alcDestroyContext)( ALCcontext *context ); -ALCAPI ALCcontext * (ALCAPIENTRY *alcGetCurrentContext)( ALCvoid ); -ALCAPI ALCdevice * (ALCAPIENTRY *alcGetContextsDevice)( ALCcontext *context ); -ALCAPI ALCdevice * (ALCAPIENTRY *alcOpenDevice)( const ALCchar *devicename ); -ALCAPI ALCboolean (ALCAPIENTRY *alcCloseDevice)( ALCdevice *device ); -ALCAPI ALCenum (ALCAPIENTRY *alcGetError)( ALCdevice *device ); -ALCAPI ALCboolean (ALCAPIENTRY *alcIsExtensionPresent)( ALCdevice *device, const ALCchar *extname ); -ALCAPI void * (ALCAPIENTRY *alcGetProcAddress)( ALCdevice *device, const ALCchar *funcname ); -ALCAPI ALCenum (ALCAPIENTRY *alcGetEnumValue)( ALCdevice *device, const ALCchar *enumname ); -ALCAPI const ALCchar* (ALCAPIENTRY *alcGetString)( ALCdevice *device, ALCenum param ); -ALCAPI void (ALCAPIENTRY *alcGetIntegerv)( ALCdevice *device, ALCenum param, ALCsizei size, ALCint *dest ); -ALCAPI ALCdevice * (ALCAPIENTRY *alcCaptureOpenDevice)( const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize ); -ALCAPI ALCboolean (ALCAPIENTRY *alcCaptureCloseDevice)( ALCdevice *device ); -ALCAPI void (ALCAPIENTRY *alcCaptureStart)( ALCdevice *device ); -ALCAPI void (ALCAPIENTRY *alcCaptureStop)( ALCdevice *device ); -ALCAPI void (ALCAPIENTRY *alcCaptureSamples)( ALCdevice *device, ALCvoid *buffer, ALCsizei samples ); -*/ -/* Type definitions */ -typedef ALCcontext * (ALCAPIENTRY *LPALCCREATECONTEXT) (ALCdevice *device, const ALCint *attrlist); -typedef ALCboolean (ALCAPIENTRY *LPALCMAKECONTEXTCURRENT)( ALCcontext *context ); -typedef void (ALCAPIENTRY *LPALCPROCESSCONTEXT)( ALCcontext *context ); -typedef void (ALCAPIENTRY *LPALCSUSPENDCONTEXT)( ALCcontext *context ); -typedef void (ALCAPIENTRY *LPALCDESTROYCONTEXT)( ALCcontext *context ); -typedef ALCcontext * (ALCAPIENTRY *LPALCGETCURRENTCONTEXT)( ALCvoid ); -typedef ALCdevice * (ALCAPIENTRY *LPALCGETCONTEXTSDEVICE)( ALCcontext *context ); -typedef ALCdevice * (ALCAPIENTRY *LPALCOPENDEVICE)( const ALCchar *devicename ); -typedef ALCboolean (ALCAPIENTRY *LPALCCLOSEDEVICE)( ALCdevice *device ); -typedef ALCenum (ALCAPIENTRY *LPALCGETERROR)( ALCdevice *device ); -typedef ALCboolean (ALCAPIENTRY *LPALCISEXTENSIONPRESENT)( ALCdevice *device, const ALCchar *extname ); -typedef void * (ALCAPIENTRY *LPALCGETPROCADDRESS)(ALCdevice *device, const ALCchar *funcname ); -typedef ALCenum (ALCAPIENTRY *LPALCGETENUMVALUE)(ALCdevice *device, const ALCchar *enumname ); -typedef const ALCchar* (ALCAPIENTRY *LPALCGETSTRING)( ALCdevice *device, ALCenum param ); -typedef void (ALCAPIENTRY *LPALCGETINTEGERV)( ALCdevice *device, ALCenum param, ALCsizei size, ALCint *dest ); -typedef ALCdevice * (ALCAPIENTRY *LPALCCAPTUREOPENDEVICE)( const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize ); -typedef ALCboolean (ALCAPIENTRY *LPALCCAPTURECLOSEDEVICE)( ALCdevice *device ); -typedef void (ALCAPIENTRY *LPALCCAPTURESTART)( ALCdevice *device ); -typedef void (ALCAPIENTRY *LPALCCAPTURESTOP)( ALCdevice *device ); -typedef void (ALCAPIENTRY *LPALCCAPTURESAMPLES)( ALCdevice *device, ALCvoid *buffer, ALCsizei samples ); - -#endif /* ALC_NO_PROTOTYPES */ - -#ifdef TARGET_OS_MAC -#if TARGET_OS_MAC -#pragma export off -#endif /* TARGET_OS_MAC */ -#endif /* TARGET_OS_MAC */ - -#ifdef __cplusplus +#if defined(__cplusplus) } #endif -#endif /* ALC_CONTEXT_H_ */ +#endif /* AL_ALC_H */ diff --git a/code/AL/alctypes.h b/code/AL/alctypes.h deleted file mode 100644 index a7c7858f..00000000 --- a/code/AL/alctypes.h +++ /dev/null @@ -1,143 +0,0 @@ -#ifndef _ALCTYPES_H_ -#define _ALCTYPES_H_ - -#if !defined(_WIN32) -struct _AL_device; -typedef struct _AL_device ALCdevice; - -typedef void ALCcontext; -#endif /* _WIN32 */ - -typedef int ALCenum; - -/** ALC boolean type. */ -typedef char ALCboolean; - -/** ALC 8bit signed byte. */ -typedef char ALCbyte; - -/** ALC 8bit unsigned byte. */ -typedef unsigned char ALCubyte; - -/** OpenAL 8bit char */ -typedef char ALCchar; - -/** ALC 16bit signed short integer type. */ -typedef short ALCshort; - -/** ALC 16bit unsigned short integer type. */ -typedef unsigned short ALCushort; - -/** ALC 32bit unsigned integer type. */ -typedef unsigned ALCuint; - -/** ALC 32bit signed integer type. */ -typedef int ALCint; - -/** ALC 32bit floating point type. */ -typedef float ALCfloat; - -/** ALC 64bit double point type. */ -typedef double ALCdouble; - -/** ALC 32bit type. */ -typedef int ALCsizei; - -/** ALC void type */ -typedef void ALCvoid; - -/* Enumerant values begin at column 50. No tabs. */ - -/* bad value */ -#define ALC_INVALID 0 - -/* Boolean False. */ -#define ALC_FALSE 0 - -/* Boolean True. */ -#define ALC_TRUE 1 - -/** - * followed by Hz - */ -#define ALC_FREQUENCY 0x1007 - -/** - * followed by Hz - */ -#define ALC_REFRESH 0x1008 - -/** - * followed by AL_TRUE, AL_FALSE - */ -#define ALC_SYNC 0x1009 - -/** - * followed by Num of requested Mono (3D) Sources - */ -#define ALC_MONO_SOURCES 0x1010 - -/** - * followed by Num of requested Stereo Sources - */ -#define ALC_STEREO_SOURCES 0x1011 - -/** - * errors - */ - -/** - * No error - */ -#define ALC_NO_ERROR ALC_FALSE - -/** - * No device - */ -#define ALC_INVALID_DEVICE 0xA001 - -/** - * invalid context ID - */ -#define ALC_INVALID_CONTEXT 0xA002 - -/** - * bad enum - */ -#define ALC_INVALID_ENUM 0xA003 - -/** - * bad value - */ -#define ALC_INVALID_VALUE 0xA004 - -/** - * Out of memory. - */ -#define ALC_OUT_OF_MEMORY 0xA005 - - - -/** - * The Specifier string for default device - */ -#define ALC_DEFAULT_DEVICE_SPECIFIER 0x1004 -#define ALC_DEVICE_SPECIFIER 0x1005 -#define ALC_ALL_DEVICES_SPECIFIER 0x1013 -#define ALC_EXTENSIONS 0x1006 - -#define ALC_MAJOR_VERSION 0x1000 -#define ALC_MINOR_VERSION 0x1001 - -#define ALC_ATTRIBUTES_SIZE 0x1002 -#define ALC_ALL_ATTRIBUTES 0x1003 - -/** - * Capture extension - */ -#define ALC_CAPTURE_DEVICE_SPECIFIER 0x310 -#define ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER 0x311 -#define ALC_CAPTURE_SAMPLES 0x312 - - -#endif /* _ALCTYPES_H */ diff --git a/code/AL/alext.h b/code/AL/alext.h new file mode 100644 index 00000000..0447f2bb --- /dev/null +++ b/code/AL/alext.h @@ -0,0 +1,355 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 2008 by authors. + * 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. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#ifndef AL_ALEXT_H +#define AL_ALEXT_H + +#include +/* Define int64_t and uint64_t types */ +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +#include +#elif defined(_WIN32) && defined(__GNUC__) +#include +#elif defined(_WIN32) +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +#else +/* Fallback if nothing above works */ +#include +#endif + +#include "alc.h" +#include "al.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef AL_LOKI_IMA_ADPCM_format +#define AL_LOKI_IMA_ADPCM_format 1 +#define AL_FORMAT_IMA_ADPCM_MONO16_EXT 0x10000 +#define AL_FORMAT_IMA_ADPCM_STEREO16_EXT 0x10001 +#endif + +#ifndef AL_LOKI_WAVE_format +#define AL_LOKI_WAVE_format 1 +#define AL_FORMAT_WAVE_EXT 0x10002 +#endif + +#ifndef AL_EXT_vorbis +#define AL_EXT_vorbis 1 +#define AL_FORMAT_VORBIS_EXT 0x10003 +#endif + +#ifndef AL_LOKI_quadriphonic +#define AL_LOKI_quadriphonic 1 +#define AL_FORMAT_QUAD8_LOKI 0x10004 +#define AL_FORMAT_QUAD16_LOKI 0x10005 +#endif + +#ifndef AL_EXT_float32 +#define AL_EXT_float32 1 +#define AL_FORMAT_MONO_FLOAT32 0x10010 +#define AL_FORMAT_STEREO_FLOAT32 0x10011 +#endif + +#ifndef AL_EXT_double +#define AL_EXT_double 1 +#define AL_FORMAT_MONO_DOUBLE_EXT 0x10012 +#define AL_FORMAT_STEREO_DOUBLE_EXT 0x10013 +#endif + +#ifndef AL_EXT_MULAW +#define AL_EXT_MULAW 1 +#define AL_FORMAT_MONO_MULAW_EXT 0x10014 +#define AL_FORMAT_STEREO_MULAW_EXT 0x10015 +#endif + +#ifndef AL_EXT_ALAW +#define AL_EXT_ALAW 1 +#define AL_FORMAT_MONO_ALAW_EXT 0x10016 +#define AL_FORMAT_STEREO_ALAW_EXT 0x10017 +#endif + +#ifndef ALC_LOKI_audio_channel +#define ALC_LOKI_audio_channel 1 +#define ALC_CHAN_MAIN_LOKI 0x500001 +#define ALC_CHAN_PCM_LOKI 0x500002 +#define ALC_CHAN_CD_LOKI 0x500003 +#endif + +#ifndef AL_EXT_MCFORMATS +#define AL_EXT_MCFORMATS 1 +#define AL_FORMAT_QUAD8 0x1204 +#define AL_FORMAT_QUAD16 0x1205 +#define AL_FORMAT_QUAD32 0x1206 +#define AL_FORMAT_REAR8 0x1207 +#define AL_FORMAT_REAR16 0x1208 +#define AL_FORMAT_REAR32 0x1209 +#define AL_FORMAT_51CHN8 0x120A +#define AL_FORMAT_51CHN16 0x120B +#define AL_FORMAT_51CHN32 0x120C +#define AL_FORMAT_61CHN8 0x120D +#define AL_FORMAT_61CHN16 0x120E +#define AL_FORMAT_61CHN32 0x120F +#define AL_FORMAT_71CHN8 0x1210 +#define AL_FORMAT_71CHN16 0x1211 +#define AL_FORMAT_71CHN32 0x1212 +#endif + +#ifndef AL_EXT_MULAW_MCFORMATS +#define AL_EXT_MULAW_MCFORMATS 1 +#define AL_FORMAT_MONO_MULAW 0x10014 +#define AL_FORMAT_STEREO_MULAW 0x10015 +#define AL_FORMAT_QUAD_MULAW 0x10021 +#define AL_FORMAT_REAR_MULAW 0x10022 +#define AL_FORMAT_51CHN_MULAW 0x10023 +#define AL_FORMAT_61CHN_MULAW 0x10024 +#define AL_FORMAT_71CHN_MULAW 0x10025 +#endif + +#ifndef AL_EXT_IMA4 +#define AL_EXT_IMA4 1 +#define AL_FORMAT_MONO_IMA4 0x1300 +#define AL_FORMAT_STEREO_IMA4 0x1301 +#endif + +#ifndef AL_EXT_STATIC_BUFFER +#define AL_EXT_STATIC_BUFFER 1 +typedef ALvoid (AL_APIENTRY*PFNALBUFFERDATASTATICPROC)(const ALint,ALenum,ALvoid*,ALsizei,ALsizei); +#ifdef AL_ALEXT_PROTOTYPES +AL_API ALvoid AL_APIENTRY alBufferDataStatic(const ALint buffer, ALenum format, ALvoid *data, ALsizei len, ALsizei freq); +#endif +#endif + +#ifndef ALC_EXT_EFX +#define ALC_EXT_EFX 1 +#include "efx.h" +#endif + +#ifndef ALC_EXT_disconnect +#define ALC_EXT_disconnect 1 +#define ALC_CONNECTED 0x313 +#endif + +#ifndef ALC_EXT_thread_local_context +#define ALC_EXT_thread_local_context 1 +typedef ALCboolean (ALC_APIENTRY*PFNALCSETTHREADCONTEXTPROC)(ALCcontext *context); +typedef ALCcontext* (ALC_APIENTRY*PFNALCGETTHREADCONTEXTPROC)(void); +#ifdef AL_ALEXT_PROTOTYPES +ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context); +ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void); +#endif +#endif + +#ifndef AL_EXT_source_distance_model +#define AL_EXT_source_distance_model 1 +#define AL_SOURCE_DISTANCE_MODEL 0x200 +#endif + +#ifndef AL_SOFT_buffer_sub_data +#define AL_SOFT_buffer_sub_data 1 +#define AL_BYTE_RW_OFFSETS_SOFT 0x1031 +#define AL_SAMPLE_RW_OFFSETS_SOFT 0x1032 +typedef ALvoid (AL_APIENTRY*PFNALBUFFERSUBDATASOFTPROC)(ALuint,ALenum,const ALvoid*,ALsizei,ALsizei); +#ifdef AL_ALEXT_PROTOTYPES +AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer,ALenum format,const ALvoid *data,ALsizei offset,ALsizei length); +#endif +#endif + +#ifndef AL_SOFT_loop_points +#define AL_SOFT_loop_points 1 +#define AL_LOOP_POINTS_SOFT 0x2015 +#endif + +#ifndef AL_EXT_FOLDBACK +#define AL_EXT_FOLDBACK 1 +#define AL_EXT_FOLDBACK_NAME "AL_EXT_FOLDBACK" +#define AL_FOLDBACK_EVENT_BLOCK 0x4112 +#define AL_FOLDBACK_EVENT_START 0x4111 +#define AL_FOLDBACK_EVENT_STOP 0x4113 +#define AL_FOLDBACK_MODE_MONO 0x4101 +#define AL_FOLDBACK_MODE_STEREO 0x4102 +typedef void (AL_APIENTRY*LPALFOLDBACKCALLBACK)(ALenum,ALsizei); +typedef void (AL_APIENTRY*LPALREQUESTFOLDBACKSTART)(ALenum,ALsizei,ALsizei,ALfloat*,LPALFOLDBACKCALLBACK); +typedef void (AL_APIENTRY*LPALREQUESTFOLDBACKSTOP)(void); +#ifdef AL_ALEXT_PROTOTYPES +AL_API void AL_APIENTRY alRequestFoldbackStart(ALenum mode,ALsizei count,ALsizei length,ALfloat *mem,LPALFOLDBACKCALLBACK callback); +AL_API void AL_APIENTRY alRequestFoldbackStop(void); +#endif +#endif + +#ifndef ALC_EXT_DEDICATED +#define ALC_EXT_DEDICATED 1 +#define AL_DEDICATED_GAIN 0x0001 +#define AL_EFFECT_DEDICATED_DIALOGUE 0x9001 +#define AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT 0x9000 +#endif + +#ifndef AL_SOFT_buffer_samples +#define AL_SOFT_buffer_samples 1 +/* Channel configurations */ +#define AL_MONO_SOFT 0x1500 +#define AL_STEREO_SOFT 0x1501 +#define AL_REAR_SOFT 0x1502 +#define AL_QUAD_SOFT 0x1503 +#define AL_5POINT1_SOFT 0x1504 +#define AL_6POINT1_SOFT 0x1505 +#define AL_7POINT1_SOFT 0x1506 + +/* Sample types */ +#define AL_BYTE_SOFT 0x1400 +#define AL_UNSIGNED_BYTE_SOFT 0x1401 +#define AL_SHORT_SOFT 0x1402 +#define AL_UNSIGNED_SHORT_SOFT 0x1403 +#define AL_INT_SOFT 0x1404 +#define AL_UNSIGNED_INT_SOFT 0x1405 +#define AL_FLOAT_SOFT 0x1406 +#define AL_DOUBLE_SOFT 0x1407 +#define AL_BYTE3_SOFT 0x1408 +#define AL_UNSIGNED_BYTE3_SOFT 0x1409 + +/* Storage formats */ +#define AL_MONO8_SOFT 0x1100 +#define AL_MONO16_SOFT 0x1101 +#define AL_MONO32F_SOFT 0x10010 +#define AL_STEREO8_SOFT 0x1102 +#define AL_STEREO16_SOFT 0x1103 +#define AL_STEREO32F_SOFT 0x10011 +#define AL_QUAD8_SOFT 0x1204 +#define AL_QUAD16_SOFT 0x1205 +#define AL_QUAD32F_SOFT 0x1206 +#define AL_REAR8_SOFT 0x1207 +#define AL_REAR16_SOFT 0x1208 +#define AL_REAR32F_SOFT 0x1209 +#define AL_5POINT1_8_SOFT 0x120A +#define AL_5POINT1_16_SOFT 0x120B +#define AL_5POINT1_32F_SOFT 0x120C +#define AL_6POINT1_8_SOFT 0x120D +#define AL_6POINT1_16_SOFT 0x120E +#define AL_6POINT1_32F_SOFT 0x120F +#define AL_7POINT1_8_SOFT 0x1210 +#define AL_7POINT1_16_SOFT 0x1211 +#define AL_7POINT1_32F_SOFT 0x1212 + +/* Buffer attributes */ +#define AL_INTERNAL_FORMAT_SOFT 0x2008 +#define AL_BYTE_LENGTH_SOFT 0x2009 +#define AL_SAMPLE_LENGTH_SOFT 0x200A +#define AL_SEC_LENGTH_SOFT 0x200B + +typedef void (AL_APIENTRY*LPALBUFFERSAMPLESSOFT)(ALuint,ALuint,ALenum,ALsizei,ALenum,ALenum,const ALvoid*); +typedef void (AL_APIENTRY*LPALBUFFERSUBSAMPLESSOFT)(ALuint,ALsizei,ALsizei,ALenum,ALenum,const ALvoid*); +typedef void (AL_APIENTRY*LPALGETBUFFERSAMPLESSOFT)(ALuint,ALsizei,ALsizei,ALenum,ALenum,ALvoid*); +typedef ALboolean (AL_APIENTRY*LPALISBUFFERFORMATSUPPORTEDSOFT)(ALenum); +#ifdef AL_ALEXT_PROTOTYPES +AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint buffer, ALuint samplerate, ALenum internalformat, ALsizei samples, ALenum channels, ALenum type, const ALvoid *data); +AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint buffer, ALsizei offset, ALsizei samples, ALenum channels, ALenum type, const ALvoid *data); +AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint buffer, ALsizei offset, ALsizei samples, ALenum channels, ALenum type, ALvoid *data); +AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum format); +#endif +#endif + +#ifndef AL_SOFT_direct_channels +#define AL_SOFT_direct_channels 1 +#define AL_DIRECT_CHANNELS_SOFT 0x1033 +#endif + +#ifndef ALC_SOFT_loopback +#define ALC_SOFT_loopback 1 +#define ALC_FORMAT_CHANNELS_SOFT 0x1990 +#define ALC_FORMAT_TYPE_SOFT 0x1991 + +/* Sample types */ +#define ALC_BYTE_SOFT 0x1400 +#define ALC_UNSIGNED_BYTE_SOFT 0x1401 +#define ALC_SHORT_SOFT 0x1402 +#define ALC_UNSIGNED_SHORT_SOFT 0x1403 +#define ALC_INT_SOFT 0x1404 +#define ALC_UNSIGNED_INT_SOFT 0x1405 +#define ALC_FLOAT_SOFT 0x1406 + +/* Channel configurations */ +#define ALC_MONO_SOFT 0x1500 +#define ALC_STEREO_SOFT 0x1501 +#define ALC_QUAD_SOFT 0x1503 +#define ALC_5POINT1_SOFT 0x1504 +#define ALC_6POINT1_SOFT 0x1505 +#define ALC_7POINT1_SOFT 0x1506 + +typedef ALCdevice* (ALC_APIENTRY*LPALCLOOPBACKOPENDEVICESOFT)(const ALCchar*); +typedef ALCboolean (ALC_APIENTRY*LPALCISRENDERFORMATSUPPORTEDSOFT)(ALCdevice*,ALCsizei,ALCenum,ALCenum); +typedef void (ALC_APIENTRY*LPALCRENDERSAMPLESSOFT)(ALCdevice*,ALCvoid*,ALCsizei); +#ifdef AL_ALEXT_PROTOTYPES +ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceName); +ALC_API ALCboolean ALC_APIENTRY alcIsRenderFormatSupportedSOFT(ALCdevice *device, ALCsizei freq, ALCenum channels, ALCenum type); +ALC_API void ALC_APIENTRY alcRenderSamplesSOFT(ALCdevice *device, ALCvoid *buffer, ALCsizei samples); +#endif +#endif + +#ifndef AL_EXT_STEREO_ANGLES +#define AL_EXT_STEREO_ANGLES 1 +#define AL_STEREO_ANGLES 0x1030 +#endif + +#ifndef AL_EXT_SOURCE_RADIUS +#define AL_EXT_SOURCE_RADIUS 1 +#define AL_SOURCE_RADIUS 0x1031 +#endif + +#ifndef AL_SOFT_source_latency +#define AL_SOFT_source_latency 1 +#define AL_SAMPLE_OFFSET_LATENCY_SOFT 0x1200 +#define AL_SEC_OFFSET_LATENCY_SOFT 0x1201 +typedef int64_t ALint64SOFT; +typedef uint64_t ALuint64SOFT; +typedef void (AL_APIENTRY*LPALSOURCEDSOFT)(ALuint,ALenum,ALdouble); +typedef void (AL_APIENTRY*LPALSOURCE3DSOFT)(ALuint,ALenum,ALdouble,ALdouble,ALdouble); +typedef void (AL_APIENTRY*LPALSOURCEDVSOFT)(ALuint,ALenum,const ALdouble*); +typedef void (AL_APIENTRY*LPALGETSOURCEDSOFT)(ALuint,ALenum,ALdouble*); +typedef void (AL_APIENTRY*LPALGETSOURCE3DSOFT)(ALuint,ALenum,ALdouble*,ALdouble*,ALdouble*); +typedef void (AL_APIENTRY*LPALGETSOURCEDVSOFT)(ALuint,ALenum,ALdouble*); +typedef void (AL_APIENTRY*LPALSOURCEI64SOFT)(ALuint,ALenum,ALint64SOFT); +typedef void (AL_APIENTRY*LPALSOURCE3I64SOFT)(ALuint,ALenum,ALint64SOFT,ALint64SOFT,ALint64SOFT); +typedef void (AL_APIENTRY*LPALSOURCEI64VSOFT)(ALuint,ALenum,const ALint64SOFT*); +typedef void (AL_APIENTRY*LPALGETSOURCEI64SOFT)(ALuint,ALenum,ALint64SOFT*); +typedef void (AL_APIENTRY*LPALGETSOURCE3I64SOFT)(ALuint,ALenum,ALint64SOFT*,ALint64SOFT*,ALint64SOFT*); +typedef void (AL_APIENTRY*LPALGETSOURCEI64VSOFT)(ALuint,ALenum,ALint64SOFT*); +#ifdef AL_ALEXT_PROTOTYPES +AL_API void AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value); +AL_API void AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3); +AL_API void AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values); +AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value); +AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3); +AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values); +AL_API void AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value); +AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3); +AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values); +AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value); +AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3); +AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values); +#endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/code/AL/altypes.h b/code/AL/altypes.h deleted file mode 100644 index 3ec959fd..00000000 --- a/code/AL/altypes.h +++ /dev/null @@ -1,352 +0,0 @@ -#ifndef _AL_TYPES_H_ -#define _AL_TYPES_H_ - -/* define platform type */ -#if !defined(MACINTOSH_AL) && !defined(LINUX_AL) && !defined(WINDOWS_AL) - #ifdef __APPLE__ - #define MACINTOSH_AL - #else - #ifdef _WIN32 - #define WINDOWS_AL - #else - #define LINUX_AL - #endif - #endif -#endif - -/** OpenAL bool type. */ -typedef char ALboolean; - -/** OpenAL 8bit signed byte. */ -typedef char ALbyte; - -/** OpenAL 8bit unsigned byte. */ -typedef unsigned char ALubyte; - -/** OpenAL 8bit char */ -typedef char ALchar; - -/** OpenAL 16bit signed short integer type. */ -typedef short ALshort; - -/** OpenAL 16bit unsigned short integer type. */ -typedef unsigned short ALushort; - -/** OpenAL 32bit unsigned integer type. */ -typedef unsigned int ALuint; - -/** OpenAL 32bit signed integer type. */ -typedef int ALint; - -/** OpenAL 32bit floating point type. */ -typedef float ALfloat; - -/** OpenAL 64bit double point type. */ -typedef double ALdouble; - -/** OpenAL 32bit type. */ -typedef int ALsizei; - -/** OpenAL void type (for params, not returns). */ -typedef void ALvoid; - -/** OpenAL enumerations. */ -typedef int ALenum; - -/** OpenAL bitfields. */ -typedef unsigned int ALbitfield; - -/** OpenAL clamped float. */ -typedef ALfloat ALclampf; - -/** Openal clamped double. */ -typedef ALdouble ALclampd; - -/* Enumerant values begin at column 50. No tabs. */ - -/* bad value */ -#define AL_INVALID -1 - -#define AL_NONE 0 - -/* Boolean False. */ -#define AL_FALSE 0 - -/** Boolean True. */ -#define AL_TRUE 1 - -/** Indicate Source has relative coordinates. */ -#define AL_SOURCE_RELATIVE 0x202 - - - -/** - * Directional source, inner cone angle, in degrees. - * Range: [0-360] - * Default: 360 - */ -#define AL_CONE_INNER_ANGLE 0x1001 - -/** - * Directional source, outer cone angle, in degrees. - * Range: [0-360] - * Default: 360 - */ -#define AL_CONE_OUTER_ANGLE 0x1002 - -/** - * Specify the pitch to be applied, either at source, - * or on mixer results, at listener. - * Range: [0.5-2.0] - * Default: 1.0 - */ -#define AL_PITCH 0x1003 - -/** - * Specify the current location in three dimensional space. - * OpenAL, like OpenGL, uses a right handed coordinate system, - * where in a frontal default view X (thumb) points right, - * Y points up (index finger), and Z points towards the - * viewer/camera (middle finger). - * To switch from a left handed coordinate system, flip the - * sign on the Z coordinate. - * Listener position is always in the world coordinate system. - */ -#define AL_POSITION 0x1004 - -/** Specify the current direction. */ -#define AL_DIRECTION 0x1005 - -/** Specify the current velocity in three dimensional space. */ -#define AL_VELOCITY 0x1006 - -/** - * Indicate whether source is looping. - * Type: ALboolean? - * Range: [AL_TRUE, AL_FALSE] - * Default: FALSE. - */ -#define AL_LOOPING 0x1007 - -/** - * Indicate the buffer to provide sound samples. - * Type: ALuint. - * Range: any valid Buffer id. - */ -#define AL_BUFFER 0x1009 - -/** - * Indicate the gain (volume amplification) applied. - * Type: ALfloat. - * Range: ]0.0- ] - * A value of 1.0 means un-attenuated/unchanged. - * Each division by 2 equals an attenuation of -6dB. - * Each multiplicaton with 2 equals an amplification of +6dB. - * A value of 0.0 is meaningless with respect to a logarithmic - * scale; it is interpreted as zero volume - the channel - * is effectively disabled. - */ -#define AL_GAIN 0x100A - -/* - * Indicate minimum source attenuation - * Type: ALfloat - * Range: [0.0 - 1.0] - * - * Logarthmic - */ -#define AL_MIN_GAIN 0x100D - -/** - * Indicate maximum source attenuation - * Type: ALfloat - * Range: [0.0 - 1.0] - * - * Logarthmic - */ -#define AL_MAX_GAIN 0x100E - -/** - * Indicate listener orientation. - * - * at/up - */ -#define AL_ORIENTATION 0x100F - -/** - * Specify the channel mask. (Creative) - * Type: ALuint - * Range: [0 - 255] - */ -#define AL_CHANNEL_MASK 0x3000 - - -/** - * Source state information. - */ -#define AL_SOURCE_STATE 0x1010 -#define AL_INITIAL 0x1011 -#define AL_PLAYING 0x1012 -#define AL_PAUSED 0x1013 -#define AL_STOPPED 0x1014 - -/** - * Buffer Queue params - */ -#define AL_BUFFERS_QUEUED 0x1015 -#define AL_BUFFERS_PROCESSED 0x1016 - -/** - * Source buffer position information - */ -#define AL_SEC_OFFSET 0x1024 -#define AL_SAMPLE_OFFSET 0x1025 -#define AL_BYTE_OFFSET 0x1026 - -/* - * Source type (Static, Streaming or undetermined) - * Source is Static if a Buffer has been attached using AL_BUFFER - * Source is Streaming if one or more Buffers have been attached using alSourceQueueBuffers - * Source is undetermined when it has the NULL buffer attached - */ -#define AL_SOURCE_TYPE 0x1027 -#define AL_STATIC 0x1028 -#define AL_STREAMING 0x1029 -#define AL_UNDETERMINED 0x1030 - -/** Sound samples: format specifier. */ -#define AL_FORMAT_MONO8 0x1100 -#define AL_FORMAT_MONO16 0x1101 -#define AL_FORMAT_STEREO8 0x1102 -#define AL_FORMAT_STEREO16 0x1103 - -/** - * source specific reference distance - * Type: ALfloat - * Range: 0.0 - +inf - * - * At 0.0, no distance attenuation occurs. Default is - * 1.0. - */ -#define AL_REFERENCE_DISTANCE 0x1020 - -/** - * source specific rolloff factor - * Type: ALfloat - * Range: 0.0 - +inf - * - */ -#define AL_ROLLOFF_FACTOR 0x1021 - -/** - * Directional source, outer cone gain. - * - * Default: 0.0 - * Range: [0.0 - 1.0] - * Logarithmic - */ -#define AL_CONE_OUTER_GAIN 0x1022 - -/** - * Indicate distance above which sources are not - * attenuated using the inverse clamped distance model. - * - * Default: +inf - * Type: ALfloat - * Range: 0.0 - +inf - */ -#define AL_MAX_DISTANCE 0x1023 - -/** - * Sound samples: frequency, in units of Hertz [Hz]. - * This is the number of samples per second. Half of the - * sample frequency marks the maximum significant - * frequency component. - */ -#define AL_FREQUENCY 0x2001 -#define AL_BITS 0x2002 -#define AL_CHANNELS 0x2003 -#define AL_SIZE 0x2004 -#define AL_DATA 0x2005 - -/** - * Buffer state. - * - * Not supported for public use (yet). - */ -#define AL_UNUSED 0x2010 -#define AL_PENDING 0x2011 -#define AL_PROCESSED 0x2012 - - -/** Errors: No Error. */ -#define AL_NO_ERROR AL_FALSE - -/** - * Invalid Name paramater passed to AL call. - */ -#define AL_INVALID_NAME 0xA001 - -/** - * Invalid parameter passed to AL call. - */ -#define AL_ILLEGAL_ENUM 0xA002 -#define AL_INVALID_ENUM 0xA002 - -/** - * Invalid enum parameter value. - */ -#define AL_INVALID_VALUE 0xA003 - -/** - * Illegal call. - */ -#define AL_ILLEGAL_COMMAND 0xA004 -#define AL_INVALID_OPERATION 0xA004 - - -/** - * No mojo. - */ -#define AL_OUT_OF_MEMORY 0xA005 - - -/** Context strings: Vendor Name. */ -#define AL_VENDOR 0xB001 -#define AL_VERSION 0xB002 -#define AL_RENDERER 0xB003 -#define AL_EXTENSIONS 0xB004 - -/** Global tweakage. */ - -/** - * Doppler scale. Default 1.0 - */ -#define AL_DOPPLER_FACTOR 0xC000 - -/** - * Tweaks speed of propagation. - */ -#define AL_DOPPLER_VELOCITY 0xC001 - -/** - * Speed of Sound in units per second - */ -#define AL_SPEED_OF_SOUND 0xC003 - -/** - * Distance models - * - * used in conjunction with DistanceModel - * - * implicit: NONE, which disances distance attenuation. - */ -#define AL_DISTANCE_MODEL 0xD000 -#define AL_INVERSE_DISTANCE 0xD001 -#define AL_INVERSE_DISTANCE_CLAMPED 0xD002 -#define AL_LINEAR_DISTANCE 0xD003 -#define AL_LINEAR_DISTANCE_CLAMPED 0xD004 -#define AL_EXPONENT_DISTANCE 0xD005 -#define AL_EXPONENT_DISTANCE_CLAMPED 0xD006 - -#endif diff --git a/code/AL/alut.h b/code/AL/alut.h deleted file mode 100644 index e29ae582..00000000 --- a/code/AL/alut.h +++ /dev/null @@ -1,90 +0,0 @@ -#ifndef _ALUT_H_ -#define _ALUT_H_ - -/* define platform type */ -#if !defined(MACINTOSH_AL) && !defined(LINUX_AL) && !defined(WINDOWS_AL) - #ifdef __APPLE__ - #define MACINTOSH_AL - #else - #ifdef _WIN32 - #define WINDOWS_AL - #else - #define LINUX_AL - #endif - #endif -#endif - -#include "altypes.h" - -#ifdef _WIN32 -#define ALUTAPI -#define ALUTAPIENTRY __cdecl -#define AL_CALLBACK -#else /* _WIN32 */ - -#ifdef TARGET_OS_MAC -#if TARGET_OS_MAC -#pragma export on -#endif /* TARGET_OS_MAC */ -#endif /* TARGET_OS_MAC */ - -#ifndef ALUTAPI -#define ALUTAPI -#endif - -#ifndef ALUTAPIENTRY -#define ALUTAPIENTRY -#endif - -#ifndef AL_CALLBACK -#define AL_CALLBACK -#endif - -#endif /* _WIN32 */ - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef ALUT_NO_PROTOTYPES - -ALUTAPI void ALUTAPIENTRY alutInit(int *argc, char *argv[]); -ALUTAPI void ALUTAPIENTRY alutExit(ALvoid); - -#ifndef MACINTOSH_AL -/* Windows and Linux versions have a loop parameter, Macintosh doesn't */ -ALUTAPI void ALUTAPIENTRY alutLoadWAVFile(ALbyte *file, ALenum *format, ALvoid **data, ALsizei *size, ALsizei *freq, ALboolean *loop); -ALUTAPI void ALUTAPIENTRY alutLoadWAVMemory(ALbyte *memory, ALenum *format, ALvoid **data, ALsizei *size, ALsizei *freq, ALboolean *loop); -#else -ALUTAPI void ALUTAPIENTRY alutLoadWAVFile(ALbyte *file, ALenum *format, ALvoid **data, ALsizei *size, ALsizei *freq); -ALUTAPI void ALUTAPIENTRY alutLoadWAVMemory(ALbyte *memory, ALenum *format, ALvoid **data, ALsizei *size, ALsizei *freq); -#endif - -ALUTAPI void ALUTAPIENTRY alutUnloadWAV(ALenum format, ALvoid *data, ALsizei size, ALsizei freq); - -#else /* ALUT_NO_PROTOTYPES */ - - void (ALUTAPIENTRY *alutInit)( int *argc, char *argv[] ); - void (ALUTAPIENTRY *alutExit)( ALvoid ); -#ifndef MACINTOSH_AL - void (ALUTAPIENTRY *alutLoadWAVFile)( ALbyte *file,ALenum *format,ALvoid **data,ALsizei *size,ALsizei *freq,ALboolean *loop ); - void (ALUTAPIENTRY *alutLoadWAVMemory)( ALbyte *memory,ALenum *format,ALvoid **data,ALsizei *size,ALsizei *freq,ALboolean *loop ); -#else - void (ALUTAPIENTRY *alutLoadWAVFile( ALbyte *file,ALenum *format,ALvoid **data,ALsizei *size,ALsizei *freq ); - void (ALUTAPIENTRY *alutLoadWAVMemory)( ALbyte *memory,ALenum *format,ALvoid **data,ALsizei *size,ALsizei *freq ); -#endif - void (ALUTAPIENTRY *alutUnloadWAV)( ALenum format,ALvoid *data,ALsizei size,ALsizei freq ); - -#endif /* ALUT_NO_PROTOTYPES */ - -#ifdef TARGET_OS_MAC -#if TARGET_OS_MAC -#pragma export off -#endif /* TARGET_OS_MAC */ -#endif /* TARGET_OS_MAC */ - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/code/AL/efx-creative.h b/code/AL/efx-creative.h new file mode 100644 index 00000000..0a04c982 --- /dev/null +++ b/code/AL/efx-creative.h @@ -0,0 +1,3 @@ +/* The tokens that would be defined here are already defined in efx.h. This + * empty file is here to provide compatibility with Windows-based projects + * that would include it. */ diff --git a/code/AL/efx-presets.h b/code/AL/efx-presets.h new file mode 100644 index 00000000..86dcbda2 --- /dev/null +++ b/code/AL/efx-presets.h @@ -0,0 +1,402 @@ +/* Reverb presets for EFX */ + +#ifndef EFX_PRESETS_H +#define EFX_PRESETS_H + +#ifndef EFXEAXREVERBPROPERTIES_DEFINED +#define EFXEAXREVERBPROPERTIES_DEFINED +typedef struct { + float flDensity; + float flDiffusion; + float flGain; + float flGainHF; + float flGainLF; + float flDecayTime; + float flDecayHFRatio; + float flDecayLFRatio; + float flReflectionsGain; + float flReflectionsDelay; + float flReflectionsPan[3]; + float flLateReverbGain; + float flLateReverbDelay; + float flLateReverbPan[3]; + float flEchoTime; + float flEchoDepth; + float flModulationTime; + float flModulationDepth; + float flAirAbsorptionGainHF; + float flHFReference; + float flLFReference; + float flRoomRolloffFactor; + int iDecayHFLimit; +} EFXEAXREVERBPROPERTIES, *LPEFXEAXREVERBPROPERTIES; +#endif + +/* Default Presets */ + +#define EFX_REVERB_PRESET_GENERIC \ + { 1.0000f, 1.0000f, 0.3162f, 0.8913f, 1.0000f, 1.4900f, 0.8300f, 1.0000f, 0.0500f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_PADDEDCELL \ + { 0.1715f, 1.0000f, 0.3162f, 0.0010f, 1.0000f, 0.1700f, 0.1000f, 1.0000f, 0.2500f, 0.0010f, { 0.0000f, 0.0000f, 0.0000f }, 1.2691f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ROOM \ + { 0.4287f, 1.0000f, 0.3162f, 0.5929f, 1.0000f, 0.4000f, 0.8300f, 1.0000f, 0.1503f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 1.0629f, 0.0030f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_BATHROOM \ + { 0.1715f, 1.0000f, 0.3162f, 0.2512f, 1.0000f, 1.4900f, 0.5400f, 1.0000f, 0.6531f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 3.2734f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_LIVINGROOM \ + { 0.9766f, 1.0000f, 0.3162f, 0.0010f, 1.0000f, 0.5000f, 0.1000f, 1.0000f, 0.2051f, 0.0030f, { 0.0000f, 0.0000f, 0.0000f }, 0.2805f, 0.0040f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_STONEROOM \ + { 1.0000f, 1.0000f, 0.3162f, 0.7079f, 1.0000f, 2.3100f, 0.6400f, 1.0000f, 0.4411f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1003f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_AUDITORIUM \ + { 1.0000f, 1.0000f, 0.3162f, 0.5781f, 1.0000f, 4.3200f, 0.5900f, 1.0000f, 0.4032f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.7170f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CONCERTHALL \ + { 1.0000f, 1.0000f, 0.3162f, 0.5623f, 1.0000f, 3.9200f, 0.7000f, 1.0000f, 0.2427f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.9977f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CAVE \ + { 1.0000f, 1.0000f, 0.3162f, 1.0000f, 1.0000f, 2.9100f, 1.3000f, 1.0000f, 0.5000f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.7063f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_ARENA \ + { 1.0000f, 1.0000f, 0.3162f, 0.4477f, 1.0000f, 7.2400f, 0.3300f, 1.0000f, 0.2612f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.0186f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_HANGAR \ + { 1.0000f, 1.0000f, 0.3162f, 0.3162f, 1.0000f, 10.0500f, 0.2300f, 1.0000f, 0.5000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.2560f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CARPETEDHALLWAY \ + { 0.4287f, 1.0000f, 0.3162f, 0.0100f, 1.0000f, 0.3000f, 0.1000f, 1.0000f, 0.1215f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 0.1531f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_HALLWAY \ + { 0.3645f, 1.0000f, 0.3162f, 0.7079f, 1.0000f, 1.4900f, 0.5900f, 1.0000f, 0.2458f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.6615f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_STONECORRIDOR \ + { 1.0000f, 1.0000f, 0.3162f, 0.7612f, 1.0000f, 2.7000f, 0.7900f, 1.0000f, 0.2472f, 0.0130f, { 0.0000f, 0.0000f, 0.0000f }, 1.5758f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ALLEY \ + { 1.0000f, 0.3000f, 0.3162f, 0.7328f, 1.0000f, 1.4900f, 0.8600f, 1.0000f, 0.2500f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.9954f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 0.9500f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FOREST \ + { 1.0000f, 0.3000f, 0.3162f, 0.0224f, 1.0000f, 1.4900f, 0.5400f, 1.0000f, 0.0525f, 0.1620f, { 0.0000f, 0.0000f, 0.0000f }, 0.7682f, 0.0880f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CITY \ + { 1.0000f, 0.5000f, 0.3162f, 0.3981f, 1.0000f, 1.4900f, 0.6700f, 1.0000f, 0.0730f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.1427f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_MOUNTAINS \ + { 1.0000f, 0.2700f, 0.3162f, 0.0562f, 1.0000f, 1.4900f, 0.2100f, 1.0000f, 0.0407f, 0.3000f, { 0.0000f, 0.0000f, 0.0000f }, 0.1919f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_QUARRY \ + { 1.0000f, 1.0000f, 0.3162f, 0.3162f, 1.0000f, 1.4900f, 0.8300f, 1.0000f, 0.0000f, 0.0610f, { 0.0000f, 0.0000f, 0.0000f }, 1.7783f, 0.0250f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 0.7000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_PLAIN \ + { 1.0000f, 0.2100f, 0.3162f, 0.1000f, 1.0000f, 1.4900f, 0.5000f, 1.0000f, 0.0585f, 0.1790f, { 0.0000f, 0.0000f, 0.0000f }, 0.1089f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_PARKINGLOT \ + { 1.0000f, 1.0000f, 0.3162f, 1.0000f, 1.0000f, 1.6500f, 1.5000f, 1.0000f, 0.2082f, 0.0080f, { 0.0000f, 0.0000f, 0.0000f }, 0.2652f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_SEWERPIPE \ + { 0.3071f, 0.8000f, 0.3162f, 0.3162f, 1.0000f, 2.8100f, 0.1400f, 1.0000f, 1.6387f, 0.0140f, { 0.0000f, 0.0000f, 0.0000f }, 3.2471f, 0.0210f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_UNDERWATER \ + { 0.3645f, 1.0000f, 0.3162f, 0.0100f, 1.0000f, 1.4900f, 0.1000f, 1.0000f, 0.5963f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 7.0795f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 1.1800f, 0.3480f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_DRUGGED \ + { 0.4287f, 0.5000f, 0.3162f, 1.0000f, 1.0000f, 8.3900f, 1.3900f, 1.0000f, 0.8760f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 3.1081f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 1.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_DIZZY \ + { 0.3645f, 0.6000f, 0.3162f, 0.6310f, 1.0000f, 17.2300f, 0.5600f, 1.0000f, 0.1392f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.4937f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.8100f, 0.3100f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_PSYCHOTIC \ + { 0.0625f, 0.5000f, 0.3162f, 0.8404f, 1.0000f, 7.5600f, 0.9100f, 1.0000f, 0.4864f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 2.4378f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 4.0000f, 1.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +/* Castle Presets */ + +#define EFX_REVERB_PRESET_CASTLE_SMALLROOM \ + { 1.0000f, 0.8900f, 0.3162f, 0.3981f, 0.1000f, 1.2200f, 0.8300f, 0.3100f, 0.8913f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CASTLE_SHORTPASSAGE \ + { 1.0000f, 0.8900f, 0.3162f, 0.3162f, 0.1000f, 2.3200f, 0.8300f, 0.3100f, 0.8913f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CASTLE_MEDIUMROOM \ + { 1.0000f, 0.9300f, 0.3162f, 0.2818f, 0.1000f, 2.0400f, 0.8300f, 0.4600f, 0.6310f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 1.5849f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1550f, 0.0300f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CASTLE_LARGEROOM \ + { 1.0000f, 0.8200f, 0.3162f, 0.2818f, 0.1259f, 2.5300f, 0.8300f, 0.5000f, 0.4467f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.1850f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CASTLE_LONGPASSAGE \ + { 1.0000f, 0.8900f, 0.3162f, 0.3981f, 0.1000f, 3.4200f, 0.8300f, 0.3100f, 0.8913f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CASTLE_HALL \ + { 1.0000f, 0.8100f, 0.3162f, 0.2818f, 0.1778f, 3.1400f, 0.7900f, 0.6200f, 0.1778f, 0.0560f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CASTLE_CUPBOARD \ + { 1.0000f, 0.8900f, 0.3162f, 0.2818f, 0.1000f, 0.6700f, 0.8700f, 0.3100f, 1.4125f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 3.5481f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CASTLE_COURTYARD \ + { 1.0000f, 0.4200f, 0.3162f, 0.4467f, 0.1995f, 2.1300f, 0.6100f, 0.2300f, 0.2239f, 0.1600f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0360f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.3700f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_CASTLE_ALCOVE \ + { 1.0000f, 0.8900f, 0.3162f, 0.5012f, 0.1000f, 1.6400f, 0.8700f, 0.3100f, 1.0000f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 0.1380f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 5168.6001f, 139.5000f, 0.0000f, 0x1 } + +/* Factory Presets */ + +#define EFX_REVERB_PRESET_FACTORY_SMALLROOM \ + { 0.3645f, 0.8200f, 0.3162f, 0.7943f, 0.5012f, 1.7200f, 0.6500f, 1.3100f, 0.7079f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.7783f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.1190f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FACTORY_SHORTPASSAGE \ + { 0.3645f, 0.6400f, 0.2512f, 0.7943f, 0.5012f, 2.5300f, 0.6500f, 1.3100f, 1.0000f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.1350f, 0.2300f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FACTORY_MEDIUMROOM \ + { 0.4287f, 0.8200f, 0.2512f, 0.7943f, 0.5012f, 2.7600f, 0.6500f, 1.3100f, 0.2818f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1740f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FACTORY_LARGEROOM \ + { 0.4287f, 0.7500f, 0.2512f, 0.7079f, 0.6310f, 4.2400f, 0.5100f, 1.3100f, 0.1778f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.2310f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FACTORY_LONGPASSAGE \ + { 0.3645f, 0.6400f, 0.2512f, 0.7943f, 0.5012f, 4.0600f, 0.6500f, 1.3100f, 1.0000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0370f, { 0.0000f, 0.0000f, 0.0000f }, 0.1350f, 0.2300f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FACTORY_HALL \ + { 0.4287f, 0.7500f, 0.3162f, 0.7079f, 0.6310f, 7.4300f, 0.5100f, 1.3100f, 0.0631f, 0.0730f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0270f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FACTORY_CUPBOARD \ + { 0.3071f, 0.6300f, 0.2512f, 0.7943f, 0.5012f, 0.4900f, 0.6500f, 1.3100f, 1.2589f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.1070f, 0.0700f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FACTORY_COURTYARD \ + { 0.3071f, 0.5700f, 0.3162f, 0.3162f, 0.6310f, 2.3200f, 0.2900f, 0.5600f, 0.2239f, 0.1400f, { 0.0000f, 0.0000f, 0.0000f }, 0.3981f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2900f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_FACTORY_ALCOVE \ + { 0.3645f, 0.5900f, 0.2512f, 0.7943f, 0.5012f, 3.1400f, 0.6500f, 1.3100f, 1.4125f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.1140f, 0.1000f, 0.2500f, 0.0000f, 0.9943f, 3762.6001f, 362.5000f, 0.0000f, 0x1 } + +/* Ice Palace Presets */ + +#define EFX_REVERB_PRESET_ICEPALACE_SMALLROOM \ + { 1.0000f, 0.8400f, 0.3162f, 0.5623f, 0.2818f, 1.5100f, 1.5300f, 0.2700f, 0.8913f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1640f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ICEPALACE_SHORTPASSAGE \ + { 1.0000f, 0.7500f, 0.3162f, 0.5623f, 0.2818f, 1.7900f, 1.4600f, 0.2800f, 0.5012f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0190f, { 0.0000f, 0.0000f, 0.0000f }, 0.1770f, 0.0900f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ICEPALACE_MEDIUMROOM \ + { 1.0000f, 0.8700f, 0.3162f, 0.5623f, 0.4467f, 2.2200f, 1.5300f, 0.3200f, 0.3981f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0270f, { 0.0000f, 0.0000f, 0.0000f }, 0.1860f, 0.1200f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ICEPALACE_LARGEROOM \ + { 1.0000f, 0.8100f, 0.3162f, 0.5623f, 0.4467f, 3.1400f, 1.5300f, 0.3200f, 0.2512f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0270f, { 0.0000f, 0.0000f, 0.0000f }, 0.2140f, 0.1100f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ICEPALACE_LONGPASSAGE \ + { 1.0000f, 0.7700f, 0.3162f, 0.5623f, 0.3981f, 3.0100f, 1.4600f, 0.2800f, 0.7943f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0250f, { 0.0000f, 0.0000f, 0.0000f }, 0.1860f, 0.0400f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ICEPALACE_HALL \ + { 1.0000f, 0.7600f, 0.3162f, 0.4467f, 0.5623f, 5.4900f, 1.5300f, 0.3800f, 0.1122f, 0.0540f, { 0.0000f, 0.0000f, 0.0000f }, 0.6310f, 0.0520f, { 0.0000f, 0.0000f, 0.0000f }, 0.2260f, 0.1100f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ICEPALACE_CUPBOARD \ + { 1.0000f, 0.8300f, 0.3162f, 0.5012f, 0.2239f, 0.7600f, 1.5300f, 0.2600f, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.1430f, 0.0800f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ICEPALACE_COURTYARD \ + { 1.0000f, 0.5900f, 0.3162f, 0.2818f, 0.3162f, 2.0400f, 1.2000f, 0.3800f, 0.3162f, 0.1730f, { 0.0000f, 0.0000f, 0.0000f }, 0.3162f, 0.0430f, { 0.0000f, 0.0000f, 0.0000f }, 0.2350f, 0.4800f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_ICEPALACE_ALCOVE \ + { 1.0000f, 0.8400f, 0.3162f, 0.5623f, 0.2818f, 2.7600f, 1.4600f, 0.2800f, 1.1220f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1610f, 0.0900f, 0.2500f, 0.0000f, 0.9943f, 12428.5000f, 99.6000f, 0.0000f, 0x1 } + +/* Space Station Presets */ + +#define EFX_REVERB_PRESET_SPACESTATION_SMALLROOM \ + { 0.2109f, 0.7000f, 0.3162f, 0.7079f, 0.8913f, 1.7200f, 0.8200f, 0.5500f, 0.7943f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0130f, { 0.0000f, 0.0000f, 0.0000f }, 0.1880f, 0.2600f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPACESTATION_SHORTPASSAGE \ + { 0.2109f, 0.8700f, 0.3162f, 0.6310f, 0.8913f, 3.5700f, 0.5000f, 0.5500f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.1720f, 0.2000f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPACESTATION_MEDIUMROOM \ + { 0.2109f, 0.7500f, 0.3162f, 0.6310f, 0.8913f, 3.0100f, 0.5000f, 0.5500f, 0.3981f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0350f, { 0.0000f, 0.0000f, 0.0000f }, 0.2090f, 0.3100f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPACESTATION_LARGEROOM \ + { 0.3645f, 0.8100f, 0.3162f, 0.6310f, 0.8913f, 3.8900f, 0.3800f, 0.6100f, 0.3162f, 0.0560f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0350f, { 0.0000f, 0.0000f, 0.0000f }, 0.2330f, 0.2800f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPACESTATION_LONGPASSAGE \ + { 0.4287f, 0.8200f, 0.3162f, 0.6310f, 0.8913f, 4.6200f, 0.6200f, 0.5500f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0310f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2300f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPACESTATION_HALL \ + { 0.4287f, 0.8700f, 0.3162f, 0.6310f, 0.8913f, 7.1100f, 0.3800f, 0.6100f, 0.1778f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.6310f, 0.0470f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2500f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPACESTATION_CUPBOARD \ + { 0.1715f, 0.5600f, 0.3162f, 0.7079f, 0.8913f, 0.7900f, 0.8100f, 0.5500f, 1.4125f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.7783f, 0.0180f, { 0.0000f, 0.0000f, 0.0000f }, 0.1810f, 0.3100f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPACESTATION_ALCOVE \ + { 0.2109f, 0.7800f, 0.3162f, 0.7079f, 0.8913f, 1.1600f, 0.8100f, 0.5500f, 1.4125f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0180f, { 0.0000f, 0.0000f, 0.0000f }, 0.1920f, 0.2100f, 0.2500f, 0.0000f, 0.9943f, 3316.1001f, 458.2000f, 0.0000f, 0x1 } + +/* Wooden Galleon Presets */ + +#define EFX_REVERB_PRESET_WOODEN_SMALLROOM \ + { 1.0000f, 1.0000f, 0.3162f, 0.1122f, 0.3162f, 0.7900f, 0.3200f, 0.8700f, 1.0000f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_WOODEN_SHORTPASSAGE \ + { 1.0000f, 1.0000f, 0.3162f, 0.1259f, 0.3162f, 1.7500f, 0.5000f, 0.8700f, 0.8913f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.6310f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_WOODEN_MEDIUMROOM \ + { 1.0000f, 1.0000f, 0.3162f, 0.1000f, 0.2818f, 1.4700f, 0.4200f, 0.8200f, 0.8913f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_WOODEN_LARGEROOM \ + { 1.0000f, 1.0000f, 0.3162f, 0.0891f, 0.2818f, 2.6500f, 0.3300f, 0.8200f, 0.8913f, 0.0660f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_WOODEN_LONGPASSAGE \ + { 1.0000f, 1.0000f, 0.3162f, 0.1000f, 0.3162f, 1.9900f, 0.4000f, 0.7900f, 1.0000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.4467f, 0.0360f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_WOODEN_HALL \ + { 1.0000f, 1.0000f, 0.3162f, 0.0794f, 0.2818f, 3.4500f, 0.3000f, 0.8200f, 0.8913f, 0.0880f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0630f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_WOODEN_CUPBOARD \ + { 1.0000f, 1.0000f, 0.3162f, 0.1413f, 0.3162f, 0.5600f, 0.4600f, 0.9100f, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0280f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_WOODEN_COURTYARD \ + { 1.0000f, 0.6500f, 0.3162f, 0.0794f, 0.3162f, 1.7900f, 0.3500f, 0.7900f, 0.5623f, 0.1230f, { 0.0000f, 0.0000f, 0.0000f }, 0.1000f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_WOODEN_ALCOVE \ + { 1.0000f, 1.0000f, 0.3162f, 0.1259f, 0.3162f, 1.2200f, 0.6200f, 0.9100f, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 4705.0000f, 99.6000f, 0.0000f, 0x1 } + +/* Sports Presets */ + +#define EFX_REVERB_PRESET_SPORT_EMPTYSTADIUM \ + { 1.0000f, 1.0000f, 0.3162f, 0.4467f, 0.7943f, 6.2600f, 0.5100f, 1.1000f, 0.0631f, 0.1830f, { 0.0000f, 0.0000f, 0.0000f }, 0.3981f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPORT_SQUASHCOURT \ + { 1.0000f, 0.7500f, 0.3162f, 0.3162f, 0.7943f, 2.2200f, 0.9100f, 1.1600f, 0.4467f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.1260f, 0.1900f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPORT_SMALLSWIMMINGPOOL \ + { 1.0000f, 0.7000f, 0.3162f, 0.7943f, 0.8913f, 2.7600f, 1.2500f, 1.1400f, 0.6310f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1790f, 0.1500f, 0.8950f, 0.1900f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_SPORT_LARGESWIMMINGPOOL \ + { 1.0000f, 0.8200f, 0.3162f, 0.7943f, 1.0000f, 5.4900f, 1.3100f, 1.1400f, 0.4467f, 0.0390f, { 0.0000f, 0.0000f, 0.0000f }, 0.5012f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2220f, 0.5500f, 1.1590f, 0.2100f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_SPORT_GYMNASIUM \ + { 1.0000f, 0.8100f, 0.3162f, 0.4467f, 0.8913f, 3.1400f, 1.0600f, 1.3500f, 0.3981f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.5623f, 0.0450f, { 0.0000f, 0.0000f, 0.0000f }, 0.1460f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPORT_FULLSTADIUM \ + { 1.0000f, 1.0000f, 0.3162f, 0.0708f, 0.7943f, 5.2500f, 0.1700f, 0.8000f, 0.1000f, 0.1880f, { 0.0000f, 0.0000f, 0.0000f }, 0.2818f, 0.0380f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SPORT_STADIUMTANNOY \ + { 1.0000f, 0.7800f, 0.3162f, 0.5623f, 0.5012f, 2.5300f, 0.8800f, 0.6800f, 0.2818f, 0.2300f, { 0.0000f, 0.0000f, 0.0000f }, 0.5012f, 0.0630f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +/* Prefab Presets */ + +#define EFX_REVERB_PRESET_PREFAB_WORKSHOP \ + { 0.4287f, 1.0000f, 0.3162f, 0.1413f, 0.3981f, 0.7600f, 1.0000f, 1.0000f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_PREFAB_SCHOOLROOM \ + { 0.4022f, 0.6900f, 0.3162f, 0.6310f, 0.5012f, 0.9800f, 0.4500f, 0.1800f, 1.4125f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.0950f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_PREFAB_PRACTISEROOM \ + { 0.4022f, 0.8700f, 0.3162f, 0.3981f, 0.5012f, 1.1200f, 0.5600f, 0.1800f, 1.2589f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0110f, { 0.0000f, 0.0000f, 0.0000f }, 0.0950f, 0.1400f, 0.2500f, 0.0000f, 0.9943f, 7176.8999f, 211.2000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_PREFAB_OUTHOUSE \ + { 1.0000f, 0.8200f, 0.3162f, 0.1122f, 0.1585f, 1.3800f, 0.3800f, 0.3500f, 0.8913f, 0.0240f, { 0.0000f, 0.0000f, -0.0000f }, 0.6310f, 0.0440f, { 0.0000f, 0.0000f, 0.0000f }, 0.1210f, 0.1700f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_PREFAB_CARAVAN \ + { 1.0000f, 1.0000f, 0.3162f, 0.0891f, 0.1259f, 0.4300f, 1.5000f, 1.0000f, 1.0000f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 1.9953f, 0.0120f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +/* Dome and Pipe Presets */ + +#define EFX_REVERB_PRESET_DOME_TOMB \ + { 1.0000f, 0.7900f, 0.3162f, 0.3548f, 0.2239f, 4.1800f, 0.2100f, 0.1000f, 0.3868f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 1.6788f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.1770f, 0.1900f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_PIPE_SMALL \ + { 1.0000f, 1.0000f, 0.3162f, 0.3548f, 0.2239f, 5.0400f, 0.1000f, 0.1000f, 0.5012f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 2.5119f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_DOME_SAINTPAULS \ + { 1.0000f, 0.8700f, 0.3162f, 0.3548f, 0.2239f, 10.4800f, 0.1900f, 0.1000f, 0.1778f, 0.0900f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0420f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.1200f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_PIPE_LONGTHIN \ + { 0.2560f, 0.9100f, 0.3162f, 0.4467f, 0.2818f, 9.2100f, 0.1800f, 0.1000f, 0.7079f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_PIPE_LARGE \ + { 1.0000f, 1.0000f, 0.3162f, 0.3548f, 0.2239f, 8.4500f, 0.1000f, 0.1000f, 0.3981f, 0.0460f, { 0.0000f, 0.0000f, 0.0000f }, 1.5849f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_PIPE_RESONANT \ + { 0.1373f, 0.9100f, 0.3162f, 0.4467f, 0.2818f, 6.8100f, 0.1800f, 0.1000f, 0.7079f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.0000f, 0.0220f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 20.0000f, 0.0000f, 0x0 } + +/* Outdoors Presets */ + +#define EFX_REVERB_PRESET_OUTDOORS_BACKYARD \ + { 1.0000f, 0.4500f, 0.3162f, 0.2512f, 0.5012f, 1.1200f, 0.3400f, 0.4600f, 0.4467f, 0.0690f, { 0.0000f, 0.0000f, -0.0000f }, 0.7079f, 0.0230f, { 0.0000f, 0.0000f, 0.0000f }, 0.2180f, 0.3400f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_OUTDOORS_ROLLINGPLAINS \ + { 1.0000f, 0.0000f, 0.3162f, 0.0112f, 0.6310f, 2.1300f, 0.2100f, 0.4600f, 0.1778f, 0.3000f, { 0.0000f, 0.0000f, -0.0000f }, 0.4467f, 0.0190f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_OUTDOORS_DEEPCANYON \ + { 1.0000f, 0.7400f, 0.3162f, 0.1778f, 0.6310f, 3.8900f, 0.2100f, 0.4600f, 0.3162f, 0.2230f, { 0.0000f, 0.0000f, -0.0000f }, 0.3548f, 0.0190f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_OUTDOORS_CREEK \ + { 1.0000f, 0.3500f, 0.3162f, 0.1778f, 0.5012f, 2.1300f, 0.2100f, 0.4600f, 0.3981f, 0.1150f, { 0.0000f, 0.0000f, -0.0000f }, 0.1995f, 0.0310f, { 0.0000f, 0.0000f, 0.0000f }, 0.2180f, 0.3400f, 0.2500f, 0.0000f, 0.9943f, 4399.1001f, 242.9000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_OUTDOORS_VALLEY \ + { 1.0000f, 0.2800f, 0.3162f, 0.0282f, 0.1585f, 2.8800f, 0.2600f, 0.3500f, 0.1413f, 0.2630f, { 0.0000f, 0.0000f, -0.0000f }, 0.3981f, 0.1000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.3400f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 } + +/* Mood Presets */ + +#define EFX_REVERB_PRESET_MOOD_HEAVEN \ + { 1.0000f, 0.9400f, 0.3162f, 0.7943f, 0.4467f, 5.0400f, 1.1200f, 0.5600f, 0.2427f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0290f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0800f, 2.7420f, 0.0500f, 0.9977f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_MOOD_HELL \ + { 1.0000f, 0.5700f, 0.3162f, 0.3548f, 0.4467f, 3.5700f, 0.4900f, 2.0000f, 0.0000f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1100f, 0.0400f, 2.1090f, 0.5200f, 0.9943f, 5000.0000f, 139.5000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_MOOD_MEMORY \ + { 1.0000f, 0.8500f, 0.3162f, 0.6310f, 0.3548f, 4.0600f, 0.8200f, 0.5600f, 0.0398f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 1.1220f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.4740f, 0.4500f, 0.9886f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +/* Driving Presets */ + +#define EFX_REVERB_PRESET_DRIVING_COMMENTATOR \ + { 1.0000f, 0.0000f, 3.1623f, 0.5623f, 0.5012f, 2.4200f, 0.8800f, 0.6800f, 0.1995f, 0.0930f, { 0.0000f, 0.0000f, 0.0000f }, 0.2512f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9886f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_DRIVING_PITGARAGE \ + { 0.4287f, 0.5900f, 0.3162f, 0.7079f, 0.5623f, 1.7200f, 0.9300f, 0.8700f, 0.5623f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.1100f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_DRIVING_INCAR_RACER \ + { 0.0832f, 0.8000f, 0.3162f, 1.0000f, 0.7943f, 0.1700f, 2.0000f, 0.4100f, 1.7783f, 0.0070f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0150f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10268.2002f, 251.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_DRIVING_INCAR_SPORTS \ + { 0.0832f, 0.8000f, 0.3162f, 0.6310f, 1.0000f, 0.1700f, 0.7500f, 0.4100f, 1.0000f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.5623f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10268.2002f, 251.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_DRIVING_INCAR_LUXURY \ + { 0.2560f, 1.0000f, 0.3162f, 0.1000f, 0.5012f, 0.1300f, 0.4100f, 0.4600f, 0.7943f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 1.5849f, 0.0100f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10268.2002f, 251.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_DRIVING_FULLGRANDSTAND \ + { 1.0000f, 1.0000f, 0.3162f, 0.2818f, 0.6310f, 3.0100f, 1.3700f, 1.2800f, 0.3548f, 0.0900f, { 0.0000f, 0.0000f, 0.0000f }, 0.1778f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10420.2002f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_DRIVING_EMPTYGRANDSTAND \ + { 1.0000f, 1.0000f, 0.3162f, 1.0000f, 0.7943f, 4.6200f, 1.7500f, 1.4000f, 0.2082f, 0.0900f, { 0.0000f, 0.0000f, 0.0000f }, 0.2512f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.0000f, 0.9943f, 10420.2002f, 250.0000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_DRIVING_TUNNEL \ + { 1.0000f, 0.8100f, 0.3162f, 0.3981f, 0.8913f, 3.4200f, 0.9400f, 1.3100f, 0.7079f, 0.0510f, { 0.0000f, 0.0000f, 0.0000f }, 0.7079f, 0.0470f, { 0.0000f, 0.0000f, 0.0000f }, 0.2140f, 0.0500f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 155.3000f, 0.0000f, 0x1 } + +/* City Presets */ + +#define EFX_REVERB_PRESET_CITY_STREETS \ + { 1.0000f, 0.7800f, 0.3162f, 0.7079f, 0.8913f, 1.7900f, 1.1200f, 0.9100f, 0.2818f, 0.0460f, { 0.0000f, 0.0000f, 0.0000f }, 0.1995f, 0.0280f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2000f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CITY_SUBWAY \ + { 1.0000f, 0.7400f, 0.3162f, 0.7079f, 0.8913f, 3.0100f, 1.2300f, 0.9100f, 0.7079f, 0.0460f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0280f, { 0.0000f, 0.0000f, 0.0000f }, 0.1250f, 0.2100f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CITY_MUSEUM \ + { 1.0000f, 0.8200f, 0.3162f, 0.1778f, 0.1778f, 3.2800f, 1.4000f, 0.5700f, 0.2512f, 0.0390f, { 0.0000f, 0.0000f, -0.0000f }, 0.8913f, 0.0340f, { 0.0000f, 0.0000f, 0.0000f }, 0.1300f, 0.1700f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_CITY_LIBRARY \ + { 1.0000f, 0.8200f, 0.3162f, 0.2818f, 0.0891f, 2.7600f, 0.8900f, 0.4100f, 0.3548f, 0.0290f, { 0.0000f, 0.0000f, -0.0000f }, 0.8913f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 0.1300f, 0.1700f, 0.2500f, 0.0000f, 0.9943f, 2854.3999f, 107.5000f, 0.0000f, 0x0 } + +#define EFX_REVERB_PRESET_CITY_UNDERPASS \ + { 1.0000f, 0.8200f, 0.3162f, 0.4467f, 0.8913f, 3.5700f, 1.1200f, 0.9100f, 0.3981f, 0.0590f, { 0.0000f, 0.0000f, 0.0000f }, 0.8913f, 0.0370f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.1400f, 0.2500f, 0.0000f, 0.9920f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CITY_ABANDONED \ + { 1.0000f, 0.6900f, 0.3162f, 0.7943f, 0.8913f, 3.2800f, 1.1700f, 0.9100f, 0.4467f, 0.0440f, { 0.0000f, 0.0000f, 0.0000f }, 0.2818f, 0.0240f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.2000f, 0.2500f, 0.0000f, 0.9966f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +/* Misc. Presets */ + +#define EFX_REVERB_PRESET_DUSTYROOM \ + { 0.3645f, 0.5600f, 0.3162f, 0.7943f, 0.7079f, 1.7900f, 0.3800f, 0.2100f, 0.5012f, 0.0020f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0060f, { 0.0000f, 0.0000f, 0.0000f }, 0.2020f, 0.0500f, 0.2500f, 0.0000f, 0.9886f, 13046.0000f, 163.3000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_CHAPEL \ + { 1.0000f, 0.8400f, 0.3162f, 0.5623f, 1.0000f, 4.6200f, 0.6400f, 1.2300f, 0.4467f, 0.0320f, { 0.0000f, 0.0000f, 0.0000f }, 0.7943f, 0.0490f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.0000f, 0.2500f, 0.1100f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + +#define EFX_REVERB_PRESET_SMALLWATERROOM \ + { 1.0000f, 0.7000f, 0.3162f, 0.4477f, 1.0000f, 1.5100f, 1.2500f, 1.1400f, 0.8913f, 0.0200f, { 0.0000f, 0.0000f, 0.0000f }, 1.4125f, 0.0300f, { 0.0000f, 0.0000f, 0.0000f }, 0.1790f, 0.1500f, 0.8950f, 0.1900f, 0.9920f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } + +#endif /* EFX_PRESETS_H */ diff --git a/code/AL/efx.h b/code/AL/efx.h new file mode 100644 index 00000000..57766983 --- /dev/null +++ b/code/AL/efx.h @@ -0,0 +1,761 @@ +#ifndef AL_EFX_H +#define AL_EFX_H + + +#include "alc.h" +#include "al.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ALC_EXT_EFX_NAME "ALC_EXT_EFX" + +#define ALC_EFX_MAJOR_VERSION 0x20001 +#define ALC_EFX_MINOR_VERSION 0x20002 +#define ALC_MAX_AUXILIARY_SENDS 0x20003 + + +/* Listener properties. */ +#define AL_METERS_PER_UNIT 0x20004 + +/* Source properties. */ +#define AL_DIRECT_FILTER 0x20005 +#define AL_AUXILIARY_SEND_FILTER 0x20006 +#define AL_AIR_ABSORPTION_FACTOR 0x20007 +#define AL_ROOM_ROLLOFF_FACTOR 0x20008 +#define AL_CONE_OUTER_GAINHF 0x20009 +#define AL_DIRECT_FILTER_GAINHF_AUTO 0x2000A +#define AL_AUXILIARY_SEND_FILTER_GAIN_AUTO 0x2000B +#define AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO 0x2000C + + +/* Effect properties. */ + +/* Reverb effect parameters */ +#define AL_REVERB_DENSITY 0x0001 +#define AL_REVERB_DIFFUSION 0x0002 +#define AL_REVERB_GAIN 0x0003 +#define AL_REVERB_GAINHF 0x0004 +#define AL_REVERB_DECAY_TIME 0x0005 +#define AL_REVERB_DECAY_HFRATIO 0x0006 +#define AL_REVERB_REFLECTIONS_GAIN 0x0007 +#define AL_REVERB_REFLECTIONS_DELAY 0x0008 +#define AL_REVERB_LATE_REVERB_GAIN 0x0009 +#define AL_REVERB_LATE_REVERB_DELAY 0x000A +#define AL_REVERB_AIR_ABSORPTION_GAINHF 0x000B +#define AL_REVERB_ROOM_ROLLOFF_FACTOR 0x000C +#define AL_REVERB_DECAY_HFLIMIT 0x000D + +/* EAX Reverb effect parameters */ +#define AL_EAXREVERB_DENSITY 0x0001 +#define AL_EAXREVERB_DIFFUSION 0x0002 +#define AL_EAXREVERB_GAIN 0x0003 +#define AL_EAXREVERB_GAINHF 0x0004 +#define AL_EAXREVERB_GAINLF 0x0005 +#define AL_EAXREVERB_DECAY_TIME 0x0006 +#define AL_EAXREVERB_DECAY_HFRATIO 0x0007 +#define AL_EAXREVERB_DECAY_LFRATIO 0x0008 +#define AL_EAXREVERB_REFLECTIONS_GAIN 0x0009 +#define AL_EAXREVERB_REFLECTIONS_DELAY 0x000A +#define AL_EAXREVERB_REFLECTIONS_PAN 0x000B +#define AL_EAXREVERB_LATE_REVERB_GAIN 0x000C +#define AL_EAXREVERB_LATE_REVERB_DELAY 0x000D +#define AL_EAXREVERB_LATE_REVERB_PAN 0x000E +#define AL_EAXREVERB_ECHO_TIME 0x000F +#define AL_EAXREVERB_ECHO_DEPTH 0x0010 +#define AL_EAXREVERB_MODULATION_TIME 0x0011 +#define AL_EAXREVERB_MODULATION_DEPTH 0x0012 +#define AL_EAXREVERB_AIR_ABSORPTION_GAINHF 0x0013 +#define AL_EAXREVERB_HFREFERENCE 0x0014 +#define AL_EAXREVERB_LFREFERENCE 0x0015 +#define AL_EAXREVERB_ROOM_ROLLOFF_FACTOR 0x0016 +#define AL_EAXREVERB_DECAY_HFLIMIT 0x0017 + +/* Chorus effect parameters */ +#define AL_CHORUS_WAVEFORM 0x0001 +#define AL_CHORUS_PHASE 0x0002 +#define AL_CHORUS_RATE 0x0003 +#define AL_CHORUS_DEPTH 0x0004 +#define AL_CHORUS_FEEDBACK 0x0005 +#define AL_CHORUS_DELAY 0x0006 + +/* Distortion effect parameters */ +#define AL_DISTORTION_EDGE 0x0001 +#define AL_DISTORTION_GAIN 0x0002 +#define AL_DISTORTION_LOWPASS_CUTOFF 0x0003 +#define AL_DISTORTION_EQCENTER 0x0004 +#define AL_DISTORTION_EQBANDWIDTH 0x0005 + +/* Echo effect parameters */ +#define AL_ECHO_DELAY 0x0001 +#define AL_ECHO_LRDELAY 0x0002 +#define AL_ECHO_DAMPING 0x0003 +#define AL_ECHO_FEEDBACK 0x0004 +#define AL_ECHO_SPREAD 0x0005 + +/* Flanger effect parameters */ +#define AL_FLANGER_WAVEFORM 0x0001 +#define AL_FLANGER_PHASE 0x0002 +#define AL_FLANGER_RATE 0x0003 +#define AL_FLANGER_DEPTH 0x0004 +#define AL_FLANGER_FEEDBACK 0x0005 +#define AL_FLANGER_DELAY 0x0006 + +/* Frequency shifter effect parameters */ +#define AL_FREQUENCY_SHIFTER_FREQUENCY 0x0001 +#define AL_FREQUENCY_SHIFTER_LEFT_DIRECTION 0x0002 +#define AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION 0x0003 + +/* Vocal morpher effect parameters */ +#define AL_VOCAL_MORPHER_PHONEMEA 0x0001 +#define AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING 0x0002 +#define AL_VOCAL_MORPHER_PHONEMEB 0x0003 +#define AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING 0x0004 +#define AL_VOCAL_MORPHER_WAVEFORM 0x0005 +#define AL_VOCAL_MORPHER_RATE 0x0006 + +/* Pitchshifter effect parameters */ +#define AL_PITCH_SHIFTER_COARSE_TUNE 0x0001 +#define AL_PITCH_SHIFTER_FINE_TUNE 0x0002 + +/* Ringmodulator effect parameters */ +#define AL_RING_MODULATOR_FREQUENCY 0x0001 +#define AL_RING_MODULATOR_HIGHPASS_CUTOFF 0x0002 +#define AL_RING_MODULATOR_WAVEFORM 0x0003 + +/* Autowah effect parameters */ +#define AL_AUTOWAH_ATTACK_TIME 0x0001 +#define AL_AUTOWAH_RELEASE_TIME 0x0002 +#define AL_AUTOWAH_RESONANCE 0x0003 +#define AL_AUTOWAH_PEAK_GAIN 0x0004 + +/* Compressor effect parameters */ +#define AL_COMPRESSOR_ONOFF 0x0001 + +/* Equalizer effect parameters */ +#define AL_EQUALIZER_LOW_GAIN 0x0001 +#define AL_EQUALIZER_LOW_CUTOFF 0x0002 +#define AL_EQUALIZER_MID1_GAIN 0x0003 +#define AL_EQUALIZER_MID1_CENTER 0x0004 +#define AL_EQUALIZER_MID1_WIDTH 0x0005 +#define AL_EQUALIZER_MID2_GAIN 0x0006 +#define AL_EQUALIZER_MID2_CENTER 0x0007 +#define AL_EQUALIZER_MID2_WIDTH 0x0008 +#define AL_EQUALIZER_HIGH_GAIN 0x0009 +#define AL_EQUALIZER_HIGH_CUTOFF 0x000A + +/* Effect type */ +#define AL_EFFECT_FIRST_PARAMETER 0x0000 +#define AL_EFFECT_LAST_PARAMETER 0x8000 +#define AL_EFFECT_TYPE 0x8001 + +/* Effect types, used with the AL_EFFECT_TYPE property */ +#define AL_EFFECT_NULL 0x0000 +#define AL_EFFECT_REVERB 0x0001 +#define AL_EFFECT_CHORUS 0x0002 +#define AL_EFFECT_DISTORTION 0x0003 +#define AL_EFFECT_ECHO 0x0004 +#define AL_EFFECT_FLANGER 0x0005 +#define AL_EFFECT_FREQUENCY_SHIFTER 0x0006 +#define AL_EFFECT_VOCAL_MORPHER 0x0007 +#define AL_EFFECT_PITCH_SHIFTER 0x0008 +#define AL_EFFECT_RING_MODULATOR 0x0009 +#define AL_EFFECT_AUTOWAH 0x000A +#define AL_EFFECT_COMPRESSOR 0x000B +#define AL_EFFECT_EQUALIZER 0x000C +#define AL_EFFECT_EAXREVERB 0x8000 + +/* Auxiliary Effect Slot properties. */ +#define AL_EFFECTSLOT_EFFECT 0x0001 +#define AL_EFFECTSLOT_GAIN 0x0002 +#define AL_EFFECTSLOT_AUXILIARY_SEND_AUTO 0x0003 + +/* NULL Auxiliary Slot ID to disable a source send. */ +#define AL_EFFECTSLOT_NULL 0x0000 + + +/* Filter properties. */ + +/* Lowpass filter parameters */ +#define AL_LOWPASS_GAIN 0x0001 +#define AL_LOWPASS_GAINHF 0x0002 + +/* Highpass filter parameters */ +#define AL_HIGHPASS_GAIN 0x0001 +#define AL_HIGHPASS_GAINLF 0x0002 + +/* Bandpass filter parameters */ +#define AL_BANDPASS_GAIN 0x0001 +#define AL_BANDPASS_GAINLF 0x0002 +#define AL_BANDPASS_GAINHF 0x0003 + +/* Filter type */ +#define AL_FILTER_FIRST_PARAMETER 0x0000 +#define AL_FILTER_LAST_PARAMETER 0x8000 +#define AL_FILTER_TYPE 0x8001 + +/* Filter types, used with the AL_FILTER_TYPE property */ +#define AL_FILTER_NULL 0x0000 +#define AL_FILTER_LOWPASS 0x0001 +#define AL_FILTER_HIGHPASS 0x0002 +#define AL_FILTER_BANDPASS 0x0003 + + +/* Effect object function types. */ +typedef void (AL_APIENTRY *LPALGENEFFECTS)(ALsizei, ALuint*); +typedef void (AL_APIENTRY *LPALDELETEEFFECTS)(ALsizei, const ALuint*); +typedef ALboolean (AL_APIENTRY *LPALISEFFECT)(ALuint); +typedef void (AL_APIENTRY *LPALEFFECTI)(ALuint, ALenum, ALint); +typedef void (AL_APIENTRY *LPALEFFECTIV)(ALuint, ALenum, const ALint*); +typedef void (AL_APIENTRY *LPALEFFECTF)(ALuint, ALenum, ALfloat); +typedef void (AL_APIENTRY *LPALEFFECTFV)(ALuint, ALenum, const ALfloat*); +typedef void (AL_APIENTRY *LPALGETEFFECTI)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALGETEFFECTIV)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALGETEFFECTF)(ALuint, ALenum, ALfloat*); +typedef void (AL_APIENTRY *LPALGETEFFECTFV)(ALuint, ALenum, ALfloat*); + +/* Filter object function types. */ +typedef void (AL_APIENTRY *LPALGENFILTERS)(ALsizei, ALuint*); +typedef void (AL_APIENTRY *LPALDELETEFILTERS)(ALsizei, const ALuint*); +typedef ALboolean (AL_APIENTRY *LPALISFILTER)(ALuint); +typedef void (AL_APIENTRY *LPALFILTERI)(ALuint, ALenum, ALint); +typedef void (AL_APIENTRY *LPALFILTERIV)(ALuint, ALenum, const ALint*); +typedef void (AL_APIENTRY *LPALFILTERF)(ALuint, ALenum, ALfloat); +typedef void (AL_APIENTRY *LPALFILTERFV)(ALuint, ALenum, const ALfloat*); +typedef void (AL_APIENTRY *LPALGETFILTERI)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALGETFILTERIV)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALGETFILTERF)(ALuint, ALenum, ALfloat*); +typedef void (AL_APIENTRY *LPALGETFILTERFV)(ALuint, ALenum, ALfloat*); + +/* Auxiliary Effect Slot object function types. */ +typedef void (AL_APIENTRY *LPALGENAUXILIARYEFFECTSLOTS)(ALsizei, ALuint*); +typedef void (AL_APIENTRY *LPALDELETEAUXILIARYEFFECTSLOTS)(ALsizei, const ALuint*); +typedef ALboolean (AL_APIENTRY *LPALISAUXILIARYEFFECTSLOT)(ALuint); +typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTI)(ALuint, ALenum, ALint); +typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTIV)(ALuint, ALenum, const ALint*); +typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTF)(ALuint, ALenum, ALfloat); +typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTFV)(ALuint, ALenum, const ALfloat*); +typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTI)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTIV)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTF)(ALuint, ALenum, ALfloat*); +typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTFV)(ALuint, ALenum, ALfloat*); + +#ifdef AL_ALEXT_PROTOTYPES +AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects); +AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, const ALuint *effects); +AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect); +AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint iValue); +AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, const ALint *piValues); +AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat flValue); +AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, const ALfloat *pflValues); +AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *piValue); +AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *piValues); +AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *pflValue); +AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *pflValues); + +AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters); +AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, const ALuint *filters); +AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter); +AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint iValue); +AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, const ALint *piValues); +AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat flValue); +AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, const ALfloat *pflValues); +AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *piValue); +AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *piValues); +AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *pflValue); +AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *pflValues); + +AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots); +AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *effectslots); +AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot); +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint iValue); +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, const ALint *piValues); +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat flValue); +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, const ALfloat *pflValues); +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *piValue); +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues); +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *pflValue); +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues); +#endif + +/* Filter ranges and defaults. */ + +/* Lowpass filter */ +#define AL_LOWPASS_MIN_GAIN (0.0f) +#define AL_LOWPASS_MAX_GAIN (1.0f) +#define AL_LOWPASS_DEFAULT_GAIN (1.0f) + +#define AL_LOWPASS_MIN_GAINHF (0.0f) +#define AL_LOWPASS_MAX_GAINHF (1.0f) +#define AL_LOWPASS_DEFAULT_GAINHF (1.0f) + +/* Highpass filter */ +#define AL_HIGHPASS_MIN_GAIN (0.0f) +#define AL_HIGHPASS_MAX_GAIN (1.0f) +#define AL_HIGHPASS_DEFAULT_GAIN (1.0f) + +#define AL_HIGHPASS_MIN_GAINLF (0.0f) +#define AL_HIGHPASS_MAX_GAINLF (1.0f) +#define AL_HIGHPASS_DEFAULT_GAINLF (1.0f) + +/* Bandpass filter */ +#define AL_BANDPASS_MIN_GAIN (0.0f) +#define AL_BANDPASS_MAX_GAIN (1.0f) +#define AL_BANDPASS_DEFAULT_GAIN (1.0f) + +#define AL_BANDPASS_MIN_GAINHF (0.0f) +#define AL_BANDPASS_MAX_GAINHF (1.0f) +#define AL_BANDPASS_DEFAULT_GAINHF (1.0f) + +#define AL_BANDPASS_MIN_GAINLF (0.0f) +#define AL_BANDPASS_MAX_GAINLF (1.0f) +#define AL_BANDPASS_DEFAULT_GAINLF (1.0f) + + +/* Effect parameter ranges and defaults. */ + +/* Standard reverb effect */ +#define AL_REVERB_MIN_DENSITY (0.0f) +#define AL_REVERB_MAX_DENSITY (1.0f) +#define AL_REVERB_DEFAULT_DENSITY (1.0f) + +#define AL_REVERB_MIN_DIFFUSION (0.0f) +#define AL_REVERB_MAX_DIFFUSION (1.0f) +#define AL_REVERB_DEFAULT_DIFFUSION (1.0f) + +#define AL_REVERB_MIN_GAIN (0.0f) +#define AL_REVERB_MAX_GAIN (1.0f) +#define AL_REVERB_DEFAULT_GAIN (0.32f) + +#define AL_REVERB_MIN_GAINHF (0.0f) +#define AL_REVERB_MAX_GAINHF (1.0f) +#define AL_REVERB_DEFAULT_GAINHF (0.89f) + +#define AL_REVERB_MIN_DECAY_TIME (0.1f) +#define AL_REVERB_MAX_DECAY_TIME (20.0f) +#define AL_REVERB_DEFAULT_DECAY_TIME (1.49f) + +#define AL_REVERB_MIN_DECAY_HFRATIO (0.1f) +#define AL_REVERB_MAX_DECAY_HFRATIO (2.0f) +#define AL_REVERB_DEFAULT_DECAY_HFRATIO (0.83f) + +#define AL_REVERB_MIN_REFLECTIONS_GAIN (0.0f) +#define AL_REVERB_MAX_REFLECTIONS_GAIN (3.16f) +#define AL_REVERB_DEFAULT_REFLECTIONS_GAIN (0.05f) + +#define AL_REVERB_MIN_REFLECTIONS_DELAY (0.0f) +#define AL_REVERB_MAX_REFLECTIONS_DELAY (0.3f) +#define AL_REVERB_DEFAULT_REFLECTIONS_DELAY (0.007f) + +#define AL_REVERB_MIN_LATE_REVERB_GAIN (0.0f) +#define AL_REVERB_MAX_LATE_REVERB_GAIN (10.0f) +#define AL_REVERB_DEFAULT_LATE_REVERB_GAIN (1.26f) + +#define AL_REVERB_MIN_LATE_REVERB_DELAY (0.0f) +#define AL_REVERB_MAX_LATE_REVERB_DELAY (0.1f) +#define AL_REVERB_DEFAULT_LATE_REVERB_DELAY (0.011f) + +#define AL_REVERB_MIN_AIR_ABSORPTION_GAINHF (0.892f) +#define AL_REVERB_MAX_AIR_ABSORPTION_GAINHF (1.0f) +#define AL_REVERB_DEFAULT_AIR_ABSORPTION_GAINHF (0.994f) + +#define AL_REVERB_MIN_ROOM_ROLLOFF_FACTOR (0.0f) +#define AL_REVERB_MAX_ROOM_ROLLOFF_FACTOR (10.0f) +#define AL_REVERB_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f) + +#define AL_REVERB_MIN_DECAY_HFLIMIT AL_FALSE +#define AL_REVERB_MAX_DECAY_HFLIMIT AL_TRUE +#define AL_REVERB_DEFAULT_DECAY_HFLIMIT AL_TRUE + +/* EAX reverb effect */ +#define AL_EAXREVERB_MIN_DENSITY (0.0f) +#define AL_EAXREVERB_MAX_DENSITY (1.0f) +#define AL_EAXREVERB_DEFAULT_DENSITY (1.0f) + +#define AL_EAXREVERB_MIN_DIFFUSION (0.0f) +#define AL_EAXREVERB_MAX_DIFFUSION (1.0f) +#define AL_EAXREVERB_DEFAULT_DIFFUSION (1.0f) + +#define AL_EAXREVERB_MIN_GAIN (0.0f) +#define AL_EAXREVERB_MAX_GAIN (1.0f) +#define AL_EAXREVERB_DEFAULT_GAIN (0.32f) + +#define AL_EAXREVERB_MIN_GAINHF (0.0f) +#define AL_EAXREVERB_MAX_GAINHF (1.0f) +#define AL_EAXREVERB_DEFAULT_GAINHF (0.89f) + +#define AL_EAXREVERB_MIN_GAINLF (0.0f) +#define AL_EAXREVERB_MAX_GAINLF (1.0f) +#define AL_EAXREVERB_DEFAULT_GAINLF (1.0f) + +#define AL_EAXREVERB_MIN_DECAY_TIME (0.1f) +#define AL_EAXREVERB_MAX_DECAY_TIME (20.0f) +#define AL_EAXREVERB_DEFAULT_DECAY_TIME (1.49f) + +#define AL_EAXREVERB_MIN_DECAY_HFRATIO (0.1f) +#define AL_EAXREVERB_MAX_DECAY_HFRATIO (2.0f) +#define AL_EAXREVERB_DEFAULT_DECAY_HFRATIO (0.83f) + +#define AL_EAXREVERB_MIN_DECAY_LFRATIO (0.1f) +#define AL_EAXREVERB_MAX_DECAY_LFRATIO (2.0f) +#define AL_EAXREVERB_DEFAULT_DECAY_LFRATIO (1.0f) + +#define AL_EAXREVERB_MIN_REFLECTIONS_GAIN (0.0f) +#define AL_EAXREVERB_MAX_REFLECTIONS_GAIN (3.16f) +#define AL_EAXREVERB_DEFAULT_REFLECTIONS_GAIN (0.05f) + +#define AL_EAXREVERB_MIN_REFLECTIONS_DELAY (0.0f) +#define AL_EAXREVERB_MAX_REFLECTIONS_DELAY (0.3f) +#define AL_EAXREVERB_DEFAULT_REFLECTIONS_DELAY (0.007f) + +#define AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ (0.0f) + +#define AL_EAXREVERB_MIN_LATE_REVERB_GAIN (0.0f) +#define AL_EAXREVERB_MAX_LATE_REVERB_GAIN (10.0f) +#define AL_EAXREVERB_DEFAULT_LATE_REVERB_GAIN (1.26f) + +#define AL_EAXREVERB_MIN_LATE_REVERB_DELAY (0.0f) +#define AL_EAXREVERB_MAX_LATE_REVERB_DELAY (0.1f) +#define AL_EAXREVERB_DEFAULT_LATE_REVERB_DELAY (0.011f) + +#define AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ (0.0f) + +#define AL_EAXREVERB_MIN_ECHO_TIME (0.075f) +#define AL_EAXREVERB_MAX_ECHO_TIME (0.25f) +#define AL_EAXREVERB_DEFAULT_ECHO_TIME (0.25f) + +#define AL_EAXREVERB_MIN_ECHO_DEPTH (0.0f) +#define AL_EAXREVERB_MAX_ECHO_DEPTH (1.0f) +#define AL_EAXREVERB_DEFAULT_ECHO_DEPTH (0.0f) + +#define AL_EAXREVERB_MIN_MODULATION_TIME (0.04f) +#define AL_EAXREVERB_MAX_MODULATION_TIME (4.0f) +#define AL_EAXREVERB_DEFAULT_MODULATION_TIME (0.25f) + +#define AL_EAXREVERB_MIN_MODULATION_DEPTH (0.0f) +#define AL_EAXREVERB_MAX_MODULATION_DEPTH (1.0f) +#define AL_EAXREVERB_DEFAULT_MODULATION_DEPTH (0.0f) + +#define AL_EAXREVERB_MIN_AIR_ABSORPTION_GAINHF (0.892f) +#define AL_EAXREVERB_MAX_AIR_ABSORPTION_GAINHF (1.0f) +#define AL_EAXREVERB_DEFAULT_AIR_ABSORPTION_GAINHF (0.994f) + +#define AL_EAXREVERB_MIN_HFREFERENCE (1000.0f) +#define AL_EAXREVERB_MAX_HFREFERENCE (20000.0f) +#define AL_EAXREVERB_DEFAULT_HFREFERENCE (5000.0f) + +#define AL_EAXREVERB_MIN_LFREFERENCE (20.0f) +#define AL_EAXREVERB_MAX_LFREFERENCE (1000.0f) +#define AL_EAXREVERB_DEFAULT_LFREFERENCE (250.0f) + +#define AL_EAXREVERB_MIN_ROOM_ROLLOFF_FACTOR (0.0f) +#define AL_EAXREVERB_MAX_ROOM_ROLLOFF_FACTOR (10.0f) +#define AL_EAXREVERB_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f) + +#define AL_EAXREVERB_MIN_DECAY_HFLIMIT AL_FALSE +#define AL_EAXREVERB_MAX_DECAY_HFLIMIT AL_TRUE +#define AL_EAXREVERB_DEFAULT_DECAY_HFLIMIT AL_TRUE + +/* Chorus effect */ +#define AL_CHORUS_WAVEFORM_SINUSOID (0) +#define AL_CHORUS_WAVEFORM_TRIANGLE (1) + +#define AL_CHORUS_MIN_WAVEFORM (0) +#define AL_CHORUS_MAX_WAVEFORM (1) +#define AL_CHORUS_DEFAULT_WAVEFORM (1) + +#define AL_CHORUS_MIN_PHASE (-180) +#define AL_CHORUS_MAX_PHASE (180) +#define AL_CHORUS_DEFAULT_PHASE (90) + +#define AL_CHORUS_MIN_RATE (0.0f) +#define AL_CHORUS_MAX_RATE (10.0f) +#define AL_CHORUS_DEFAULT_RATE (1.1f) + +#define AL_CHORUS_MIN_DEPTH (0.0f) +#define AL_CHORUS_MAX_DEPTH (1.0f) +#define AL_CHORUS_DEFAULT_DEPTH (0.1f) + +#define AL_CHORUS_MIN_FEEDBACK (-1.0f) +#define AL_CHORUS_MAX_FEEDBACK (1.0f) +#define AL_CHORUS_DEFAULT_FEEDBACK (0.25f) + +#define AL_CHORUS_MIN_DELAY (0.0f) +#define AL_CHORUS_MAX_DELAY (0.016f) +#define AL_CHORUS_DEFAULT_DELAY (0.016f) + +/* Distortion effect */ +#define AL_DISTORTION_MIN_EDGE (0.0f) +#define AL_DISTORTION_MAX_EDGE (1.0f) +#define AL_DISTORTION_DEFAULT_EDGE (0.2f) + +#define AL_DISTORTION_MIN_GAIN (0.01f) +#define AL_DISTORTION_MAX_GAIN (1.0f) +#define AL_DISTORTION_DEFAULT_GAIN (0.05f) + +#define AL_DISTORTION_MIN_LOWPASS_CUTOFF (80.0f) +#define AL_DISTORTION_MAX_LOWPASS_CUTOFF (24000.0f) +#define AL_DISTORTION_DEFAULT_LOWPASS_CUTOFF (8000.0f) + +#define AL_DISTORTION_MIN_EQCENTER (80.0f) +#define AL_DISTORTION_MAX_EQCENTER (24000.0f) +#define AL_DISTORTION_DEFAULT_EQCENTER (3600.0f) + +#define AL_DISTORTION_MIN_EQBANDWIDTH (80.0f) +#define AL_DISTORTION_MAX_EQBANDWIDTH (24000.0f) +#define AL_DISTORTION_DEFAULT_EQBANDWIDTH (3600.0f) + +/* Echo effect */ +#define AL_ECHO_MIN_DELAY (0.0f) +#define AL_ECHO_MAX_DELAY (0.207f) +#define AL_ECHO_DEFAULT_DELAY (0.1f) + +#define AL_ECHO_MIN_LRDELAY (0.0f) +#define AL_ECHO_MAX_LRDELAY (0.404f) +#define AL_ECHO_DEFAULT_LRDELAY (0.1f) + +#define AL_ECHO_MIN_DAMPING (0.0f) +#define AL_ECHO_MAX_DAMPING (0.99f) +#define AL_ECHO_DEFAULT_DAMPING (0.5f) + +#define AL_ECHO_MIN_FEEDBACK (0.0f) +#define AL_ECHO_MAX_FEEDBACK (1.0f) +#define AL_ECHO_DEFAULT_FEEDBACK (0.5f) + +#define AL_ECHO_MIN_SPREAD (-1.0f) +#define AL_ECHO_MAX_SPREAD (1.0f) +#define AL_ECHO_DEFAULT_SPREAD (-1.0f) + +/* Flanger effect */ +#define AL_FLANGER_WAVEFORM_SINUSOID (0) +#define AL_FLANGER_WAVEFORM_TRIANGLE (1) + +#define AL_FLANGER_MIN_WAVEFORM (0) +#define AL_FLANGER_MAX_WAVEFORM (1) +#define AL_FLANGER_DEFAULT_WAVEFORM (1) + +#define AL_FLANGER_MIN_PHASE (-180) +#define AL_FLANGER_MAX_PHASE (180) +#define AL_FLANGER_DEFAULT_PHASE (0) + +#define AL_FLANGER_MIN_RATE (0.0f) +#define AL_FLANGER_MAX_RATE (10.0f) +#define AL_FLANGER_DEFAULT_RATE (0.27f) + +#define AL_FLANGER_MIN_DEPTH (0.0f) +#define AL_FLANGER_MAX_DEPTH (1.0f) +#define AL_FLANGER_DEFAULT_DEPTH (1.0f) + +#define AL_FLANGER_MIN_FEEDBACK (-1.0f) +#define AL_FLANGER_MAX_FEEDBACK (1.0f) +#define AL_FLANGER_DEFAULT_FEEDBACK (-0.5f) + +#define AL_FLANGER_MIN_DELAY (0.0f) +#define AL_FLANGER_MAX_DELAY (0.004f) +#define AL_FLANGER_DEFAULT_DELAY (0.002f) + +/* Frequency shifter effect */ +#define AL_FREQUENCY_SHIFTER_MIN_FREQUENCY (0.0f) +#define AL_FREQUENCY_SHIFTER_MAX_FREQUENCY (24000.0f) +#define AL_FREQUENCY_SHIFTER_DEFAULT_FREQUENCY (0.0f) + +#define AL_FREQUENCY_SHIFTER_MIN_LEFT_DIRECTION (0) +#define AL_FREQUENCY_SHIFTER_MAX_LEFT_DIRECTION (2) +#define AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION (0) + +#define AL_FREQUENCY_SHIFTER_DIRECTION_DOWN (0) +#define AL_FREQUENCY_SHIFTER_DIRECTION_UP (1) +#define AL_FREQUENCY_SHIFTER_DIRECTION_OFF (2) + +#define AL_FREQUENCY_SHIFTER_MIN_RIGHT_DIRECTION (0) +#define AL_FREQUENCY_SHIFTER_MAX_RIGHT_DIRECTION (2) +#define AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION (0) + +/* Vocal morpher effect */ +#define AL_VOCAL_MORPHER_MIN_PHONEMEA (0) +#define AL_VOCAL_MORPHER_MAX_PHONEMEA (29) +#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEA (0) + +#define AL_VOCAL_MORPHER_MIN_PHONEMEA_COARSE_TUNING (-24) +#define AL_VOCAL_MORPHER_MAX_PHONEMEA_COARSE_TUNING (24) +#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEA_COARSE_TUNING (0) + +#define AL_VOCAL_MORPHER_MIN_PHONEMEB (0) +#define AL_VOCAL_MORPHER_MAX_PHONEMEB (29) +#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEB (10) + +#define AL_VOCAL_MORPHER_MIN_PHONEMEB_COARSE_TUNING (-24) +#define AL_VOCAL_MORPHER_MAX_PHONEMEB_COARSE_TUNING (24) +#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEB_COARSE_TUNING (0) + +#define AL_VOCAL_MORPHER_PHONEME_A (0) +#define AL_VOCAL_MORPHER_PHONEME_E (1) +#define AL_VOCAL_MORPHER_PHONEME_I (2) +#define AL_VOCAL_MORPHER_PHONEME_O (3) +#define AL_VOCAL_MORPHER_PHONEME_U (4) +#define AL_VOCAL_MORPHER_PHONEME_AA (5) +#define AL_VOCAL_MORPHER_PHONEME_AE (6) +#define AL_VOCAL_MORPHER_PHONEME_AH (7) +#define AL_VOCAL_MORPHER_PHONEME_AO (8) +#define AL_VOCAL_MORPHER_PHONEME_EH (9) +#define AL_VOCAL_MORPHER_PHONEME_ER (10) +#define AL_VOCAL_MORPHER_PHONEME_IH (11) +#define AL_VOCAL_MORPHER_PHONEME_IY (12) +#define AL_VOCAL_MORPHER_PHONEME_UH (13) +#define AL_VOCAL_MORPHER_PHONEME_UW (14) +#define AL_VOCAL_MORPHER_PHONEME_B (15) +#define AL_VOCAL_MORPHER_PHONEME_D (16) +#define AL_VOCAL_MORPHER_PHONEME_F (17) +#define AL_VOCAL_MORPHER_PHONEME_G (18) +#define AL_VOCAL_MORPHER_PHONEME_J (19) +#define AL_VOCAL_MORPHER_PHONEME_K (20) +#define AL_VOCAL_MORPHER_PHONEME_L (21) +#define AL_VOCAL_MORPHER_PHONEME_M (22) +#define AL_VOCAL_MORPHER_PHONEME_N (23) +#define AL_VOCAL_MORPHER_PHONEME_P (24) +#define AL_VOCAL_MORPHER_PHONEME_R (25) +#define AL_VOCAL_MORPHER_PHONEME_S (26) +#define AL_VOCAL_MORPHER_PHONEME_T (27) +#define AL_VOCAL_MORPHER_PHONEME_V (28) +#define AL_VOCAL_MORPHER_PHONEME_Z (29) + +#define AL_VOCAL_MORPHER_WAVEFORM_SINUSOID (0) +#define AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE (1) +#define AL_VOCAL_MORPHER_WAVEFORM_SAWTOOTH (2) + +#define AL_VOCAL_MORPHER_MIN_WAVEFORM (0) +#define AL_VOCAL_MORPHER_MAX_WAVEFORM (2) +#define AL_VOCAL_MORPHER_DEFAULT_WAVEFORM (0) + +#define AL_VOCAL_MORPHER_MIN_RATE (0.0f) +#define AL_VOCAL_MORPHER_MAX_RATE (10.0f) +#define AL_VOCAL_MORPHER_DEFAULT_RATE (1.41f) + +/* Pitch shifter effect */ +#define AL_PITCH_SHIFTER_MIN_COARSE_TUNE (-12) +#define AL_PITCH_SHIFTER_MAX_COARSE_TUNE (12) +#define AL_PITCH_SHIFTER_DEFAULT_COARSE_TUNE (12) + +#define AL_PITCH_SHIFTER_MIN_FINE_TUNE (-50) +#define AL_PITCH_SHIFTER_MAX_FINE_TUNE (50) +#define AL_PITCH_SHIFTER_DEFAULT_FINE_TUNE (0) + +/* Ring modulator effect */ +#define AL_RING_MODULATOR_MIN_FREQUENCY (0.0f) +#define AL_RING_MODULATOR_MAX_FREQUENCY (8000.0f) +#define AL_RING_MODULATOR_DEFAULT_FREQUENCY (440.0f) + +#define AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF (0.0f) +#define AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF (24000.0f) +#define AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF (800.0f) + +#define AL_RING_MODULATOR_SINUSOID (0) +#define AL_RING_MODULATOR_SAWTOOTH (1) +#define AL_RING_MODULATOR_SQUARE (2) + +#define AL_RING_MODULATOR_MIN_WAVEFORM (0) +#define AL_RING_MODULATOR_MAX_WAVEFORM (2) +#define AL_RING_MODULATOR_DEFAULT_WAVEFORM (0) + +/* Autowah effect */ +#define AL_AUTOWAH_MIN_ATTACK_TIME (0.0001f) +#define AL_AUTOWAH_MAX_ATTACK_TIME (1.0f) +#define AL_AUTOWAH_DEFAULT_ATTACK_TIME (0.06f) + +#define AL_AUTOWAH_MIN_RELEASE_TIME (0.0001f) +#define AL_AUTOWAH_MAX_RELEASE_TIME (1.0f) +#define AL_AUTOWAH_DEFAULT_RELEASE_TIME (0.06f) + +#define AL_AUTOWAH_MIN_RESONANCE (2.0f) +#define AL_AUTOWAH_MAX_RESONANCE (1000.0f) +#define AL_AUTOWAH_DEFAULT_RESONANCE (1000.0f) + +#define AL_AUTOWAH_MIN_PEAK_GAIN (0.00003f) +#define AL_AUTOWAH_MAX_PEAK_GAIN (31621.0f) +#define AL_AUTOWAH_DEFAULT_PEAK_GAIN (11.22f) + +/* Compressor effect */ +#define AL_COMPRESSOR_MIN_ONOFF (0) +#define AL_COMPRESSOR_MAX_ONOFF (1) +#define AL_COMPRESSOR_DEFAULT_ONOFF (1) + +/* Equalizer effect */ +#define AL_EQUALIZER_MIN_LOW_GAIN (0.126f) +#define AL_EQUALIZER_MAX_LOW_GAIN (7.943f) +#define AL_EQUALIZER_DEFAULT_LOW_GAIN (1.0f) + +#define AL_EQUALIZER_MIN_LOW_CUTOFF (50.0f) +#define AL_EQUALIZER_MAX_LOW_CUTOFF (800.0f) +#define AL_EQUALIZER_DEFAULT_LOW_CUTOFF (200.0f) + +#define AL_EQUALIZER_MIN_MID1_GAIN (0.126f) +#define AL_EQUALIZER_MAX_MID1_GAIN (7.943f) +#define AL_EQUALIZER_DEFAULT_MID1_GAIN (1.0f) + +#define AL_EQUALIZER_MIN_MID1_CENTER (200.0f) +#define AL_EQUALIZER_MAX_MID1_CENTER (3000.0f) +#define AL_EQUALIZER_DEFAULT_MID1_CENTER (500.0f) + +#define AL_EQUALIZER_MIN_MID1_WIDTH (0.01f) +#define AL_EQUALIZER_MAX_MID1_WIDTH (1.0f) +#define AL_EQUALIZER_DEFAULT_MID1_WIDTH (1.0f) + +#define AL_EQUALIZER_MIN_MID2_GAIN (0.126f) +#define AL_EQUALIZER_MAX_MID2_GAIN (7.943f) +#define AL_EQUALIZER_DEFAULT_MID2_GAIN (1.0f) + +#define AL_EQUALIZER_MIN_MID2_CENTER (1000.0f) +#define AL_EQUALIZER_MAX_MID2_CENTER (8000.0f) +#define AL_EQUALIZER_DEFAULT_MID2_CENTER (3000.0f) + +#define AL_EQUALIZER_MIN_MID2_WIDTH (0.01f) +#define AL_EQUALIZER_MAX_MID2_WIDTH (1.0f) +#define AL_EQUALIZER_DEFAULT_MID2_WIDTH (1.0f) + +#define AL_EQUALIZER_MIN_HIGH_GAIN (0.126f) +#define AL_EQUALIZER_MAX_HIGH_GAIN (7.943f) +#define AL_EQUALIZER_DEFAULT_HIGH_GAIN (1.0f) + +#define AL_EQUALIZER_MIN_HIGH_CUTOFF (4000.0f) +#define AL_EQUALIZER_MAX_HIGH_CUTOFF (16000.0f) +#define AL_EQUALIZER_DEFAULT_HIGH_CUTOFF (6000.0f) + + +/* Source parameter value ranges and defaults. */ +#define AL_MIN_AIR_ABSORPTION_FACTOR (0.0f) +#define AL_MAX_AIR_ABSORPTION_FACTOR (10.0f) +#define AL_DEFAULT_AIR_ABSORPTION_FACTOR (0.0f) + +#define AL_MIN_ROOM_ROLLOFF_FACTOR (0.0f) +#define AL_MAX_ROOM_ROLLOFF_FACTOR (10.0f) +#define AL_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f) + +#define AL_MIN_CONE_OUTER_GAINHF (0.0f) +#define AL_MAX_CONE_OUTER_GAINHF (1.0f) +#define AL_DEFAULT_CONE_OUTER_GAINHF (1.0f) + +#define AL_MIN_DIRECT_FILTER_GAINHF_AUTO AL_FALSE +#define AL_MAX_DIRECT_FILTER_GAINHF_AUTO AL_TRUE +#define AL_DEFAULT_DIRECT_FILTER_GAINHF_AUTO AL_TRUE + +#define AL_MIN_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_FALSE +#define AL_MAX_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_TRUE +#define AL_DEFAULT_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_TRUE + +#define AL_MIN_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_FALSE +#define AL_MAX_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_TRUE +#define AL_DEFAULT_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_TRUE + + +/* Listener parameter value ranges and defaults. */ +#define AL_MIN_METERS_PER_UNIT FLT_MIN +#define AL_MAX_METERS_PER_UNIT FLT_MAX +#define AL_DEFAULT_METERS_PER_UNIT (1.0f) + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* AL_EFX_H */ diff --git a/code/asm/ftola.asm b/code/asm/ftola.asm index eea9d0e3..321b6b5e 100644 --- a/code/asm/ftola.asm +++ b/code/asm/ftola.asm @@ -21,6 +21,9 @@ ; MASM ftol conversion functions using SSE or FPU ; assume __cdecl calling convention is being used for x86, __fastcall for x64 +.686p +.xmm + IFNDEF idx64 .model flat, c ENDIF diff --git a/code/asm/ftola.c b/code/asm/ftola.c index 6e8ff061..e805acb4 100644 --- a/code/asm/ftola.c +++ b/code/asm/ftola.c @@ -61,7 +61,7 @@ int qvmftolsse(void) long qftolx87(float f) { long retval; - unsigned short oldcw; + unsigned short oldcw = 0; __asm__ volatile ( @@ -81,7 +81,7 @@ long qftolx87(float f) int qvmftolx87(void) { int retval; - unsigned short oldcw; + unsigned short oldcw = 0; __asm__ volatile ( diff --git a/code/asm/snapvector.asm b/code/asm/snapvector.asm index 22f9b225..9e61bec6 100644 --- a/code/asm/snapvector.asm +++ b/code/asm/snapvector.asm @@ -24,6 +24,9 @@ ; function prototype: ; void qsnapvector(vec3_t vec) +.686p +.xmm + IFNDEF idx64 .model flat, c ENDIF diff --git a/code/asm/snapvector.c b/code/asm/snapvector.c index f0f62466..44e81f58 100644 --- a/code/asm/snapvector.c +++ b/code/asm/snapvector.c @@ -55,8 +55,8 @@ void qsnapvectorsse(vec3_t vec) #define QROUNDX87(src) \ "flds " src "\n" \ - "fistps " src "\n" \ - "filds " src "\n" \ + "fistpl " src "\n" \ + "fildl " src "\n" \ "fstps " src "\n" void qsnapvectorx87(vec3_t vec) diff --git a/code/botlib/be_aas_def.h b/code/botlib/be_aas_def.h index 4f5655bf..4e177cfa 100644 --- a/code/botlib/be_aas_def.h +++ b/code/botlib/be_aas_def.h @@ -34,10 +34,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA //debugging on #define AAS_DEBUG -#define CS_SCORES 32 -#define CS_MODELS (CS_SCORES+MAX_CLIENTS) -#define CS_SOUNDS (CS_MODELS+MAX_MODELS) - #define DF_AASENTNUMBER(x) (x - aasworld.entities) #define DF_NUMBERAASENT(x) (&aasworld.entities[x]) #define DF_AASENTCLIENT(x) (x - aasworld.entities - 1) @@ -47,13 +43,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define MAX_PATH MAX_QPATH #endif -//string index (for model, sound and image index) -typedef struct aas_stringindex_s -{ - int numindexes; - char **index; -} aas_stringindex_t; - //structure to link entities to areas and areas to entities typedef struct aas_link_s { @@ -254,9 +243,6 @@ typedef struct aas_s int maxentities; int maxclients; aas_entity_t *entities; - //string indexes - char *configstrings[MAX_CONFIGSTRINGS]; - int indexessetup; //index to retrieve travel flag for a travel type int travelflagfortype[MAX_TRAVELTYPES]; //travel flags for each area based on contents diff --git a/code/botlib/be_aas_main.c b/code/botlib/be_aas_main.c index 7a9f7017..08f82135 100644 --- a/code/botlib/be_aas_main.c +++ b/code/botlib/be_aas_main.c @@ -70,96 +70,6 @@ void QDECL AAS_Error(char *fmt, ...) // Returns: - // Changes Globals: - //=========================================================================== -char *AAS_StringFromIndex(char *indexname, char *stringindex[], int numindexes, int index) -{ - if (!aasworld.indexessetup) - { - botimport.Print(PRT_ERROR, "%s: index %d not setup\n", indexname, index); - return ""; - } //end if - if (index < 0 || index >= numindexes) - { - botimport.Print(PRT_ERROR, "%s: index %d out of range\n", indexname, index); - return ""; - } //end if - if (!stringindex[index]) - { - if (index) - { - botimport.Print(PRT_ERROR, "%s: reference to unused index %d\n", indexname, index); - } //end if - return ""; - } //end if - return stringindex[index]; -} //end of the function AAS_StringFromIndex -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_IndexFromString(char *indexname, char *stringindex[], int numindexes, char *string) -{ - int i; - if (!aasworld.indexessetup) - { - botimport.Print(PRT_ERROR, "%s: index not setup \"%s\"\n", indexname, string); - return 0; - } //end if - for (i = 0; i < numindexes; i++) - { - if (!stringindex[i]) continue; - if (!Q_stricmp(stringindex[i], string)) return i; - } //end for - return 0; -} //end of the function AAS_IndexFromString -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -char *AAS_ModelFromIndex(int index) -{ - return AAS_StringFromIndex("ModelFromIndex", &aasworld.configstrings[CS_MODELS], MAX_MODELS, index); -} //end of the function AAS_ModelFromIndex -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int AAS_IndexFromModel(char *modelname) -{ - return AAS_IndexFromString("IndexFromModel", &aasworld.configstrings[CS_MODELS], MAX_MODELS, modelname); -} //end of the function AAS_IndexFromModel -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AAS_UpdateStringIndexes(int numconfigstrings, char *configstrings[]) -{ - int i; - //set string pointers and copy the strings - for (i = 0; i < numconfigstrings; i++) - { - if (configstrings[i]) - { - //if (aasworld.configstrings[i]) FreeMemory(aasworld.configstrings[i]); - aasworld.configstrings[i] = (char *) GetMemory(strlen(configstrings[i]) + 1); - strcpy(aasworld.configstrings[i], configstrings[i]); - } //end if - } //end for - aasworld.indexessetup = qtrue; -} //end of the function AAS_UpdateStringIndexes -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== int AAS_Loaded(void) { return aasworld.loaded; diff --git a/code/botlib/be_aas_main.h b/code/botlib/be_aas_main.h index 0748ad11..fce17800 100644 --- a/code/botlib/be_aas_main.h +++ b/code/botlib/be_aas_main.h @@ -51,10 +51,6 @@ int AAS_StartFrame(float time); int AAS_Initialized(void); //returns true if the AAS file is loaded int AAS_Loaded(void); -//returns the model name from the given index -char *AAS_ModelFromIndex(int index); -//returns the index from the given model name -int AAS_IndexFromModel(char *modelname); //returns the current time float AAS_Time(void); // diff --git a/code/botlib/be_aas_reach.c b/code/botlib/be_aas_reach.c index 3a4564ca..ed9ff76d 100644 --- a/code/botlib/be_aas_reach.c +++ b/code/botlib/be_aas_reach.c @@ -3237,8 +3237,10 @@ aas_lreachability_t *AAS_FindFaceReachabilities(vec3_t *facepoints, int numpoint // if (towardsface) VectorCopy(bestend, testpoint); else VectorCopy(beststart, testpoint); - testpoint[2] = 0; - testpoint[2] = (bestfaceplane->dist - DotProduct(bestfaceplane->normal, testpoint)) / bestfaceplane->normal[2]; + if (bestfaceplane != NULL) + testpoint[2] = (bestfaceplane->dist - DotProduct(bestfaceplane->normal, testpoint)) / bestfaceplane->normal[2]; + else + testpoint[2] = 0; // if (!AAS_PointInsideFace(bestfacenum, testpoint, 0.1f)) { @@ -3786,7 +3788,7 @@ int AAS_Reachability_Grapple(int area1num, int area2num) aas_face_t *face2; aas_area_t *area1, *area2; aas_lreachability_t *lreach; - vec3_t areastart, facecenter, start, end, dir, down = {0, 0, -1}; + vec3_t areastart = {0, 0, 0}, facecenter, start, end, dir, down = {0, 0, -1}; vec_t *v; //only grapple when on the ground or swimming diff --git a/code/botlib/be_aas_route.c b/code/botlib/be_aas_route.c index 5e365973..d4287a04 100644 --- a/code/botlib/be_aas_route.c +++ b/code/botlib/be_aas_route.c @@ -168,12 +168,11 @@ void AAS_InitTravelFlagFromType(void) //=========================================================================== static ID_INLINE int AAS_TravelFlagForType_inline(int traveltype) { - int tfl; + int tfl = 0; - tfl = 0; - if (tfl & TRAVELFLAG_NOTTEAM1) + if (traveltype & TRAVELFLAG_NOTTEAM1) tfl |= TFL_NOTTEAM1; - if (tfl & TRAVELFLAG_NOTTEAM2) + if (traveltype & TRAVELFLAG_NOTTEAM2) tfl |= TFL_NOTTEAM2; traveltype &= TRAVELTYPE_MASK; if (traveltype < 0 || traveltype >= MAX_TRAVELTYPES) diff --git a/code/botlib/be_ai_char.c b/code/botlib/be_ai_char.c index b94c4e9a..4adb2812 100644 --- a/code/botlib/be_ai_char.c +++ b/code/botlib/be_ai_char.c @@ -760,14 +760,11 @@ void Characteristic_String(int character, int index, char *buf, int size) { strncpy(buf, ch->c[index].value.string, size-1); buf[size-1] = '\0'; - return; } //end if else { botimport.Print(PRT_ERROR, "characteristic %d is not a string\n", index); - return; } //end else if - return; } //end of the function Characteristic_String //=========================================================================== // diff --git a/code/botlib/be_ai_chat.c b/code/botlib/be_ai_chat.c index 867e4391..e90aaddc 100644 --- a/code/botlib/be_ai_chat.c +++ b/code/botlib/be_ai_chat.c @@ -673,7 +673,7 @@ bot_synonymlist_t *BotLoadSynonyms(char *filename) else if (!strcmp(token.string, "[")) { size += sizeof(bot_synonymlist_t); - if (pass) + if (pass && ptr) { syn = (bot_synonymlist_t *) ptr; ptr += sizeof(bot_synonymlist_t); @@ -705,7 +705,7 @@ bot_synonymlist_t *BotLoadSynonyms(char *filename) len = strlen(token.string) + 1; len = PAD(len, sizeof(long)); size += sizeof(bot_synonym_t) + len; - if (pass) + if (pass && ptr) { synonym = (bot_synonym_t *) ptr; ptr += sizeof(bot_synonym_t); @@ -725,7 +725,7 @@ bot_synonymlist_t *BotLoadSynonyms(char *filename) FreeSource(source); return NULL; } //end if - if (pass) + if (pass && ptr) { synonym->weight = token.floatvalue; syn->totalweight += synonym->weight; @@ -1003,7 +1003,7 @@ bot_randomlist_t *BotLoadRandomStrings(char *filename) len = strlen(token.string) + 1; len = PAD(len, sizeof(long)); size += sizeof(bot_randomlist_t) + len; - if (pass) + if (pass && ptr) { random = (bot_randomlist_t *) ptr; ptr += sizeof(bot_randomlist_t); @@ -1025,7 +1025,6 @@ bot_randomlist_t *BotLoadRandomStrings(char *filename) } //end if while(!PC_CheckTokenString(source, "}")) { - size_t len; if (!BotLoadChatMessage(source, chatmessagestring)) { FreeSource(source); @@ -1034,7 +1033,7 @@ bot_randomlist_t *BotLoadRandomStrings(char *filename) len = strlen(chatmessagestring) + 1; len = PAD(len, sizeof(long)); size += sizeof(bot_randomstring_t) + len; - if (pass) + if (pass && ptr) { randomstring = (bot_randomstring_t *) ptr; ptr += sizeof(bot_randomstring_t); @@ -1507,7 +1506,6 @@ void BotMatchVariable(bot_match_t *match, int variable, char *buf, int size) { strcpy(buf, ""); } //end else - return; } //end of the function BotMatchVariable //=========================================================================== // @@ -2113,7 +2111,7 @@ bot_chat_t *BotLoadInitialChat(char *chatfile, char *chatname) return NULL; } //end if StripDoubleQuotes(token.string); - if (pass) + if (pass && ptr) { chattype = (bot_chattype_t *) ptr; strncpy(chattype->name, token.string, MAX_CHATTYPE_NAME); @@ -2136,7 +2134,7 @@ bot_chat_t *BotLoadInitialChat(char *chatfile, char *chatname) } //end if len = strlen(chatmessagestring) + 1; len = PAD(len, sizeof(long)); - if (pass) + if (pass && ptr) { chatmessage = (bot_chatmessage_t *) ptr; chatmessage->time = -2*CHATMESSAGE_RECENTTIME; @@ -2583,7 +2581,6 @@ void BotInitialChat(int chatstate, char *type, int mcontext, char *var0, char *v strcat(match.string, var7); match.variables[7].offset = index; match.variables[7].length = strlen(var7); - index += strlen(var7); } // BotConstructChatMessage(cs, message, mcontext, &match, 0, qfalse); @@ -2766,7 +2763,6 @@ int BotReplyChat(int chatstate, char *message, int mcontext, int vcontext, char strcat(bestmatch.string, var7); bestmatch.variables[7].offset = index; bestmatch.variables[7].length = strlen(var7); - index += strlen(var7); } if (LibVarGetValue("bot_testrchat")) { diff --git a/code/botlib/be_ai_goal.c b/code/botlib/be_ai_goal.c index 9feeeab5..3a5d01ab 100644 --- a/code/botlib/be_ai_goal.c +++ b/code/botlib/be_ai_goal.c @@ -310,7 +310,7 @@ itemconfig_t *LoadItemConfig(char *filename) if (!PC_ExpectTokenType(source, TT_STRING, 0, &token)) { FreeMemory(ic); - FreeMemory(source); + FreeSource(source); return NULL; } //end if StripDoubleQuotes(token.string); @@ -558,10 +558,9 @@ void BotInitLevelItems(void) //if there's no AAS file loaded if (!AAS_Loaded()) return; - //update the modelindexes of the item info + //validate the modelindexes of the item info for (i = 0; i < ic->numiteminfo; i++) { - //ic->iteminfo[i].modelindex = AAS_IndexFromModel(ic->iteminfo[i].model); if (!ic->iteminfo[i].modelindex) { Log_Write("item %s has modelindex 0", ic->iteminfo[i].classname); @@ -692,7 +691,6 @@ void BotGoalName(int number, char *name, int size) } //end for } //end for strcpy(name, ""); - return; } //end of the function BotGoalName //=========================================================================== // diff --git a/code/botlib/be_ai_move.c b/code/botlib/be_ai_move.c index a9e64d5d..0c4de348 100644 --- a/code/botlib/be_ai_move.c +++ b/code/botlib/be_ai_move.c @@ -3455,8 +3455,6 @@ void BotMoveToGoal(bot_moveresult_t *result, int movestate, bot_goal_t *goal, in if (result->blocked) ms->reachability_time -= 10 * ms->thinktime; //copy the last origin VectorCopy(ms->origin, ms->lastorigin); - //return the movement result - return; } //end of the function BotMoveToGoal //=========================================================================== // diff --git a/code/botlib/be_ai_weap.c b/code/botlib/be_ai_weap.c index 492f943a..8fab4d79 100644 --- a/code/botlib/be_ai_weap.c +++ b/code/botlib/be_ai_weap.c @@ -153,12 +153,12 @@ bot_weaponstate_t *BotWeaponStateFromHandle(int handle) { if (handle <= 0 || handle > MAX_CLIENTS) { - botimport.Print(PRT_FATAL, "move state handle %d out of range\n", handle); + botimport.Print(PRT_FATAL, "weapon state handle %d out of range\n", handle); return NULL; } //end if if (!botweaponstates[handle]) { - botimport.Print(PRT_FATAL, "invalid move state %d\n", handle); + botimport.Print(PRT_FATAL, "invalid weapon state %d\n", handle); return NULL; } //end if return botweaponstates[handle]; @@ -440,18 +440,6 @@ int BotChooseBestFightWeapon(int weaponstate, int *inventory) //=========================================================================== void BotResetWeaponState(int weaponstate) { - struct weightconfig_s *weaponweightconfig; - int *weaponweightindex; - bot_weaponstate_t *ws; - - ws = BotWeaponStateFromHandle(weaponstate); - if (!ws) return; - weaponweightconfig = ws->weaponweightconfig; - weaponweightindex = ws->weaponweightindex; - - //Com_Memset(ws, 0, sizeof(bot_weaponstate_t)); - ws->weaponweightconfig = weaponweightconfig; - ws->weaponweightindex = weaponweightindex; } //end of the function BotResetWeaponState //======================================================================== // @@ -483,12 +471,12 @@ void BotFreeWeaponState(int handle) { if (handle <= 0 || handle > MAX_CLIENTS) { - botimport.Print(PRT_FATAL, "move state handle %d out of range\n", handle); + botimport.Print(PRT_FATAL, "weapon state handle %d out of range\n", handle); return; } //end if if (!botweaponstates[handle]) { - botimport.Print(PRT_FATAL, "invalid move state %d\n", handle); + botimport.Print(PRT_FATAL, "invalid weapon state %d\n", handle); return; } //end if BotFreeWeaponWeights(handle); diff --git a/code/botlib/be_ai_weight.c b/code/botlib/be_ai_weight.c index 9f3d0f74..a6a478e3 100644 --- a/code/botlib/be_ai_weight.c +++ b/code/botlib/be_ai_weight.c @@ -272,7 +272,6 @@ fuzzyseperator_t *ReadFuzzySeperators_r(source_t *source) fs->child = NULL; if (lastfs) lastfs->next = fs; else firstfs = fs; - lastfs = fs; } //end if // return firstfs; diff --git a/code/botlib/be_interface.c b/code/botlib/be_interface.c index 394a7643..6f599753 100644 --- a/code/botlib/be_interface.c +++ b/code/botlib/be_interface.c @@ -144,19 +144,19 @@ int Export_BotLibSetup(void) if(botDeveloper) { - char *homedir, *gamedir, *basedir; + char *homedir, *gamedir, *basegame; char logfilename[MAX_OSPATH]; homedir = LibVarGetString("homedir"); gamedir = LibVarGetString("gamedir"); - basedir = LibVarGetString("com_basegame"); + basegame = LibVarGetString("basegame"); if (*homedir) { if(*gamedir) Com_sprintf(logfilename, sizeof(logfilename), "%s%c%s%cbotlib.log", homedir, PATH_SEP, gamedir, PATH_SEP); - else if(*basedir) - Com_sprintf(logfilename, sizeof(logfilename), "%s%c%s%cbotlib.log", homedir, PATH_SEP, basedir, PATH_SEP); + else if(*basegame) + Com_sprintf(logfilename, sizeof(logfilename), "%s%c%s%cbotlib.log", homedir, PATH_SEP, basegame, PATH_SEP); else Com_sprintf(logfilename, sizeof(logfilename), "%s%c" BASEGAME "%cbotlib.log", homedir, PATH_SEP, PATH_SEP); } @@ -546,7 +546,7 @@ int BotExportTest(int parm0, char *parm1, vec3_t parm2, vec3_t parm3) reachnum = BotGetReachabilityToGoal(origin, newarea, lastgoalareanum, lastareanum, avoidreach, avoidreachtimes, avoidreachtries, - &goal, TFL_DEFAULT|TFL_FUNCBOB|TFL_ROCKETJUMP, TFL_DEFAULT|TFL_FUNCBOB|TFL_ROCKETJUMP, + &goal, TFL_DEFAULT|TFL_FUNCBOB|TFL_ROCKETJUMP, NULL, 0, &resultFlags); AAS_ReachabilityFromNum(reachnum, &reach); AAS_ShowReachability(&reach); @@ -565,7 +565,7 @@ int BotExportTest(int parm0, char *parm1, vec3_t parm2, vec3_t parm3) reachnum = BotGetReachabilityToGoal(curorigin, curarea, lastgoalareanum, lastareanum, avoidreach, avoidreachtimes, avoidreachtries, - &goal, TFL_DEFAULT|TFL_FUNCBOB|TFL_ROCKETJUMP, TFL_DEFAULT|TFL_FUNCBOB|TFL_ROCKETJUMP, + &goal, TFL_DEFAULT|TFL_FUNCBOB|TFL_ROCKETJUMP, NULL, 0, &resultFlags); AAS_ReachabilityFromNum(reachnum, &reach); AAS_ShowReachability(&reach); diff --git a/code/botlib/botlib.h b/code/botlib/botlib.h index 9eaee0a6..abdaa688 100644 --- a/code/botlib/botlib.h +++ b/code/botlib/botlib.h @@ -437,9 +437,10 @@ botlib_export_t *GetBotLibAPI( int apiVersion, botlib_import_t *import ); name: default: module(s): description: -"basedir" "" l_utils.c base directory -"gamedir" "" l_utils.c game directory -"cddir" "" l_utils.c CD directory +"basedir" "" - base directory +"homedir" "" be_interface.c home directory +"gamedir" "" be_interface.c mod game directory +"basegame" "" be_interface.c base game directory "log" "0" l_log.c enable/disable creating a log file "maxclients" "4" be_interface.c maximum number of clients diff --git a/code/botlib/l_precomp.c b/code/botlib/l_precomp.c index e427d8a2..bfa7564c 100644 --- a/code/botlib/l_precomp.c +++ b/code/botlib/l_precomp.c @@ -414,7 +414,6 @@ int PC_ReadDefineParms(source_t *source, define_t *define, token_t **parms, int if (indent <= 0) { if (lastcomma) SourceWarning(source, "too many comma's"); - lastcomma = 1; break; } //end if } //end if @@ -783,7 +782,7 @@ int PC_ExpandBuiltinDefine(source_t *source, token_t *deftoken, define_t *define int PC_ExpandDefine(source_t *source, token_t *deftoken, define_t *define, token_t **firsttoken, token_t **lasttoken) { - token_t *parms[MAX_DEFINEPARMS], *dt, *pt, *t; + token_t *parms[MAX_DEFINEPARMS] = { NULL }, *dt, *pt, *t; token_t *t1, *t2, *first, *last, *nextpt, token; int parmnum, i; @@ -1209,12 +1208,6 @@ int PC_Directive_define(source_t *source) //unread the define name before executing the #undef directive PC_UnreadSourceToken(source, &token); if (!PC_Directive_undef(source)) return qfalse; - //if the define was not removed (define->flags & DEFINE_FIXED) -#if DEFINEHASHING - define = PC_FindHashedDefine(source->definehash, token.string); -#else - define = PC_FindDefine(source->defines, token.string); -#endif //DEFINEHASHING } //end if //allocate define define = (define_t *) GetMemory(sizeof(define_t)); @@ -2096,7 +2089,6 @@ int PC_EvaluateTokens(source_t *source, token_t *tokens, signed long int *intval if (v->prev) v->prev->next = v->next; else firstvalue = v->next; if (v->next) v->next->prev = v->prev; - else lastvalue = v->prev; //FreeMemory(v); FreeValue(v); } //end if @@ -2104,7 +2096,6 @@ int PC_EvaluateTokens(source_t *source, token_t *tokens, signed long int *intval if (o->prev) o->prev->next = o->next; else firstoperator = o->next; if (o->next) o->next->prev = o->prev; - else lastoperator = o->prev; //FreeMemory(o); FreeOperator(o); } //end while diff --git a/code/botlib/lcc.mak b/code/botlib/lcc.mak deleted file mode 100644 index f5567c3a..00000000 --- a/code/botlib/lcc.mak +++ /dev/null @@ -1,55 +0,0 @@ -# -# Makefile for Gladiator Bot library: gladiator.dll -# Intended for LCC-Win32 -# - -CC=lcc -CFLAGS=-DC_ONLY -o -OBJS= be_aas_bspq2.obj \ - be_aas_bsphl.obj \ - be_aas_cluster.obj \ - be_aas_debug.obj \ - be_aas_entity.obj \ - be_aas_file.obj \ - be_aas_light.obj \ - be_aas_main.obj \ - be_aas_move.obj \ - be_aas_optimize.obj \ - be_aas_reach.obj \ - be_aas_route.obj \ - be_aas_routealt.obj \ - be_aas_sample.obj \ - be_aas_sound.obj \ - be_ai2_dm.obj \ - be_ai2_dmnet.obj \ - be_ai2_main.obj \ - be_ai_char.obj \ - be_ai_chat.obj \ - be_ai_goal.obj \ - be_ai_load.obj \ - be_ai_move.obj \ - be_ai_weap.obj \ - be_ai_weight.obj \ - be_ea.obj \ - be_interface.obj \ - l_crc.obj \ - l_libvar.obj \ - l_log.obj \ - l_memory.obj \ - l_precomp.obj \ - l_script.obj \ - l_struct.obj \ - l_utils.obj \ - q_shared.obj - -all: gladiator.dll - -gladiator.dll: $(OBJS) - lcclnk -dll -entry GetBotAPI *.obj botlib.def -o gladiator.dll - -clean: - del *.obj gladiator.dll - -%.obj: %.c - $(CC) $(CFLAGS) $< - diff --git a/code/botlib/linux-i386.mak b/code/botlib/linux-i386.mak deleted file mode 100644 index c9607a7b..00000000 --- a/code/botlib/linux-i386.mak +++ /dev/null @@ -1,92 +0,0 @@ -# -# Makefile for Gladiator Bot library: gladiator.so -# Intended for gcc/Linux -# - -ARCH=i386 -CC=gcc -BASE_CFLAGS=-Dstricmp=strcasecmp - -#use these cflags to optimize it -CFLAGS=$(BASE_CFLAGS) -m486 -O6 -ffast-math -funroll-loops \ - -fomit-frame-pointer -fexpensive-optimizations -malign-loops=2 \ - -malign-jumps=2 -malign-functions=2 -#use these when debugging -#CFLAGS=$(BASE_CFLAGS) -g - -LDFLAGS=-ldl -lm -SHLIBEXT=so -SHLIBCFLAGS=-fPIC -SHLIBLDFLAGS=-shared - -DO_CC=$(CC) $(CFLAGS) $(SHLIBCFLAGS) -o $@ -c $< - -############################################################################# -# SETUP AND BUILD -# GLADIATOR BOT -############################################################################# - -.c.o: - $(DO_CC) - -GAME_OBJS = \ - be_aas_bsphl.o\ - be_aas_bspq2.o\ - be_aas_cluster.o\ - be_aas_debug.o\ - be_aas_entity.o\ - be_aas_file.o\ - be_aas_light.o\ - be_aas_main.o\ - be_aas_move.o\ - be_aas_optimize.o\ - be_aas_reach.o\ - be_aas_route.o\ - be_aas_routealt.o\ - be_aas_sample.o\ - be_aas_sound.o\ - be_ai2_dmq2.o\ - be_ai2_dmhl.o\ - be_ai2_dmnet.o\ - be_ai2_main.o\ - be_ai_char.o\ - be_ai_chat.o\ - be_ai_goal.o\ - be_ai_load.o\ - be_ai_move.o\ - be_ai_weap.o\ - be_ai_weight.o\ - be_ea.o\ - be_interface.o\ - l_crc.o\ - l_libvar.o\ - l_log.o\ - l_memory.o\ - l_precomp.o\ - l_script.o\ - l_struct.o\ - l_utils.o\ - q_shared.o - -glad$(ARCH).$(SHLIBEXT) : $(GAME_OBJS) - $(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(GAME_OBJS) - - -############################################################################# -# MISC -############################################################################# - -clean: - -rm -f $(GAME_OBJS) - -depend: - gcc -MM $(GAME_OBJS:.o=.c) - - -install: - cp gladiator.so .. - -# -# From "make depend" -# - diff --git a/code/cgame/cg_draw.c b/code/cgame/cg_draw.c index 9c02ecf7..613b7c8b 100644 --- a/code/cgame/cg_draw.c +++ b/code/cgame/cg_draw.c @@ -2992,7 +2992,7 @@ void CG_DrawActive(stereoFrame_t stereoView) // CG_DrawBigPolygon(); //Makro - sun flare - CG_AddLensFlare(qtrue); +// CG_AddLensFlare(qtrue); CG_SetupPostProcess(); @@ -3013,5 +3013,5 @@ void CG_DrawActive(stereoFrame_t stereoView) CG_Draw2D(); //Makro - reflection particles - CG_AddLensFlare(qfalse); +// CG_AddLensFlare(qfalse); } diff --git a/code/cgame/cg_local.h b/code/cgame/cg_local.h index 72cc4d7b..f6ac3d6b 100644 --- a/code/cgame/cg_local.h +++ b/code/cgame/cg_local.h @@ -404,8 +404,8 @@ // Copyright (C) 1999-2000 Id Software, Inc. // #include "../qcommon/q_shared.h" -#include "../renderer/tr_types.h" -#include "../rend2/tr_extratypes.h" +#include "../renderercommon/tr_types.h" +#include "../renderergl2/tr_extratypes.h" #include "../game/bg_public.h" #include "cg_public.h" @@ -2461,6 +2461,7 @@ void trap_SendConsoleCommand(const char *text); // register a command name so the console can perform command completion. // FIXME: replace this with a normal console command "defineCommand"? void trap_AddCommand(const char *cmdName); +void trap_RemoveCommand(const char *cmdName); // send a string to the server over the network void trap_SendClientCommand(const char *s); @@ -2477,9 +2478,17 @@ int trap_CM_PointContents(const vec3_t p, clipHandle_t model); int trap_CM_TransformedPointContents(const vec3_t p, clipHandle_t model, const vec3_t origin, const vec3_t angles); void trap_CM_BoxTrace(trace_t * results, const vec3_t start, const vec3_t end, const vec3_t mins, const vec3_t maxs, clipHandle_t model, int brushmask); +void trap_CM_CapsuleTrace( trace_t *results, const vec3_t start, const vec3_t end, + const vec3_t mins, const vec3_t maxs, + clipHandle_t model, int brushmask ); void trap_CM_TransformedBoxTrace(trace_t * results, const vec3_t start, const vec3_t end, const vec3_t mins, const vec3_t maxs, clipHandle_t model, int brushmask, const vec3_t origin, const vec3_t angles); +void trap_CM_TransformedCapsuleTrace( trace_t *results, const vec3_t start, const vec3_t end, + const vec3_t mins, const vec3_t maxs, + clipHandle_t model, int brushmask, + const vec3_t origin, const vec3_t angles ); + // Returns the projection of a polygon onto the solid brushes in the world int trap_CM_MarkFragments(int numPoints, const vec3_t * points, @@ -2524,6 +2533,7 @@ void trap_R_AddRefEntityToScene(const refEntity_t * re); void trap_R_AddPolyToScene(qhandle_t hShader, int numVerts, const polyVert_t * verts); void trap_R_AddPolysToScene(qhandle_t hShader, int numVerts, const polyVert_t * verts, int numPolys); void trap_R_AddLightToScene(const vec3_t org, float intensity, float r, float g, float b); +void trap_R_AddAdditiveLightToScene(const vec3_t org, float intensity, float r, float g, float b); int trap_R_LightForPoint(vec3_t point, vec3_t ambientLight, vec3_t directedLight, vec3_t lightDir); void trap_R_RenderScene(const refdef_t * fd); void trap_R_SetColor(const float *rgba); // NULL = 1,1,1,1 @@ -2533,6 +2543,7 @@ void trap_R_ModelBounds(clipHandle_t model, vec3_t mins, vec3_t maxs); int trap_R_LerpTag(orientation_t * tag, clipHandle_t mod, int startFrame, int endFrame, float frac, const char *tagName); void trap_R_RemapShader(const char *oldShader, const char *newShader, const char *timeOffset); +qboolean trap_R_inPVS(const vec3_t p1, const vec3_t p2); // The glconfig_t will not change during the life of a cgame. // If it needs to change, the entire cgame will be restarted, because @@ -2593,6 +2604,7 @@ void trap_CIN_DrawCinematic(int handle); void trap_CIN_SetExtents(int handle, int x, int y, int w, int h); void trap_SnapVector(float *v); +int trap_RealTime(qtime_t *qtime); qboolean trap_loadCamera(const char *name); void trap_startCamera(int time); @@ -2624,4 +2636,4 @@ void CG_DrawBigPolygon(void); void CG_ParticleHitSnow(vec3_t org, vec3_t vel, int duration, float x, float y, float speed, float scale); void CG_ParticleHitGrass(vec3_t org, vec3_t vel, int duration, float x, float y, float speed, float scale); void CG_ParticleHitWall(vec3_t org, vec3_t vel, int duration, float x, float y, float speed, float scale); -void CG_AddLensFlare(qboolean sun); +//void CG_AddLensFlare(qboolean sun); diff --git a/code/cgame/cg_view.c b/code/cgame/cg_view.c index 3762ffff..24f02d92 100644 --- a/code/cgame/cg_view.c +++ b/code/cgame/cg_view.c @@ -1144,6 +1144,7 @@ static void CG_PlayBufferedSounds(void) #define FLARE_BLIND_ALPHA 0.25f //Makro - lens flare +/* JBravo - Temporarily disabled void CG_AddLensFlare(qboolean sun) { vec3_t dir, dp; @@ -1269,7 +1270,7 @@ void CG_AddLensFlare(qboolean sun) } } } - +*/ static qboolean CG_UnderWater( void ) { return 0 != (CG_PointContents(cg.refdef.vieworg, -1) & (CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA)); diff --git a/code/cgame/cgame.q3asm b/code/cgame/cgame.q3asm deleted file mode 100644 index 410b37df..00000000 --- a/code/cgame/cgame.q3asm +++ /dev/null @@ -1,27 +0,0 @@ -cg_main -..\cg_syscalls -cg_atmospheric -cg_consolecmds -cg_draw -cg_drawtools -cg_effects -cg_ents -cg_event -cg_info -cg_localents -cg_marks -cg_players -cg_playerstate -cg_predict -cg_scoreboard -cg_servercmds -cg_snapshot -cg_unlagged -cg_view -cg_weapons -bg_slidemove -bg_pmove -bg_lib -bg_misc -q_math -q_shared diff --git a/code/cgame/cgame_ta.q3asm b/code/cgame/cgame_ta.q3asm deleted file mode 100644 index 629a7783..00000000 --- a/code/cgame/cgame_ta.q3asm +++ /dev/null @@ -1,28 +0,0 @@ --o "\quake3\missionpack\vm\cgame" -cg_main -..\cg_syscalls -cg_consolecmds -cg_draw -cg_drawtools -cg_effects -cg_ents -cg_event -cg_info -cg_localents -cg_marks -cg_players -cg_playerstate -cg_predict -cg_scoreboard -cg_servercmds -cg_snapshot -cg_view -cg_weapons -bg_slidemove -bg_pmove -bg_lib -bg_misc -q_math -q_shared -ui_shared -cg_newdraw diff --git a/code/cgame/make-cgame.bat b/code/cgame/make-cgame.bat deleted file mode 100644 index 16ca5cb2..00000000 --- a/code/cgame/make-cgame.bat +++ /dev/null @@ -1,87 +0,0 @@ -@echo off - -REM *** NOTE: THIS BATCH FILE IS MEANT TO BE CALLED BY make-qvm.bat! -REM *** NOTE: THIS CANNOT BE RUN BY ITSELF WITHOUT %make-qvm-location% BEING DEFINED! - -cd vm -set cc=q3lcc.exe -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\ui - - -echo. -echo *** Running Q3LCC for CGAME... - -REM ***Makro - bg_materials.c needed for the new surfaceparm system -%cc% ../../game/bg_materials.c -@if errorlevel 1 goto quit -%cc% ../../game/bg_misc.c -@if errorlevel 1 goto quit -%cc% ../../game/bg_pmove.c -@if errorlevel 1 goto quit -%cc% ../../game/bg_slidemove.c -@if errorlevel 1 goto quit -%cc% ../../game/bg_lib.c -@if errorlevel 1 goto quit - -%cc% ../../game/q_math.c -@if errorlevel 1 goto quit -%cc% ../../qcommon/q_shared.c -@if errorlevel 1 goto quit - -%cc% ../cg_atmospheric.c -@if errorlevel 1 goto quit -%cc% ../cg_consolecmds.c -@if errorlevel 1 goto quit -%cc% ../cg_draw.c -@if errorlevel 1 goto quit -%cc% ../cg_drawtools.c -@if errorlevel 1 goto quit -%cc% ../cg_effects.c -@if errorlevel 1 goto quit -%cc% ../cg_ents.c -@if errorlevel 1 goto quit -%cc% ../cg_event.c -@if errorlevel 1 goto quit -%cc% ../cg_info.c -@if errorlevel 1 goto quit -%cc% ../cg_localents.c -@if errorlevel 1 goto quit -%cc% ../cg_main.c -@if errorlevel 1 goto quit -%cc% ../cg_marks.c -@if errorlevel 1 goto quit -%cc% ../cg_players.c -@if errorlevel 1 goto quit -%cc% ../cg_playerstate.c -@if errorlevel 1 goto quit -%cc% ../cg_predict.c -@if errorlevel 1 goto quit -%cc% ../cg_scoreboard.c -@if errorlevel 1 goto quit -%cc% ../cg_servercmds.c -@if errorlevel 1 goto quit -%cc% ../cg_snapshot.c -@if errorlevel 1 goto quit -%cc% ../cg_unlagged.c -@if errorlevel 1 goto quit -%cc% ../cg_view.c -@if errorlevel 1 goto quit -%cc% ../cg_weapons.c -@if errorlevel 1 goto quit - -echo. -echo *** Running Q3ASM for CGAME... - -REM *** This tells q3asm to generate a vanilla q3-compatible qvm, generate a .map file, output -REM *** the resulting .qvm into "%make-qvm-location%bin\qvm\vm\cgame" (it will be called cgame.qvm), -REM *** and to compile the files listed in the cgame.q3asm script located in "%make-qvm-location%code/cgame/cgame". - -q3asm -vq3 -m -o "%make-qvm-location%bin\qvm\vm\cgame" -f "%make-qvm-location%code/cgame/cgame" - -:quit -if errorlevel 1 ( -echo. -echo ERROR IN Q3LCC PARSING! CGAME COMPILATION HALTED! -echo. -) -echo. -cd .. diff --git a/code/cgame/tr_types.h b/code/cgame/tr_types.h deleted file mode 100644 index 29e8e124..00000000 --- a/code/cgame/tr_types.h +++ /dev/null @@ -1,233 +0,0 @@ -//----------------------------------------------------------------------------- -// -// $Id$ -// -//----------------------------------------------------------------------------- -// -// $Log$ -// Revision 1.6 2003/04/19 17:41:26 jbravo -// Applied changes that where in 1.29h -> 1.32b gamecode. -// -// Revision 1.5 2002/06/16 20:06:13 jbravo -// Reindented all the source files with "indent -kr -ut -i8 -l120 -lc120 -sob -bad -bap" -// -// Revision 1.4 2002/01/11 19:48:29 jbravo -// Formatted the source in non DOS format. -// -// Revision 1.3 2001/12/31 16:28:41 jbravo -// I made a Booboo with the Log tag. -// -// -//----------------------------------------------------------------------------- -// Copyright (C) 1999-2000 Id Software, Inc. -// -#ifndef __TR_TYPES_H -#define __TR_TYPES_H - -#define MAX_DLIGHTS 32 // can't be increased, because bit flags are used on surfaces -#define MAX_ENTITIES 1023 // can't be increased without changing drawsurf bit packing - -// renderfx flags -#define RF_MINLIGHT 1 // allways have some light (viewmodel, some items) -#define RF_THIRD_PERSON 2 // don't draw through eyes, only mirrors (player bodies, chat sprites) -#define RF_FIRST_PERSON 4 // only draw through eyes (view weapon, damage blood blob) -#define RF_DEPTHHACK 8 // for view weapon Z crunching -#define RF_NOSHADOW 64 // don't add stencil shadows - -#define RF_LIGHTING_ORIGIN 128 // use refEntity->lightingOrigin instead of refEntity->origin - // for lighting. This allows entities to sink into the floor - // with their origin going solid, and allows all parts of a - // player to get the same lighting -#define RF_SHADOW_PLANE 256 // use refEntity->shadowPlane -#define RF_WRAP_FRAMES 512 // mod the model frames by the maxframes to allow continuous - // animation without needing to know the frame count - -#define RF_SUNFLARE 1024 - -// refdef flags -#define RDF_NOWORLDMODEL 1 // used for player configuration screen -#define RDF_HYPERSPACE 4 // teleportation effect -#define RDF_NOFOG 8 -#define RDF_EXTRA 0x0010 // Makro - refdefex_t to follow after refdef_t - -typedef struct { - float blurFactor; -} refdefex_t; - -typedef struct { - vec3_t xyz; - float st[2]; - byte modulate[4]; -} polyVert_t; - -typedef struct poly_s { - qhandle_t hShader; - int numVerts; - polyVert_t *verts; -} poly_t; - -typedef enum { - RT_MODEL, - RT_POLY, - RT_SPRITE, - RT_BEAM, - RT_RAIL_CORE, - RT_RAIL_RINGS, - RT_LIGHTNING, - RT_PORTALSURFACE, // doesn't draw anything, just info for portals - - RT_MAX_REF_ENTITY_TYPE -} refEntityType_t; - -typedef struct { - refEntityType_t reType; - int renderfx; - - qhandle_t hModel; // opaque type outside refresh - - // most recent data - vec3_t lightingOrigin; // so multi-part models can be lit identically (RF_LIGHTING_ORIGIN) - float shadowPlane; // projection shadows go here, stencils go slightly lower - - vec3_t axis[3]; // rotation vectors - qboolean nonNormalizedAxes; // axis are not normalized, i.e. they have scale - float origin[3]; // also used as MODEL_BEAM's "from" - int frame; // also used as MODEL_BEAM's diameter - - // previous data for frame interpolation - float oldorigin[3]; // also used as MODEL_BEAM's "to" - int oldframe; - float backlerp; // 0.0 = current, 1.0 = old - - // texturing - int skinNum; // inline skin index - qhandle_t customSkin; // NULL for default skin - qhandle_t customShader; // use one image for the entire thing - - // misc - byte shaderRGBA[4]; // colors used by rgbgen entity shaders - float shaderTexCoord[2]; // texture coordinates used by tcMod entity modifiers - float shaderTime; // subtracted from refdef time to control effect start times - - // extra sprite information - float radius; - float rotation; -} refEntity_t; - -#define MAX_RENDER_STRINGS 8 -#define MAX_RENDER_STRING_LENGTH 32 - -typedef struct { - int x, y, width, height; - float fov_x, fov_y; - vec3_t vieworg; - vec3_t viewaxis[3]; // transformation matrix - - // time in milliseconds for shader effects and other time dependent rendering issues - int time; - - int rdflags; // RDF_NOWORLDMODEL, etc - - // 1 bits will prevent the associated area from rendering at all - byte areamask[MAX_MAP_AREA_BYTES]; - - // text messages for deform text shaders - char text[MAX_RENDER_STRINGS][MAX_RENDER_STRING_LENGTH]; -} refdef_t; - -typedef enum { - STEREO_CENTER, - STEREO_LEFT, - STEREO_RIGHT -} stereoFrame_t; - -/* -** glconfig_t -** -** Contains variables specific to the OpenGL configuration -** being run right now. These are constant once the OpenGL -** subsystem is initialized. -*/ -typedef enum { - TC_NONE, - TC_S3TC -} textureCompression_t; - -typedef enum { - GLDRV_ICD, // driver is integrated with window system - // WARNING: there are tests that check for - // > GLDRV_ICD for minidriverness, so this - // should always be the lowest value in this - // enum set - GLDRV_STANDALONE, // driver is a non-3Dfx standalone driver - GLDRV_VOODOO // driver is a 3Dfx standalone driver -} glDriverType_t; - -typedef enum { - GLHW_GENERIC, // where everthing works the way it should - GLHW_3DFX_2D3D, // Voodoo Banshee or Voodoo3, relevant since if this is - // the hardware type then there can NOT exist a secondary - // display adapter - GLHW_RIVA128, // where you can't interpolate alpha - GLHW_RAGEPRO, // where you can't modulate alpha on alpha textures - GLHW_PERMEDIA2 // where you don't have src*dst -} glHardwareType_t; - -typedef struct { - char renderer_string[MAX_STRING_CHARS]; - char vendor_string[MAX_STRING_CHARS]; - char version_string[MAX_STRING_CHARS]; - char extensions_string[BIG_INFO_STRING]; - - int maxTextureSize; // queried from GL - int maxActiveTextures; // multitexture ability - - int colorBits, depthBits, stencilBits; - - glDriverType_t driverType; - glHardwareType_t hardwareType; - - qboolean deviceSupportsGamma; - textureCompression_t textureCompression; - qboolean textureEnvAddAvailable; - - int vidWidth, vidHeight; - // aspect is the screen's physical width / height, which may be different - // than scrWidth / scrHeight if the pixels are non-square - // normal screens should be 4/3, but wide aspect monitors may be 16/9 - float windowAspect; - - int displayFrequency; - - // synonymous with "does rendering consume the entire screen?", therefore - // a Voodoo or Voodoo2 will have this set to TRUE, as will a Win32 ICD that - // used CDS. - qboolean isFullscreen; - qboolean stereoEnabled; - qboolean smpActive; // dual processor -} glconfig_t; - -// FIXME: VM should be OS agnostic .. in theory - -/* -#ifdef Q3_VM - -#define _3DFX_DRIVER_NAME "Voodoo" -#define OPENGL_DRIVER_NAME "Default" - -#elif defined(_WIN32) -*/ - -#if defined(Q3_VM) || defined(_WIN32) - -#define _3DFX_DRIVER_NAME "3dfxvgl" -#define OPENGL_DRIVER_NAME "opengl32" - -#else - -#define _3DFX_DRIVER_NAME "libMesaVoodooGL.so" -// https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=524 -#define OPENGL_DRIVER_NAME "libGL.so.1" - -#endif // !defined _WIN32 -#endif // __TR_TYPES_H diff --git a/code/client/cl_cin.c b/code/client/cl_cin.c index 8d6f51c5..45c4dd45 100644 --- a/code/client/cl_cin.c +++ b/code/client/cl_cin.c @@ -1158,7 +1158,6 @@ redump: if (cinTable[currentHandle].numQuads == -1) { readQuadInfo( framedata ); setupQuad( 0, 0 ); - // we need to use CL_ScaledMilliseconds because of the smp mode calls from the renderer cinTable[currentHandle].startTime = cinTable[currentHandle].lastTime = CL_ScaledMilliseconds()*com_timescale->value; } if (cinTable[currentHandle].numQuads != 1) cinTable[currentHandle].numQuads = 0; @@ -1226,7 +1225,6 @@ redump: static void RoQ_init( void ) { - // we need to use CL_ScaledMilliseconds because of the smp mode calls from the renderer cinTable[currentHandle].startTime = cinTable[currentHandle].lastTime = CL_ScaledMilliseconds()*com_timescale->value; cinTable[currentHandle].RoQPlayed = 24; @@ -1358,12 +1356,10 @@ e_status CIN_RunCinematic (int handle) return cinTable[currentHandle].status; } - // we need to use CL_ScaledMilliseconds because of the smp mode calls from the renderer thisTime = CL_ScaledMilliseconds()*com_timescale->value; if (cinTable[currentHandle].shader && (abs(thisTime - cinTable[currentHandle].lastTime))>100) { cinTable[currentHandle].startTime += thisTime - cinTable[currentHandle].lastTime; } - // we need to use CL_ScaledMilliseconds because of the smp mode calls from the renderer cinTable[currentHandle].tfps = ((((CL_ScaledMilliseconds()*com_timescale->value) - cinTable[currentHandle].startTime)*3)/100); start = cinTable[currentHandle].startTime; @@ -1372,7 +1368,6 @@ e_status CIN_RunCinematic (int handle) { RoQInterrupt(); if (start != cinTable[currentHandle].startTime) { - // we need to use CL_ScaledMilliseconds because of the smp mode calls from the renderer cinTable[currentHandle].tfps = ((((CL_ScaledMilliseconds()*com_timescale->value) - cinTable[currentHandle].startTime)*3)/100); start = cinTable[currentHandle].startTime; diff --git a/code/client/cl_console.c b/code/client/cl_console.c index 3d5ef021..d1b9fec1 100644 --- a/code/client/cl_console.c +++ b/code/client/cl_console.c @@ -53,8 +53,6 @@ typedef struct { vec4_t color; } console_t; -extern console_t con; - console_t con; cvar_t *con_conspeed; @@ -81,6 +79,16 @@ void Con_ToggleConsole_f (void) { Key_SetCatcher( Key_GetCatcher( ) ^ KEYCATCH_CONSOLE ); } +/* +=================== +Con_ToggleMenu_f +=================== +*/ +void Con_ToggleMenu_f( void ) { + CL_KeyEvent( K_ESCAPE, qtrue, Sys_Milliseconds() ); + CL_KeyEvent( K_ESCAPE, qfalse, Sys_Milliseconds() ); +} + /* ================ Con_MessageMode_f @@ -170,7 +178,9 @@ void Con_Dump_f (void) int l, x, i; short *line; fileHandle_t f; - char buffer[1024]; + int bufferlen; + char *buffer; + char filename[MAX_QPATH]; if (Cmd_Argc() != 2) { @@ -178,15 +188,18 @@ void Con_Dump_f (void) return; } - Com_Printf ("Dumped console text to %s.\n", Cmd_Argv(1) ); + Q_strncpyz( filename, Cmd_Argv( 1 ), sizeof( filename ) ); + COM_DefaultExtension( filename, sizeof( filename ), ".txt" ); - f = FS_FOpenFileWrite( Cmd_Argv( 1 ) ); + f = FS_FOpenFileWrite( filename ); if (!f) { - Com_Printf ("ERROR: couldn't open.\n"); + Com_Printf ("ERROR: couldn't open %s.\n", filename); return; } + Com_Printf ("Dumped console text to %s.\n", filename ); + // skip empty lines for (l = con.current - con.totallines + 1 ; l <= con.current ; l++) { @@ -198,8 +211,16 @@ void Con_Dump_f (void) break; } +#ifdef _WIN32 + bufferlen = con.linewidth + 3 * sizeof ( char ); +#else + bufferlen = con.linewidth + 2 * sizeof ( char ); +#endif + + buffer = Hunk_AllocateTempMemory( bufferlen ); + // write the remaining lines - buffer[con.linewidth] = 0; + buffer[bufferlen-1] = 0; for ( ; l <= con.current ; l++) { line = con.text + (l%con.totallines)*con.linewidth; @@ -212,10 +233,15 @@ void Con_Dump_f (void) else break; } - strcat( buffer, "\n" ); +#ifdef _WIN32 + Q_strcat(buffer, bufferlen, "\r\n"); +#else + Q_strcat(buffer, bufferlen, "\n"); +#endif FS_Write(buffer, strlen(buffer), f); } + Hunk_FreeTempMemory( buffer ); FS_FCloseFile( f ); } @@ -332,6 +358,7 @@ void Con_Init (void) { CL_LoadConsoleHistory( ); Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f); + Cmd_AddCommand ("togglemenu", Con_ToggleMenu_f); Cmd_AddCommand ("messagemode", Con_MessageMode_f); Cmd_AddCommand ("messagemode2", Con_MessageMode2_f); Cmd_AddCommand ("messagemode3", Con_MessageMode3_f); @@ -349,6 +376,7 @@ Con_Shutdown void Con_Shutdown(void) { Cmd_RemoveCommand("toggleconsole"); + Cmd_RemoveCommand("togglemenu"); Cmd_RemoveCommand("messagemode"); Cmd_RemoveCommand("messagemode2"); Cmd_RemoveCommand("messagemode3"); @@ -587,8 +615,6 @@ void Con_DrawNotify (void) Field_BigDraw( &chatField, skip * BIGCHAR_WIDTH, v, SCREEN_WIDTH - ( skip + 1 ) * BIGCHAR_WIDTH, qtrue, qtrue ); - - v += BIGCHAR_HEIGHT; } } diff --git a/code/client/cl_curl.c b/code/client/cl_curl.c index 3debd6ed..901ef999 100644 --- a/code/client/cl_curl.c +++ b/code/client/cl_curl.c @@ -304,7 +304,7 @@ void CL_cURL_PerformDownload(void) } FS_FCloseFile(clc.download); if(msg->msg == CURLMSG_DONE && msg->data.result == CURLE_OK) { - FS_SV_Rename(clc.downloadTempName, clc.downloadName); + FS_SV_Rename(clc.downloadTempName, clc.downloadName, qfalse); clc.downloadRestart = qtrue; } else { diff --git a/code/client/cl_keys.c b/code/client/cl_keys.c index 8438fa11..7d797199 100644 --- a/code/client/cl_keys.c +++ b/code/client/cl_keys.c @@ -800,7 +800,7 @@ int Key_StringToKeynum( char *str ) { return -1; } if ( !str[1] ) { - return str[0]; + return tolower( str[0] ); } // check for hex code @@ -993,9 +993,9 @@ void Key_Bind_f (void) if (c == 2) { if (keys[b].binding) - Com_Printf ("\"%s\" = \"%s\"\n", Cmd_Argv(1), keys[b].binding ); + Com_Printf ("\"%s\" = \"%s\"\n", Key_KeynumToString(b), keys[b].binding ); else - Com_Printf ("\"%s\" is not bound\n", Cmd_Argv(1) ); + Com_Printf ("\"%s\" is not bound\n", Key_KeynumToString(b) ); return; } @@ -1120,6 +1120,25 @@ void CL_InitKeyCommands( void ) { Cmd_AddCommand ("bindlist",Key_Bindlist_f); } +/* +=================== +CL_BindUICommand + +Returns qtrue if bind command should be executed while user interface is shown +=================== +*/ +static qboolean CL_BindUICommand( const char *cmd ) { + if ( Key_GetCatcher( ) & KEYCATCH_CONSOLE ) + return qfalse; + + if ( !Q_stricmp( cmd, "toggleconsole" ) ) + return qtrue; + if ( !Q_stricmp( cmd, "togglemenu" ) ) + return qtrue; + + return qfalse; +} + /* =================== CL_ParseBinding @@ -1130,11 +1149,20 @@ Execute the commands in the bind string void CL_ParseBinding( int key, qboolean down, unsigned time ) { char buf[ MAX_STRING_CHARS ], *p = buf, *end; + qboolean allCommands, allowUpCmds; + if( clc.state == CA_DISCONNECTED && Key_GetCatcher( ) == 0 ) + return; if( !keys[key].binding || !keys[key].binding[0] ) return; Q_strncpyz( buf, keys[key].binding, sizeof( buf ) ); + // run all bind commands if console, ui, etc aren't reading keys + allCommands = ( Key_GetCatcher( ) == 0 ); + + // allow button up commands if in game even if key catcher is set + allowUpCmds = ( clc.state != CA_DISCONNECTED ); + while( 1 ) { while( isspace( *p ) ) @@ -1147,16 +1175,20 @@ void CL_ParseBinding( int key, qboolean down, unsigned time ) // button commands add keynum and time as parameters // so that multiple sources can be discriminated and // subframe corrected - char cmd[1024]; - Com_sprintf( cmd, sizeof( cmd ), "%c%s %d %d\n", - ( down ) ? '+' : '-', p + 1, key, time ); - Cbuf_AddText( cmd ); + if ( allCommands || ( allowUpCmds && !down ) ) { + char cmd[1024]; + Com_sprintf( cmd, sizeof( cmd ), "%c%s %d %d\n", + ( down ) ? '+' : '-', p + 1, key, time ); + Cbuf_AddText( cmd ); + } } else if( down ) { // normal commands only execute on key press - Cbuf_AddText( p ); - Cbuf_AddText( "\n" ); + if ( allCommands || CL_BindUICommand( p ) ) { + Cbuf_AddText( p ); + Cbuf_AddText( "\n" ); + } } if( !end ) break; @@ -1250,11 +1282,10 @@ void CL_KeyDownEvent( int key, unsigned time ) Message_Key( key ); } else if ( clc.state == CA_DISCONNECTED ) { Console_Key( key ); - } else { - // send the bound action - CL_ParseBinding( key, qtrue, time ); } - return; + + // send the bound action + CL_ParseBinding( key, qtrue, time ); } /* @@ -1285,8 +1316,7 @@ void CL_KeyUpEvent( int key, unsigned time ) // console mode and menu mode, to keep the character from continuing // an action started before a mode switch. // - if( clc.state != CA_DISCONNECTED ) - CL_ParseBinding( key, qfalse, time ); + CL_ParseBinding( key, qfalse, time ); if ( Key_GetCatcher( ) & KEYCATCH_UI && uivm ) { VM_Call( uivm, UI_KEY_EVENT, key, qfalse ); diff --git a/code/client/cl_main.c b/code/client/cl_main.c index 494eb587..ad317e5b 100644 --- a/code/client/cl_main.c +++ b/code/client/cl_main.c @@ -256,7 +256,7 @@ void CL_Voip_f( void ) reason = "Speex not initialized"; else if (!clc.voipEnabled) reason = "Server doesn't support VoIP"; - else if ( Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER || Cvar_VariableValue("ui_singlePlayerActive")) + else if (!clc.demoplaying && (Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER || Cvar_VariableValue("ui_singlePlayerActive"))) reason = "running in single-player mode"; if (reason != NULL) { @@ -1142,13 +1142,13 @@ void CL_PlayDemo_f( void ) { Com_Error( ERR_DROP, "couldn't open %s", name); return; } - Q_strncpyz( clc.demoName, Cmd_Argv(1), sizeof( clc.demoName ) ); + Q_strncpyz( clc.demoName, arg, sizeof( clc.demoName ) ); Con_Close(); clc.state = CA_CONNECTED; clc.demoplaying = qtrue; - Q_strncpyz( clc.servername, Cmd_Argv(1), sizeof( clc.servername ) ); + Q_strncpyz( clc.servername, arg, sizeof( clc.servername ) ); #ifdef LEGACY_PROTOCOL if(protocol <= com_legacyprotocol->integer) @@ -3070,11 +3070,18 @@ CL_ShutdownRef ============ */ void CL_ShutdownRef( void ) { - if ( !re.Shutdown ) { - return; + if ( re.Shutdown ) { + re.Shutdown( qtrue ); } - re.Shutdown( qtrue ); + Com_Memset( &re, 0, sizeof( re ) ); + +#ifdef USE_RENDERER_DLOPEN + if ( rendererLib ) { + Sys_UnloadLibrary( rendererLib ); + rendererLib = NULL; + } +#endif } /* @@ -3169,7 +3176,7 @@ void CL_InitRef( void ) { Com_Printf( "----- Initializing Renderer ----\n" ); #ifdef USE_RENDERER_DLOPEN - cl_renderer = Cvar_Get("cl_renderer", "rend2", CVAR_ARCHIVE | CVAR_LATCH); + cl_renderer = Cvar_Get("cl_renderer", "opengl2", CVAR_ARCHIVE | CVAR_LATCH); Com_sprintf(dllName, sizeof(dllName), "renderer_%s_" ARCH_STRING DLL_EXT, cl_renderer->string); @@ -4145,6 +4152,9 @@ void CL_GlobalServers_f( void ) { com_gamename->string, Cmd_Argv(2)); } } + else if ( !Q_stricmp( com_gamename->string, LEGACY_MASTER_GAMENAME ) ) + Com_sprintf(command, sizeof(command), "getservers %s", + Cmd_Argv(2)); else Com_sprintf(command, sizeof(command), "getservers %s %s", com_gamename->string, Cmd_Argv(2)); diff --git a/code/client/cl_parse.c b/code/client/cl_parse.c index f64c9da7..a424aa59 100644 --- a/code/client/cl_parse.c +++ b/code/client/cl_parse.c @@ -252,7 +252,7 @@ void CL_ParseSnapshot( msg_t *msg ) { // The frame that the server did the delta from // is too old, so we can't reconstruct it properly. Com_Printf ("Delta frame too old.\n"); - } else if ( cl.parseEntitiesNum - old->parseEntitiesNum > MAX_PARSE_ENTITIES-128 ) { + } else if ( cl.parseEntitiesNum - old->parseEntitiesNum > MAX_PARSE_ENTITIES - MAX_SNAPSHOT_ENTITIES ) { Com_Printf ("Delta parseEntitiesNum too old.\n"); } else { newSnap.valid = qtrue; // valid delta parse @@ -352,11 +352,6 @@ void CL_SystemInfoChanged( void ) { // in some cases, outdated cp commands might get sent with this news serverId cl.serverId = atoi( Info_ValueForKey( systemInfo, "sv_serverid" ) ); - // don't set any vars when playing a demo - if ( clc.demoplaying ) { - return; - } - #ifdef USE_VOIP #ifdef LEGACY_PROTOCOL if(clc.compat) @@ -365,13 +360,15 @@ void CL_SystemInfoChanged( void ) { #endif { s = Info_ValueForKey( systemInfo, "sv_voip" ); - if ( Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER || Cvar_VariableValue("ui_singlePlayerActive")) - clc.voipEnabled = qfalse; - else - clc.voipEnabled = atoi(s); + clc.voipEnabled = atoi(s); } #endif + // don't set any vars when playing a demo + if ( clc.demoplaying ) { + return; + } + s = Info_ValueForKey( systemInfo, "sv_cheats" ); cl_connectedToCheatServer = atoi( s ); if ( !cl_connectedToCheatServer ) { @@ -637,7 +634,7 @@ void CL_ParseDownload ( msg_t *msg ) { clc.download = 0; // rename the file - FS_SV_Rename ( clc.downloadTempName, clc.downloadName ); + FS_SV_Rename ( clc.downloadTempName, clc.downloadName, qfalse ); } // send intentions now @@ -789,7 +786,6 @@ void CL_ParseVoip ( msg_t *msg ) { } for (i = 0; i < frames; i++) { - char encoded[256]; const int len = MSG_ReadByte(msg); if (len < 0) { Com_DPrintf("VoIP: Short packet!\n"); diff --git a/code/client/cl_ui.c b/code/client/cl_ui.c index 8d2afa0d..2c1519a3 100644 --- a/code/client/cl_ui.c +++ b/code/client/cl_ui.c @@ -146,7 +146,7 @@ static int LAN_AddServer(int source, const char *name, const char *address) { break; } if (servers && *count < max) { - NET_StringToAdr( address, &adr, NA_IP ); + NET_StringToAdr( address, &adr, NA_UNSPEC ); for ( i = 0; i < *count; i++ ) { if (NET_CompareAdr(servers[i].adr, adr)) { break; @@ -190,7 +190,7 @@ static void LAN_RemoveServer(int source, const char *addr) { } if (servers) { netadr_t comp; - NET_StringToAdr( addr, &comp, NA_IP ); + NET_StringToAdr( addr, &comp, NA_UNSPEC ); for (i = 0; i < *count; i++) { if (NET_CompareAdr( comp, servers[i].adr)) { int j = i; @@ -750,7 +750,7 @@ intptr_t CL_UISystemCalls( intptr_t *args ) { return 0; case UI_CVAR_CREATE: - Cvar_Get( VMA(1), VMA(2), args[3] ); + Cvar_Register( NULL, VMA(1), VMA(2), args[3] ); return 0; case UI_CVAR_INFOSTRINGBUFFER: diff --git a/code/client/client.h b/code/client/client.h index 19f00249..a6155555 100644 --- a/code/client/client.h +++ b/code/client/client.h @@ -23,7 +23,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "../qcommon/q_shared.h" #include "../qcommon/qcommon.h" -#include "../renderer/tr_public.h" +#include "../renderercommon/tr_public.h" #include "../ui/ui_public.h" #include "keys.h" #include "snd_public.h" @@ -87,7 +87,7 @@ typedef struct { // the parseEntities array must be large enough to hold PACKET_BACKUP frames of // entities, so that when a delta compressed message arives from the server // it can be un-deltad from the original -#define MAX_PARSE_ENTITIES 2048 +#define MAX_PARSE_ENTITIES ( PACKET_BACKUP * MAX_SNAPSHOT_ENTITIES ) extern int g_console_field_width; diff --git a/code/client/snd_adpcm.c b/code/client/snd_adpcm.c index 89e68f42..4e138726 100644 --- a/code/client/snd_adpcm.c +++ b/code/client/snd_adpcm.c @@ -310,7 +310,7 @@ void S_AdpcmEncodeSound( sfx_t *sfx, short *samples ) { newchunk = SND_malloc(); if (sfx->soundData == NULL) { sfx->soundData = newchunk; - } else { + } else if (chunk != NULL) { chunk->next = newchunk; } chunk = newchunk; diff --git a/code/client/snd_codec.c b/code/client/snd_codec.c index ddddb71a..b1923277 100644 --- a/code/client/snd_codec.c +++ b/code/client/snd_codec.c @@ -124,6 +124,10 @@ void S_CodecInit() { codecs = NULL; +#ifdef USE_CODEC_OPUS + S_CodecRegister(&opus_codec); +#endif + #ifdef USE_CODEC_VORBIS S_CodecRegister(&ogg_codec); #endif diff --git a/code/client/snd_codec.h b/code/client/snd_codec.h index 03fcaa25..5ab1202f 100644 --- a/code/client/snd_codec.h +++ b/code/client/snd_codec.h @@ -95,4 +95,13 @@ void S_OGG_CodecCloseStream(snd_stream_t *stream); int S_OGG_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer); #endif // USE_CODEC_VORBIS +// Ogg Opus codec +#ifdef USE_CODEC_OPUS +extern snd_codec_t opus_codec; +void *S_OggOpus_CodecLoad(const char *filename, snd_info_t *info); +snd_stream_t *S_OggOpus_CodecOpenStream(const char *filename); +void S_OggOpus_CodecCloseStream(snd_stream_t *stream); +int S_OggOpus_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer); +#endif // USE_CODEC_OPUS + #endif // !_SND_CODEC_H_ diff --git a/code/client/snd_codec_opus.c b/code/client/snd_codec_opus.c new file mode 100644 index 00000000..190aee9a --- /dev/null +++ b/code/client/snd_codec_opus.c @@ -0,0 +1,452 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. +Copyright (C) 2005 Stuart Dalton (badcdev@gmail.com) +Copyright (C) 2005-2006 Joerg Dietrich + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake III Arena source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +// Ogg Opus support is enabled by this define +#ifdef USE_CODEC_OPUS + +// includes for the Q3 sound system +#include "client.h" +#include "snd_codec.h" + +// includes for the Ogg Opus codec +#include +#include + +// samples are 16 bit +#define OPUS_SAMPLEWIDTH 2 + +// Q3 Ogg Opus codec +snd_codec_t opus_codec = +{ + "opus", + S_OggOpus_CodecLoad, + S_OggOpus_CodecOpenStream, + S_OggOpus_CodecReadStream, + S_OggOpus_CodecCloseStream, + NULL +}; + +// callbacks for opusfile + +// fread() replacement +int S_OggOpus_Callback_read(void *datasource, unsigned char *ptr, int size ) +{ + snd_stream_t *stream; + int bytesRead = 0; + + // check if input is valid + if(!ptr) + { + errno = EFAULT; + return -1; + } + + if(!size) + { + // It's not an error, caller just wants zero bytes! + errno = 0; + return 0; + } + + if (size < 0) + { + errno = EINVAL; + return -1; + } + + if(!datasource) + { + errno = EBADF; + return -1; + } + + // we use a snd_stream_t in the generic pointer to pass around + stream = (snd_stream_t *) datasource; + + // read it with the Q3 function FS_Read() + bytesRead = FS_Read(ptr, size, stream->file); + + // update the file position + stream->pos += bytesRead; + + return bytesRead; +} + +// fseek() replacement +int S_OggOpus_Callback_seek(void *datasource, opus_int64 offset, int whence) +{ + snd_stream_t *stream; + int retVal = 0; + + // check if input is valid + if(!datasource) + { + errno = EBADF; + return -1; + } + + // snd_stream_t in the generic pointer + stream = (snd_stream_t *) datasource; + + // we must map the whence to its Q3 counterpart + switch(whence) + { + case SEEK_SET : + { + // set the file position in the actual file with the Q3 function + retVal = FS_Seek(stream->file, (long) offset, FS_SEEK_SET); + + // something has gone wrong, so we return here + if(retVal < 0) + { + return retVal; + } + + // keep track of file position + stream->pos = (int) offset; + break; + } + + case SEEK_CUR : + { + // set the file position in the actual file with the Q3 function + retVal = FS_Seek(stream->file, (long) offset, FS_SEEK_CUR); + + // something has gone wrong, so we return here + if(retVal < 0) + { + return retVal; + } + + // keep track of file position + stream->pos += (int) offset; + break; + } + + case SEEK_END : + { + // Quake 3 seems to have trouble with FS_SEEK_END + // so we use the file length and FS_SEEK_SET + + // set the file position in the actual file with the Q3 function + retVal = FS_Seek(stream->file, (long) stream->length + (long) offset, FS_SEEK_SET); + + // something has gone wrong, so we return here + if(retVal < 0) + { + return retVal; + } + + // keep track of file position + stream->pos = stream->length + (int) offset; + break; + } + + default : + { + // unknown whence, so we return an error + errno = EINVAL; + return -1; + } + } + + // stream->pos shouldn't be smaller than zero or bigger than the filesize + stream->pos = (stream->pos < 0) ? 0 : stream->pos; + stream->pos = (stream->pos > stream->length) ? stream->length : stream->pos; + + return 0; +} + +// fclose() replacement +int S_OggOpus_Callback_close(void *datasource) +{ + // we do nothing here and close all things manually in S_OggOpus_CodecCloseStream() + return 0; +} + +// ftell() replacement +opus_int64 S_OggOpus_Callback_tell(void *datasource) +{ + snd_stream_t *stream; + + // check if input is valid + if(!datasource) + { + errno = EBADF; + return -1; + } + + // snd_stream_t in the generic pointer + stream = (snd_stream_t *) datasource; + + return (opus_int64) FS_FTell(stream->file); +} + +// the callback structure +const OpusFileCallbacks S_OggOpus_Callbacks = +{ + &S_OggOpus_Callback_read, + &S_OggOpus_Callback_seek, + &S_OggOpus_Callback_tell, + &S_OggOpus_Callback_close +}; + +/* +================= +S_OggOpus_CodecOpenStream +================= +*/ +snd_stream_t *S_OggOpus_CodecOpenStream(const char *filename) +{ + snd_stream_t *stream; + + // Opus codec control structure + OggOpusFile *of; + + // some variables used to get informations about the file + const OpusHead *opusInfo; + ogg_int64_t numSamples; + + // check if input is valid + if(!filename) + { + return NULL; + } + + // Open the stream + stream = S_CodecUtilOpen(filename, &opus_codec); + if(!stream) + { + return NULL; + } + + // open the codec with our callbacks and stream as the generic pointer + of = op_open_callbacks(stream, &S_OggOpus_Callbacks, NULL, 0, NULL ); + if (!of) + { + S_CodecUtilClose(&stream); + + return NULL; + } + + // the stream must be seekable + if(!op_seekable(of)) + { + op_free(of); + + S_CodecUtilClose(&stream); + + return NULL; + } + + // get the info about channels and rate + opusInfo = op_head(of, -1); + if(!opusInfo) + { + op_free(of); + + S_CodecUtilClose(&stream); + + return NULL; + } + + if(opusInfo->stream_count != 1) + { + op_free(of); + + S_CodecUtilClose(&stream); + + Com_Printf("Only Ogg Opus files with one stream are support\n"); + return NULL; + } + + if(opusInfo->channel_count != 1 && opusInfo->channel_count != 2) + { + op_free(of); + + S_CodecUtilClose(&stream); + + Com_Printf("Only mono and stereo Ogg Opus files are supported\n"); + return NULL; + } + + // get the number of sample-frames in the file + numSamples = op_pcm_total(of, -1); + + // fill in the info-structure in the stream + stream->info.rate = 48000; + stream->info.width = OPUS_SAMPLEWIDTH; + stream->info.channels = opusInfo->channel_count; + stream->info.samples = numSamples; + stream->info.size = stream->info.samples * stream->info.channels * stream->info.width; + stream->info.dataofs = 0; + + // We use stream->pos for the file pointer in the compressed ogg file + stream->pos = 0; + + // We use the generic pointer in stream for the opus codec control structure + stream->ptr = of; + + return stream; +} + +/* +================= +S_OggOpus_CodecCloseStream +================= +*/ +void S_OggOpus_CodecCloseStream(snd_stream_t *stream) +{ + // check if input is valid + if(!stream) + { + return; + } + + // let the opus codec cleanup its stuff + op_free((OggOpusFile *) stream->ptr); + + // close the stream + S_CodecUtilClose(&stream); +} + +/* +================= +S_OggOpus_CodecReadStream +================= +*/ +int S_OggOpus_CodecReadStream(snd_stream_t *stream, int bytes, void *buffer) +{ + // buffer handling + int samplesRead, samplesLeft, c; + opus_int16 *bufPtr; + + // check if input is valid + if(!(stream && buffer)) + { + return 0; + } + + if(bytes <= 0) + { + return 0; + } + + samplesRead = 0; + samplesLeft = bytes / stream->info.channels / stream->info.width; + bufPtr = buffer; + + if(samplesLeft <= 0) + { + return 0; + } + + // cycle until we have the requested or all available bytes read + while(-1) + { + // read some samples from the opus codec + c = op_read((OggOpusFile *) stream->ptr, bufPtr + samplesRead * stream->info.channels, samplesLeft * stream->info.channels, NULL); + + // no more samples are left + if(c <= 0) + { + break; + } + + samplesRead += c; + samplesLeft -= c; + + // we have enough samples + if(samplesLeft <= 0) + { + break; + } + } + + return samplesRead * stream->info.channels * stream->info.width; +} + +/* +===================================================================== +S_OggOpus_CodecLoad + +We handle S_OggOpus_CodecLoad as a special case of the streaming functions +where we read the whole stream at once. +====================================================================== +*/ +void *S_OggOpus_CodecLoad(const char *filename, snd_info_t *info) +{ + snd_stream_t *stream; + byte *buffer; + int bytesRead; + + // check if input is valid + if(!(filename && info)) + { + return NULL; + } + + // open the file as a stream + stream = S_OggOpus_CodecOpenStream(filename); + if(!stream) + { + return NULL; + } + + // copy over the info + info->rate = stream->info.rate; + info->width = stream->info.width; + info->channels = stream->info.channels; + info->samples = stream->info.samples; + info->size = stream->info.size; + info->dataofs = stream->info.dataofs; + + // allocate a buffer + // this buffer must be free-ed by the caller of this function + buffer = Hunk_AllocateTempMemory(info->size); + if(!buffer) + { + S_OggOpus_CodecCloseStream(stream); + + return NULL; + } + + // fill the buffer + bytesRead = S_OggOpus_CodecReadStream(stream, info->size, buffer); + + // we don't even have read a single byte + if(bytesRead <= 0) + { + Hunk_FreeTempMemory(buffer); + S_OggOpus_CodecCloseStream(stream); + + return NULL; + } + + S_OggOpus_CodecCloseStream(stream); + + return buffer; +} + +#endif // USE_CODEC_OPUS diff --git a/code/client/snd_dma.c b/code/client/snd_dma.c index 487617c2..d4ba8906 100644 --- a/code/client/snd_dma.c +++ b/code/client/snd_dma.c @@ -492,7 +492,7 @@ static qboolean S_Base_HearingThroughEntity( int entityNum, vec3_t origin ) if( listener_number == entityNum ) { - // FIXME: 28/02/06 This is an outrageous hack to detect + // This is an outrageous hack to detect // whether or not the player is rendering in third person or not. We can't // ask the renderer because the renderer has no notion of entities and we // can't ask cgame since that would involve changing the API and hence mod @@ -1452,7 +1452,6 @@ void S_UpdateBackgroundTrack( void ) { r = S_CodecReadStream(s_backgroundStream, fileBytes, raw); if(r < fileBytes) { - fileBytes = r; fileSamples = r / (s_backgroundStream->info.width * s_backgroundStream->info.channels); } diff --git a/code/client/snd_mix.c b/code/client/snd_mix.c index 11de66da..fca5e15f 100644 --- a/code/client/snd_mix.c +++ b/code/client/snd_mix.c @@ -164,7 +164,6 @@ void S_TransferPaintBuffer(int endtime) if ( s_testsound->integer ) { int i; - int count; // write a fixed sine wave count = (endtime - s_paintedtime); @@ -598,7 +597,7 @@ void S_PaintChannelFromMuLaw( channel_t *ch, sfx_t *sc, int count, int sampleOff samp[i].left += (data * leftvol)>>8; samp[i].right += (data * rightvol)>>8; samples++; - if (samples == (byte *)chunk->sndChunk+(SND_CHUNK_SIZE*2)) { + if (chunk != NULL && samples == (byte *)chunk->sndChunk+(SND_CHUNK_SIZE*2)) { chunk = chunk->next; samples = (byte *)chunk->sndChunk; } diff --git a/code/client/snd_openal.c b/code/client/snd_openal.c index 101da612..c4308f0f 100644 --- a/code/client/snd_openal.c +++ b/code/client/snd_openal.c @@ -768,7 +768,7 @@ static qboolean S_AL_HearingThroughEntity( int entityNum ) if( lastListenerNumber == entityNum ) { - // FIXME: 28/02/06 This is an outrageous hack to detect + // This is an outrageous hack to detect // whether or not the player is rendering in third person or not. We can't // ask the renderer because the renderer has no notion of entities and we // can't ask cgame since that would involve changing the API and hence mod @@ -2266,6 +2266,8 @@ static cvar_t *s_alCapture; #define ALDRIVER_DEFAULT "OpenAL32.dll" #elif defined(MACOS_X) #define ALDRIVER_DEFAULT "/System/Library/Frameworks/OpenAL.framework/OpenAL" +#elif defined(__OpenBSD__) +#define ALDRIVER_DEFAULT "libopenal.so" #else #define ALDRIVER_DEFAULT "libopenal.so.1" #endif @@ -3234,8 +3236,6 @@ qboolean S_AL_Init( soundInterface_t *si ) devicelist += curlen + 1; } } - else - devicelist = ""; s_alAvailableDevices = Cvar_Get("s_alAvailableDevices", devicenames, CVAR_ROM | CVAR_NORESTART); } diff --git a/code/client/snd_wavelet.c b/code/client/snd_wavelet.c index 9940b4f9..a325ffdc 100644 --- a/code/client/snd_wavelet.c +++ b/code/client/snd_wavelet.c @@ -29,7 +29,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA void daub4(float b[], unsigned long n, int isign) { - float wksp[4097]; + float wksp[4097] = { 0.0f }; float *a=b-1; // numerical recipies so a[1] = b[0] unsigned long nh,nh1,i,j; @@ -146,7 +146,7 @@ void encodeWavelet( sfx_t *sfx, short *packets) { newchunk = SND_malloc(); if (sfx->soundData == NULL) { sfx->soundData = newchunk; - } else { + } else if (chunk != NULL) { chunk->next = newchunk; } chunk = newchunk; @@ -215,7 +215,7 @@ void encodeMuLaw( sfx_t *sfx, short *packets) { newchunk = SND_malloc(); if (sfx->soundData == NULL) { sfx->soundData = newchunk; - } else { + } else if (chunk != NULL) { chunk->next = newchunk; } chunk = newchunk; diff --git a/code/game/be_aas.h b/code/game/be_aas.h deleted file mode 100644 index f29d7a3a..00000000 --- a/code/game/be_aas.h +++ /dev/null @@ -1,216 +0,0 @@ -//----------------------------------------------------------------------------- -// -// $Id$ -// -//----------------------------------------------------------------------------- -// -// $Log$ -// Revision 1.6 2002/06/16 20:06:13 jbravo -// Reindented all the source files with "indent -kr -ut -i8 -l120 -lc120 -sob -bad -bap" -// -// Revision 1.5 2002/01/11 19:48:29 jbravo -// Formatted the source in non DOS format. -// -// Revision 1.4 2001/12/31 16:28:42 jbravo -// I made a Booboo with the Log tag. -// -// -//----------------------------------------------------------------------------- -// Copyright (C) 1999-2000 Id Software, Inc. -// - -/***************************************************************************** - * name: be_aas.h - * - * desc: Area Awareness System, stuff exported to the AI - * - * $Archive: /source/code/botlib/be_aas.h $ - * $Author$ - * $Revision$ - * $Modtime: 10/05/99 3:32p $ - * $Date$ - * - *****************************************************************************/ - -#ifndef MAX_STRINGFIELD -#define MAX_STRINGFIELD 80 -#endif - -//travel flags -#define TFL_INVALID 0x00000001 //traveling temporary not possible -#define TFL_WALK 0x00000002 //walking -#define TFL_CROUCH 0x00000004 //crouching -#define TFL_BARRIERJUMP 0x00000008 //jumping onto a barrier -#define TFL_JUMP 0x00000010 //jumping -#define TFL_LADDER 0x00000020 //climbing a ladder -#define TFL_WALKOFFLEDGE 0x00000080 //walking of a ledge -#define TFL_SWIM 0x00000100 //swimming -#define TFL_WATERJUMP 0x00000200 //jumping out of the water -#define TFL_TELEPORT 0x00000400 //teleporting -#define TFL_ELEVATOR 0x00000800 //elevator -#define TFL_ROCKETJUMP 0x00001000 //rocket jumping -#define TFL_BFGJUMP 0x00002000 //bfg jumping -#define TFL_GRAPPLEHOOK 0x00004000 //grappling hook -#define TFL_DOUBLEJUMP 0x00008000 //double jump -#define TFL_RAMPJUMP 0x00010000 //ramp jump -#define TFL_STRAFEJUMP 0x00020000 //strafe jump -#define TFL_JUMPPAD 0x00040000 //jump pad -#define TFL_AIR 0x00080000 //travel through air -#define TFL_WATER 0x00100000 //travel through water -#define TFL_SLIME 0x00200000 //travel through slime -#define TFL_LAVA 0x00400000 //travel through lava -#define TFL_DONOTENTER 0x00800000 //travel through donotenter area -#define TFL_FUNCBOB 0x01000000 //func bobbing -#define TFL_FLIGHT 0x02000000 //flight -#define TFL_BRIDGE 0x04000000 //move over a bridge -// -#define TFL_NOTTEAM1 0x08000000 //not team 1 -#define TFL_NOTTEAM2 0x10000000 //not team 2 - -//default travel flags -#define TFL_DEFAULT TFL_WALK|TFL_CROUCH|TFL_BARRIERJUMP|\ - TFL_JUMP|TFL_LADDER|\ - TFL_WALKOFFLEDGE|TFL_SWIM|TFL_WATERJUMP|\ - TFL_TELEPORT|TFL_ELEVATOR|\ - TFL_AIR|TFL_WATER|TFL_JUMPPAD|TFL_FUNCBOB - -typedef enum { - SOLID_NOT, // no interaction with other objects - SOLID_TRIGGER, // only touch when inside, after moving - SOLID_BBOX, // touch on edge - SOLID_BSP // bsp clip, touch on edge -} solid_t; - -//a trace is returned when a box is swept through the AAS world -typedef struct aas_trace_s { - qboolean startsolid; // if true, the initial point was in a solid area - float fraction; // time completed, 1.0 = didn't hit anything - vec3_t endpos; // final position - int ent; // entity blocking the trace - int lastarea; // last area the trace was in (zero if none) - int area; // area blocking the trace (zero if none) - int planenum; // number of the plane that was hit -} aas_trace_t; - -/* Defined in botlib.h - -//bsp_trace_t hit surface -typedef struct bsp_surface_s -{ - char name[16]; - int flags; - int value; -} bsp_surface_t; - -//a trace is returned when a box is swept through the BSP world -typedef struct bsp_trace_s -{ - qboolean allsolid; // if true, plane is not valid - qboolean startsolid; // if true, the initial point was in a solid area - float fraction; // time completed, 1.0 = didn't hit anything - vec3_t endpos; // final position - cplane_t plane; // surface normal at impact - float exp_dist; // expanded plane distance - int sidenum; // number of the brush side hit - bsp_surface_t surface; // hit surface - int contents; // contents on other side of surface hit - int ent; // number of entity hit -} bsp_trace_t; -// -*/ - -//entity info -typedef struct aas_entityinfo_s { - int valid; // true if updated this frame - int type; // entity type - int flags; // entity flags - float ltime; // local time - float update_time; // time between last and current update - int number; // number of the entity - vec3_t origin; // origin of the entity - vec3_t angles; // angles of the model - vec3_t old_origin; // for lerping - vec3_t lastvisorigin; // last visible origin - vec3_t mins; // bounding box minimums - vec3_t maxs; // bounding box maximums - int groundent; // ground entity - int solid; // solid type - int modelindex; // model used - int modelindex2; // weapons, CTF flags, etc - int frame; // model frame number - int event; // impulse events -- muzzle flashes, footsteps, etc - int eventParm; // even parameter - int powerups; // bit flags - int weapon; // determines weapon and flash model, etc - int legsAnim; // mask off ANIM_TOGGLEBIT - int torsoAnim; // mask off ANIM_TOGGLEBIT -} aas_entityinfo_t; - -// area info -typedef struct aas_areainfo_s { - int contents; - int flags; - int presencetype; - int cluster; - vec3_t mins; - vec3_t maxs; - vec3_t center; -} aas_areainfo_t; - -//client movement prediction stop events, stop as soon as: -#define SE_NONE 0 -#define SE_HITGROUND 1 // the ground is hit -#define SE_LEAVEGROUND 2 // there's no ground -#define SE_ENTERWATER 4 // water is entered -#define SE_ENTERSLIME 8 // slime is entered -#define SE_ENTERLAVA 16 // lava is entered -#define SE_HITGROUNDDAMAGE 32 // the ground is hit with damage -#define SE_GAP 64 // there's a gap -#define SE_TOUCHJUMPPAD 128 // touching a jump pad area -#define SE_TOUCHTELEPORTER 256 // touching teleporter -#define SE_ENTERAREA 512 // the given stoparea is entered -#define SE_HITGROUNDAREA 1024 // a ground face in the area is hit -#define SE_HITBOUNDINGBOX 2048 // hit the specified bounding box -#define SE_TOUCHCLUSTERPORTAL 4096 // touching a cluster portal - -typedef struct aas_clientmove_s { - vec3_t endpos; //position at the end of movement prediction - int endarea; //area at end of movement prediction - vec3_t velocity; //velocity at the end of movement prediction - aas_trace_t trace; //last trace - int presencetype; //presence type at end of movement prediction - int stopevent; //event that made the prediction stop - int endcontents; //contents at the end of movement prediction - float time; //time predicted ahead - int frames; //number of frames predicted ahead -} aas_clientmove_t; - -// alternate route goals -#define ALTROUTEGOAL_ALL 1 -#define ALTROUTEGOAL_CLUSTERPORTALS 2 -#define ALTROUTEGOAL_VIEWPORTALS 4 - -typedef struct aas_altroutegoal_s { - vec3_t origin; - int areanum; - unsigned short starttraveltime; - unsigned short goaltraveltime; - unsigned short extratraveltime; -} aas_altroutegoal_t; - -// route prediction stop events -#define RSE_NONE 0 -#define RSE_NOROUTE 1 //no route to goal -#define RSE_USETRAVELTYPE 2 //stop as soon as on of the given travel types is used -#define RSE_ENTERCONTENTS 4 //stop when entering the given contents -#define RSE_ENTERAREA 8 //stop when entering the given area - -typedef struct aas_predictroute_s { - vec3_t endpos; //position at the end of movement prediction - int endarea; //area at end of movement prediction - int stopevent; //event that made the prediction stop - int endcontents; //contents at the end of movement prediction - int endtravelflags; //end travel flags - int numareas; //number of areas predicted ahead - int time; //time predicted ahead (in hundreth of a sec) -} aas_predictroute_t; diff --git a/code/game/be_ai_char.h b/code/game/be_ai_char.h deleted file mode 100644 index 7c69587b..00000000 --- a/code/game/be_ai_char.h +++ /dev/null @@ -1,57 +0,0 @@ -//----------------------------------------------------------------------------- -// -// $Id$ -// -//----------------------------------------------------------------------------- -// -// $Log$ -// Revision 1.5 2002/06/16 20:06:13 jbravo -// Reindented all the source files with "indent -kr -ut -i8 -l120 -lc120 -sob -bad -bap" -// -// Revision 1.4 2002/01/11 19:48:29 jbravo -// Formatted the source in non DOS format. -// -// Revision 1.3 2001/12/31 16:28:42 jbravo -// I made a Booboo with the Log tag. -// -// -//----------------------------------------------------------------------------- -// Copyright (C) 1999-2000 Id Software, Inc. -// - -/***************************************************************************** - * name: be_ai_char.h - * - * desc: bot characters - * - * $Archive: /source/code/botlib/be_ai_char.h $ - * $Author$ - * $Revision$ - * $Modtime: 10/05/99 3:32p $ - * $Date$ - * - *****************************************************************************/ - -//loads a bot character from a file -int BotLoadCharacter(char *charfile, float skill); - -//frees a bot character -void BotFreeCharacter(int character); - -//returns a float characteristic -float Characteristic_Float(int character, int index); - -//returns a bounded float characteristic -float Characteristic_BFloat(int character, int index, float min, float max); - -//returns an integer characteristic -int Characteristic_Integer(int character, int index); - -//returns a bounded integer characteristic -int Characteristic_BInteger(int character, int index, int min, int max); - -//returns a string characteristic -void Characteristic_String(int character, int index, char *buf, int size); - -//free cached bot characters -void BotShutdownCharacters(void); diff --git a/code/game/be_ai_chat.h b/code/game/be_ai_chat.h deleted file mode 100644 index ea25e2e5..00000000 --- a/code/game/be_ai_chat.h +++ /dev/null @@ -1,133 +0,0 @@ -//----------------------------------------------------------------------------- -// -// $Id$ -// -//----------------------------------------------------------------------------- -// -// $Log$ -// Revision 1.5 2002/06/16 20:06:13 jbravo -// Reindented all the source files with "indent -kr -ut -i8 -l120 -lc120 -sob -bad -bap" -// -// Revision 1.4 2002/01/11 19:48:29 jbravo -// Formatted the source in non DOS format. -// -// Revision 1.3 2001/12/31 16:28:42 jbravo -// I made a Booboo with the Log tag. -// -// -//----------------------------------------------------------------------------- -// Copyright (C) 1999-2000 Id Software, Inc. -// -/***************************************************************************** - * name: be_ai_chat.h - * - * desc: char AI - * - * $Archive: /source/code/botlib/be_ai_chat.h $ - * $Author$ - * $Revision$ - * $Modtime: 10/05/99 3:32p $ - * $Date$ - * - *****************************************************************************/ - -#define MAX_MESSAGE_SIZE 256 -#define MAX_CHATTYPE_NAME 32 -#define MAX_MATCHVARIABLES 8 - -#define CHAT_GENDERLESS 0 -#define CHAT_GENDERFEMALE 1 -#define CHAT_GENDERMALE 2 - -#define CHAT_ALL 0 -#define CHAT_TEAM 1 -#define CHAT_TELL 2 - -//a console message -typedef struct bot_consolemessage_s { - int handle; - float time; //message time - int type; //message type - char message[MAX_MESSAGE_SIZE]; //message - struct bot_consolemessage_s *prev, *next; //prev and next in list -} bot_consolemessage_t; - -//match variable -typedef struct bot_matchvariable_s { - char offset; - int length; -} bot_matchvariable_t; - -//returned to AI when a match is found -typedef struct bot_match_s { - char string[MAX_MESSAGE_SIZE]; - int type; - int subtype; - bot_matchvariable_t variables[MAX_MATCHVARIABLES]; -} bot_match_t; - -//setup the chat AI -int BotSetupChatAI(void); - -//shutdown the chat AI -void BotShutdownChatAI(void); - -//returns the handle to a newly allocated chat state -int BotAllocChatState(void); - -//frees the chatstate -void BotFreeChatState(int handle); - -//adds a console message to the chat state -void BotQueueConsoleMessage(int chatstate, int type, char *message); - -//removes the console message from the chat state -void BotRemoveConsoleMessage(int chatstate, int handle); - -//returns the next console message from the state -int BotNextConsoleMessage(int chatstate, bot_consolemessage_t * cm); - -//returns the number of console messages currently stored in the state -int BotNumConsoleMessages(int chatstate); - -//selects a chat message of the given type -void BotInitialChat(int chatstate, char *type, int mcontext, char *var0, char *var1, char *var2, char *var3, char *var4, - char *var5, char *var6, char *var7); -//returns the number of initial chat messages of the given type -int BotNumInitialChats(int chatstate, char *type); - -//find and select a reply for the given message -int BotReplyChat(int chatstate, char *message, int mcontext, int vcontext, char *var0, char *var1, char *var2, - char *var3, char *var4, char *var5, char *var6, char *var7); -//returns the length of the currently selected chat message -int BotChatLength(int chatstate); - -//enters the selected chat message -void BotEnterChat(int chatstate, int clientto, int sendto); - -//get the chat message ready to be output -void BotGetChatMessage(int chatstate, char *buf, int size); - -//checks if the first string contains the second one, returns index into first string or -1 if not found -int StringContains(char *str1, char *str2, int casesensitive); - -//finds a match for the given string using the match templates -int BotFindMatch(char *str, bot_match_t * match, unsigned long int context); - -//returns a variable from a match -void BotMatchVariable(bot_match_t * match, int variable, char *buf, int size); - -//unify all the white spaces in the string -void UnifyWhiteSpaces(char *string); - -//replace all the context related synonyms in the string -void BotReplaceSynonyms(char *string, unsigned long int context); - -//loads a chat file for the chat state -int BotLoadChatFile(int chatstate, char *chatfile, char *chatname); - -//store the gender of the bot in the chat state -void BotSetChatGender(int chatstate, int gender); - -//store the bot name in the chat state -void BotSetChatName(int chatstate, char *name, int client); diff --git a/code/game/be_ai_gen.h b/code/game/be_ai_gen.h deleted file mode 100644 index e2c79b20..00000000 --- a/code/game/be_ai_gen.h +++ /dev/null @@ -1,32 +0,0 @@ -//----------------------------------------------------------------------------- -// -// $Id$ -// -//----------------------------------------------------------------------------- -// -// $Log$ -// Revision 1.4 2002/01/11 19:48:29 jbravo -// Formatted the source in non DOS format. -// -// Revision 1.3 2001/12/31 16:28:42 jbravo -// I made a Booboo with the Log tag. -// -// -//----------------------------------------------------------------------------- -// Copyright (C) 1999-2000 Id Software, Inc. -// - -/***************************************************************************** - * name: be_ai_gen.h - * - * desc: genetic selection - * - * $Archive: /source/code/botlib/be_ai_gen.h $ - * $Author$ - * $Revision$ - * $Modtime: 10/05/99 3:32p $ - * $Date$ - * - *****************************************************************************/ - -int GeneticParentsAndChildSelection(int numranks, float *ranks, int *parent1, int *parent2, int *child); diff --git a/code/game/be_ai_goal.h b/code/game/be_ai_goal.h deleted file mode 100644 index 074f0daf..00000000 --- a/code/game/be_ai_goal.h +++ /dev/null @@ -1,148 +0,0 @@ -//----------------------------------------------------------------------------- -// -// $Id$ -// -//----------------------------------------------------------------------------- -// -// $Log$ -// Revision 1.5 2002/06/16 20:06:14 jbravo -// Reindented all the source files with "indent -kr -ut -i8 -l120 -lc120 -sob -bad -bap" -// -// Revision 1.4 2002/01/11 19:48:29 jbravo -// Formatted the source in non DOS format. -// -// Revision 1.3 2001/12/31 16:28:42 jbravo -// I made a Booboo with the Log tag. -// -// -//----------------------------------------------------------------------------- -// Copyright (C) 1999-2000 Id Software, Inc. -// -/***************************************************************************** - * name: be_ai_goal.h - * - * desc: goal AI - * - * $Archive: /source/code/botlib/be_ai_goal.h $ - * $Author$ - * $Revision$ - * $Modtime: 10/05/99 3:32p $ - * $Date$ - * - *****************************************************************************/ - -#define MAX_AVOIDGOALS 256 -#define MAX_GOALSTACK 8 - -#define GFL_NONE 0 -#define GFL_ITEM 1 -#define GFL_ROAM 2 -#define GFL_DROPPED 4 - -//a bot goal -typedef struct bot_goal_s { - vec3_t origin; //origin of the goal - int areanum; //area number of the goal - vec3_t mins, maxs; //mins and maxs of the goal - int entitynum; //number of the goal entity - int number; //goal number - int flags; //goal flags - int iteminfo; //item information -} bot_goal_t; - -//reset the whole goal state, but keep the item weights -void BotResetGoalState(int goalstate); - -//reset avoid goals -void BotResetAvoidGoals(int goalstate); - -//remove the goal with the given number from the avoid goals -void BotRemoveFromAvoidGoals(int goalstate, int number); - -//push a goal onto the goal stack -void BotPushGoal(int goalstate, bot_goal_t * goal); - -//pop a goal from the goal stack -void BotPopGoal(int goalstate); - -//empty the bot's goal stack -void BotEmptyGoalStack(int goalstate); - -//dump the avoid goals -void BotDumpAvoidGoals(int goalstate); - -//dump the goal stack -void BotDumpGoalStack(int goalstate); - -//get the name name of the goal with the given number -void BotGoalName(int number, char *name, int size); - -//get the top goal from the stack -int BotGetTopGoal(int goalstate, bot_goal_t * goal); - -//get the second goal on the stack -int BotGetSecondGoal(int goalstate, bot_goal_t * goal); - -//choose the best long term goal item for the bot -int BotChooseLTGItem(int goalstate, vec3_t origin, int *inventory, int travelflags); - -//choose the best nearby goal item for the bot -//the item may not be further away from the current bot position than maxtime -//also the travel time from the nearby goal towards the long term goal may not -//be larger than the travel time towards the long term goal from the current bot position -int BotChooseNBGItem(int goalstate, vec3_t origin, int *inventory, int travelflags, bot_goal_t * ltg, float maxtime); - -//returns true if the bot touches the goal -int BotTouchingGoal(vec3_t origin, bot_goal_t * goal); - -//returns true if the goal should be visible but isn't -int BotItemGoalInVisButNotVisible(int viewer, vec3_t eye, vec3_t viewangles, bot_goal_t * goal); - -//search for a goal for the given classname, the index can be used -//as a start point for the search when multiple goals are available with that same classname -int BotGetLevelItemGoal(int index, char *classname, bot_goal_t * goal); - -//get the next camp spot in the map -int BotGetNextCampSpotGoal(int num, bot_goal_t * goal); - -//get the map location with the given name -int BotGetMapLocationGoal(char *name, bot_goal_t * goal); - -//returns the avoid goal time -float BotAvoidGoalTime(int goalstate, int number); - -//set the avoid goal time -void BotSetAvoidGoalTime(int goalstate, int number, float avoidtime); - -//initializes the items in the level -void BotInitLevelItems(void); - -//regularly update dynamic entity items (dropped weapons, flags etc.) -void BotUpdateEntityItems(void); - -//interbreed the goal fuzzy logic -void BotInterbreedGoalFuzzyLogic(int parent1, int parent2, int child); - -//save the goal fuzzy logic to disk -void BotSaveGoalFuzzyLogic(int goalstate, char *filename); - -//mutate the goal fuzzy logic -void BotMutateGoalFuzzyLogic(int goalstate, float range); - -//loads item weights for the bot -int BotLoadItemWeights(int goalstate, char *filename); - -//frees the item weights of the bot -void BotFreeItemWeights(int goalstate); - -//returns the handle of a newly allocated goal state -int BotAllocGoalState(int client); - -//free the given goal state -void BotFreeGoalState(int handle); - -//setup the goal AI -int BotSetupGoalAI(void); - -//shut down the goal AI -void BotShutdownGoalAI(void); diff --git a/code/game/be_ai_move.h b/code/game/be_ai_move.h deleted file mode 100644 index b5cb7a4c..00000000 --- a/code/game/be_ai_move.h +++ /dev/null @@ -1,154 +0,0 @@ -//----------------------------------------------------------------------------- -// -// $Id$ -// -//----------------------------------------------------------------------------- -// -// $Log$ -// Revision 1.6 2002/06/16 20:06:14 jbravo -// Reindented all the source files with "indent -kr -ut -i8 -l120 -lc120 -sob -bad -bap" -// -// Revision 1.5 2002/01/11 19:48:29 jbravo -// Formatted the source in non DOS format. -// -// Revision 1.4 2001/12/31 16:28:42 jbravo -// I made a Booboo with the Log tag. -// -// -//----------------------------------------------------------------------------- -// Copyright (C) 1999-2000 Id Software, Inc. -// - -/***************************************************************************** - * name: be_ai_move.h - * - * desc: movement AI - * - * $Archive: /source/code/botlib/be_ai_move.h $ - * $Author$ - * $Revision$ - * $Modtime: 10/05/99 3:32p $ - * $Date$ - * - *****************************************************************************/ - -//movement types -#define MOVE_WALK 1 -#define MOVE_CROUCH 2 -#define MOVE_JUMP 4 -#define MOVE_GRAPPLE 8 -#define MOVE_ROCKETJUMP 16 -#define MOVE_BFGJUMP 32 -//move flags -#define MFL_BARRIERJUMP 1 //bot is performing a barrier jump -#define MFL_ONGROUND 2 //bot is in the ground -#define MFL_SWIMMING 4 //bot is swimming -#define MFL_AGAINSTLADDER 8 //bot is against a ladder -#define MFL_WATERJUMP 16 //bot is waterjumping -#define MFL_TELEPORTED 32 //bot is being teleported -#define MFL_GRAPPLEPULL 64 //bot is being pulled by the grapple -#define MFL_ACTIVEGRAPPLE 128 //bot is using the grapple hook -#define MFL_GRAPPLERESET 256 //bot has reset the grapple -#define MFL_WALK 512 //bot should walk slowly -//move result flags -#define MOVERESULT_MOVEMENTVIEW 1 //bot uses view for movement -#define MOVERESULT_SWIMVIEW 2 //bot uses view for swimming -#define MOVERESULT_WAITING 4 //bot is waiting for something -#define MOVERESULT_MOVEMENTVIEWSET 8 //bot has set the view in movement code -#define MOVERESULT_MOVEMENTWEAPON 16 //bot uses weapon for movement -#define MOVERESULT_ONTOPOFOBSTACLE 32 //bot is ontop of obstacle -#define MOVERESULT_ONTOPOF_FUNCBOB 64 //bot is ontop of a func_bobbing -#define MOVERESULT_ONTOPOF_ELEVATOR 128 //bot is ontop of an elevator (func_plat) -#define MOVERESULT_BLOCKEDBYAVOIDSPOT 256 //bot is blocked by an avoid spot -// -#define MAX_AVOIDREACH 1 -#define MAX_AVOIDSPOTS 32 -// avoid spot types -#define AVOID_CLEAR 0 //clear all avoid spots -#define AVOID_ALWAYS 1 //avoid always -#define AVOID_DONTBLOCK 2 //never totally block -// restult types -#define RESULTTYPE_ELEVATORUP 1 //elevator is up -#define RESULTTYPE_WAITFORFUNCBOBBING 2 //waiting for func bobbing to arrive -#define RESULTTYPE_BADGRAPPLEPATH 4 //grapple path is obstructed -#define RESULTTYPE_INSOLIDAREA 8 //stuck in solid area, this is bad - -//structure used to initialize the movement state -//the or_moveflags MFL_ONGROUND, MFL_TELEPORTED and MFL_WATERJUMP come from the playerstate -typedef struct bot_initmove_s { - vec3_t origin; //origin of the bot - vec3_t velocity; //velocity of the bot - vec3_t viewoffset; //view offset - int entitynum; //entity number of the bot - int client; //client number of the bot - float thinktime; //time the bot thinks - int presencetype; //presencetype of the bot - vec3_t viewangles; //view angles of the bot - int or_moveflags; //values ored to the movement flags -} bot_initmove_t; - -//NOTE: the ideal_viewangles are only valid if MFL_MOVEMENTVIEW is set -typedef struct bot_moveresult_s { - int failure; //true if movement failed all together - int type; //failure or blocked type - int blocked; //true if blocked by an entity - int blockentity; //entity blocking the bot - int traveltype; //last executed travel type - int flags; //result flags - int weapon; //weapon used for movement - vec3_t movedir; //movement direction - vec3_t ideal_viewangles; //ideal viewangles for the movement -} bot_moveresult_t; - -// bk001204: from code/botlib/be_ai_move.c -// TTimo 04/12/2001 was moved here to avoid dup defines -typedef struct bot_avoidspot_s { - vec3_t origin; - float radius; - int type; -} bot_avoidspot_t; - -//resets the whole movestate -void BotResetMoveState(int movestate); - -//moves the bot to the given goal -void BotMoveToGoal(bot_moveresult_t * result, int movestate, bot_goal_t * goal, int travelflags); - -//moves the bot in the specified direction using the specified type of movement -int BotMoveInDirection(int movestate, vec3_t dir, float speed, int type); - -//reset avoid reachability -void BotResetAvoidReach(int movestate); - -//resets the last avoid reachability -void BotResetLastAvoidReach(int movestate); - -//returns a reachability area if the origin is in one -int BotReachabilityArea(vec3_t origin, int client); - -//view target based on movement -int BotMovementViewTarget(int movestate, bot_goal_t * goal, int travelflags, float lookahead, vec3_t target); - -//predict the position of a player based on movement towards a goal -int BotPredictVisiblePosition(vec3_t origin, int areanum, bot_goal_t * goal, int travelflags, vec3_t target); - -//returns the handle of a newly allocated movestate -int BotAllocMoveState(void); - -//frees the movestate with the given handle -void BotFreeMoveState(int handle); - -//initialize movement state before performing any movement -void BotInitMoveState(int handle, bot_initmove_t * initmove); - -//add a spot to avoid (if type == AVOID_CLEAR all spots are removed) -void BotAddAvoidSpot(int movestate, vec3_t origin, float radius, int type); - -//must be called every map change -void BotSetBrushModelTypes(void); - -//setup movement AI -int BotSetupMoveAI(void); - -//shutdown movement AI -void BotShutdownMoveAI(void); diff --git a/code/game/be_ai_weap.h b/code/game/be_ai_weap.h deleted file mode 100644 index d7c3aad6..00000000 --- a/code/game/be_ai_weap.h +++ /dev/null @@ -1,111 +0,0 @@ -//----------------------------------------------------------------------------- -// -// $Id$ -// -//----------------------------------------------------------------------------- -// -// $Log$ -// Revision 1.5 2002/06/16 20:06:14 jbravo -// Reindented all the source files with "indent -kr -ut -i8 -l120 -lc120 -sob -bad -bap" -// -// Revision 1.4 2002/01/11 19:48:29 jbravo -// Formatted the source in non DOS format. -// -// Revision 1.3 2001/12/31 16:28:42 jbravo -// I made a Booboo with the Log tag. -// -// -//----------------------------------------------------------------------------- -// Copyright (C) 1999-2000 Id Software, Inc. -// - -/***************************************************************************** - * name: be_ai_weap.h - * - * desc: weapon AI - * - * $Archive: /source/code/botlib/be_ai_weap.h $ - * $Author$ - * $Revision$ - * $Modtime: 10/05/99 3:32p $ - * $Date$ - * - *****************************************************************************/ - -//projectile flags -#define PFL_WINDOWDAMAGE 1 //projectile damages through window -#define PFL_RETURN 2 //set when projectile returns to owner -//weapon flags -#define WFL_FIRERELEASED 1 //set when projectile is fired with key-up event -//damage types -#define DAMAGETYPE_IMPACT 1 //damage on impact -#define DAMAGETYPE_RADIAL 2 //radial damage -#define DAMAGETYPE_VISIBLE 4 //damage to all entities visible to the projectile - -typedef struct projectileinfo_s { - char name[MAX_STRINGFIELD]; - char model[MAX_STRINGFIELD]; - int flags; - float gravity; - int damage; - float radius; - int visdamage; - int damagetype; - int healthinc; - float push; - float detonation; - float bounce; - float bouncefric; - float bouncestop; -} projectileinfo_t; - -typedef struct weaponinfo_s { - int valid; //true if the weapon info is valid - int number; //number of the weapon - char name[MAX_STRINGFIELD]; - char model[MAX_STRINGFIELD]; - int level; - int weaponindex; - int flags; - char projectile[MAX_STRINGFIELD]; - int numprojectiles; - float hspread; - float vspread; - float speed; - float acceleration; - vec3_t recoil; - vec3_t offset; - vec3_t angleoffset; - float extrazvelocity; - int ammoamount; - int ammoindex; - float activate; - float reload; - float spinup; - float spindown; - projectileinfo_t proj; //pointer to the used projectile -} weaponinfo_t; - -//setup the weapon AI -int BotSetupWeaponAI(void); - -//shut down the weapon AI -void BotShutdownWeaponAI(void); - -//returns the best weapon to fight with -int BotChooseBestFightWeapon(int weaponstate, int *inventory); - -//returns the information of the current weapon -void BotGetWeaponInfo(int weaponstate, int weapon, weaponinfo_t * weaponinfo); - -//loads the weapon weights -int BotLoadWeaponWeights(int weaponstate, char *filename); - -//returns a handle to a newly allocated weapon state -int BotAllocWeaponState(void); - -//frees the weapon state -void BotFreeWeaponState(int weaponstate); - -//resets the whole weapon state -void BotResetWeaponState(int weaponstate); diff --git a/code/game/be_ea.h b/code/game/be_ea.h deleted file mode 100644 index ba891557..00000000 --- a/code/game/be_ea.h +++ /dev/null @@ -1,69 +0,0 @@ -//----------------------------------------------------------------------------- -// -// $Id$ -// -//----------------------------------------------------------------------------- -// -// $Log$ -// Revision 1.5 2002/06/16 20:06:14 jbravo -// Reindented all the source files with "indent -kr -ut -i8 -l120 -lc120 -sob -bad -bap" -// -// Revision 1.4 2002/01/11 19:48:29 jbravo -// Formatted the source in non DOS format. -// -// Revision 1.3 2001/12/31 16:28:42 jbravo -// I made a Booboo with the Log tag. -// -// -//----------------------------------------------------------------------------- -// Copyright (C) 1999-2000 Id Software, Inc. -// - -/***************************************************************************** - * name: be_ea.h - * - * desc: elementary actions - * - * $Archive: /source/code/botlib/be_ea.h $ - * $Author$ - * $Revision$ - * $Modtime: 10/05/99 3:32p $ - * $Date$ - * - *****************************************************************************/ - -//ClientCommand elementary actions -void EA_Say(int client, char *str); -void EA_SayTeam(int client, char *str); -void EA_Command(int client, char *command); - -void EA_Action(int client, int action); -void EA_Crouch(int client); -void EA_Walk(int client); -void EA_MoveUp(int client); -void EA_MoveDown(int client); -void EA_MoveForward(int client); -void EA_MoveBack(int client); -void EA_MoveLeft(int client); -void EA_MoveRight(int client); -void EA_Attack(int client); -void EA_Respawn(int client); -void EA_Talk(int client); -void EA_Gesture(int client); -void EA_Use(int client); - -//regular elementary actions -void EA_SelectWeapon(int client, int weapon); -void EA_Jump(int client); -void EA_DelayedJump(int client); -void EA_Move(int client, vec3_t dir, float speed); -void EA_View(int client, vec3_t viewangles); - -//send regular input to the server -void EA_EndRegular(int client, float thinktime); -void EA_GetInput(int client, float thinktime, bot_input_t * input); -void EA_ResetInput(int client); - -//setup and shutdown routines -int EA_Setup(void); -void EA_Shutdown(void); diff --git a/code/game/bg_misc.c b/code/game/bg_misc.c index f84a86af..ffc3be64 100644 --- a/code/game/bg_misc.c +++ b/code/game/bg_misc.c @@ -1049,7 +1049,7 @@ void BG_EvaluateTrajectory(const trajectory_t * tr, int atTime, vec3_t result) result[2] -= 0.5 * DEFAULT_GRAVITY * deltaTime * deltaTime; // FIXME: local gravity... break; default: - Com_Error(ERR_DROP, "BG_EvaluateTrajectory: unknown trType: %i", tr->trTime); + Com_Error(ERR_DROP, "BG_EvaluateTrajectory: unknown trType: %i", tr->trType); break; } } @@ -1093,7 +1093,7 @@ void BG_EvaluateTrajectoryDelta(const trajectory_t * tr, int atTime, vec3_t resu result[2] -= DEFAULT_GRAVITY * deltaTime; // FIXME: local gravity... break; default: - Com_Error(ERR_DROP, "BG_EvaluateTrajectoryDelta: unknown trType: %i", tr->trTime); + Com_Error(ERR_DROP, "BG_EvaluateTrajectoryDelta: unknown trType: %i", tr->trType); break; } } diff --git a/code/game/botai.h b/code/game/botai.h deleted file mode 100644 index bfa86d09..00000000 --- a/code/game/botai.h +++ /dev/null @@ -1,92 +0,0 @@ -//----------------------------------------------------------------------------- -// -// $Id$ -// -//----------------------------------------------------------------------------- -// -// $Log$ -// Revision 1.5 2002/06/16 20:06:14 jbravo -// Reindented all the source files with "indent -kr -ut -i8 -l120 -lc120 -sob -bad -bap" -// -// Revision 1.4 2002/01/11 19:48:30 jbravo -// Formatted the source in non DOS format. -// -// Revision 1.3 2001/12/31 16:28:42 jbravo -// I made a Booboo with the Log tag. -// -// -//----------------------------------------------------------------------------- - -/***************************************************************************** - * name: botai.h - * - * desc: bot AI - * - * $Archive: /source/code/game/botai.h $ - * $Author$ - * $Revision$ - * $Modtime: 03/01/00 3:32p $ - * $Date$ - * - *****************************************************************************/ - -//some maxs -#define MAX_NETNAME 36 -#define MAX_FILEPATH 144 - -//bot settings -typedef struct bot_settings_s { - char characterfile[MAX_FILEPATH]; - int skill; - char team[MAX_FILEPATH]; -} bot_settings_t; - -#ifndef BSPTRACE - -#define BSPTRACE - -//bsp_trace_t hit surface -typedef struct bsp_surface_s { - char name[16]; - int flags; - int value; -} bsp_surface_t; - -//remove the bsp_trace_s structure definition l8r on -//a trace is returned when a box is swept through the world -typedef struct bsp_trace_s { - qboolean allsolid; // if true, plane is not valid - qboolean startsolid; // if true, the initial point was in a solid area - float fraction; // time completed, 1.0 = didn't hit anything - vec3_t endpos; // final position - cplane_t plane; // surface normal at impact - float exp_dist; // expanded plane distance - int sidenum; // number of the brush side hit - bsp_surface_t surface; // the hit point surface - int contents; // contents on other side of surface hit - int ent; // number of entity hit -} bsp_trace_t; - -#endif // BSPTRACE - -// ai_main.c -int BotAISetupClient(int client, bot_settings_t * settings); - -// -// imported functions used for the BotAI -// - -// from the server -/* -void trap_Cvar_Register( vmCvar_t *cvar, const char *var_name, const char *value, int flags ); -void trap_Cvar_Update( vmCvar_t *cvar ); -void trap_Cvar_Set( const char *var_name, const char *value ); -int trap_Cvar_VariableIntegerValue( const char *var_name ); -void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize ); -void trap_GetConfigstring( int num, char *buffer, int bufferSize ); -void trap_GetServerinfo( char *buffer, int bufferSize ); -int trap_PointContents( const vec3_t point, int passEntityNum ); -qboolean trap_InPVS( const vec3_t p1, const vec3_t p2 ); -int trap_BotAllocateClient( void ); -void trap_BotFreeClient( int clientNum ); -*/ diff --git a/code/game/botlib.h b/code/game/botlib.h deleted file mode 100644 index d929477c..00000000 --- a/code/game/botlib.h +++ /dev/null @@ -1,514 +0,0 @@ -//----------------------------------------------------------------------------- -// -// $Id$ -// -//----------------------------------------------------------------------------- -// -// $Log$ -// Revision 1.5 2002/06/16 20:06:14 jbravo -// Reindented all the source files with "indent -kr -ut -i8 -l120 -lc120 -sob -bad -bap" -// -// Revision 1.4 2002/01/11 19:48:30 jbravo -// Formatted the source in non DOS format. -// -// Revision 1.3 2001/12/31 16:28:42 jbravo -// I made a Booboo with the Log tag. -// -// -//----------------------------------------------------------------------------- -// Copyright (C) 1999-2000 Id Software, Inc. -// -/***************************************************************************** - * name: botlib.h - * - * desc: bot AI library - * - * $Archive: /source/code/game/botai.h $ - * $Author$ - * $Revision$ - * $Modtime: 03/01/00 3:32p $ - * $Date$ - * - *****************************************************************************/ - -#define BOTLIB_API_VERSION 2 - -struct aas_clientmove_s; -struct aas_entityinfo_s; -struct aas_areainfo_s; -struct aas_altroutegoal_s; -struct aas_predictroute_s; -struct bot_consolemessage_s; -struct bot_match_s; -struct bot_goal_s; -struct bot_moveresult_s; -struct bot_initmove_s; -struct weaponinfo_s; - -#define BOTFILESBASEFOLDER "botfiles" -//debug line colors -#define LINECOLOR_NONE -1 -#define LINECOLOR_RED 1 //0xf2f2f0f0L -#define LINECOLOR_GREEN 2 //0xd0d1d2d3L -#define LINECOLOR_BLUE 3 //0xf3f3f1f1L -#define LINECOLOR_YELLOW 4 //0xdcdddedfL -#define LINECOLOR_ORANGE 5 //0xe0e1e2e3L - -//Print types -#define PRT_MESSAGE 1 -#define PRT_WARNING 2 -#define PRT_ERROR 3 -#define PRT_FATAL 4 -#define PRT_EXIT 5 - -//console message types -#define CMS_NORMAL 0 -#define CMS_CHAT 1 - -//botlib error codes -#define BLERR_NOERROR 0 //no error -#define BLERR_LIBRARYNOTSETUP 1 //library not setup -#define BLERR_INVALIDENTITYNUMBER 2 //invalid entity number -#define BLERR_NOAASFILE 3 //no AAS file available -#define BLERR_CANNOTOPENAASFILE 4 //cannot open AAS file -#define BLERR_WRONGAASFILEID 5 //incorrect AAS file id -#define BLERR_WRONGAASFILEVERSION 6 //incorrect AAS file version -#define BLERR_CANNOTREADAASLUMP 7 //cannot read AAS file lump -#define BLERR_CANNOTLOADICHAT 8 //cannot load initial chats -#define BLERR_CANNOTLOADITEMWEIGHTS 9 //cannot load item weights -#define BLERR_CANNOTLOADITEMCONFIG 10 //cannot load item config -#define BLERR_CANNOTLOADWEAPONWEIGHTS 11 //cannot load weapon weights -#define BLERR_CANNOTLOADWEAPONCONFIG 12 //cannot load weapon config - -//action flags -#define ACTION_ATTACK 0x0000001 -#define ACTION_USE 0x0000002 -#define ACTION_RESPAWN 0x0000008 -#define ACTION_JUMP 0x0000010 -#define ACTION_MOVEUP 0x0000020 -#define ACTION_CROUCH 0x0000080 -#define ACTION_MOVEDOWN 0x0000100 -#define ACTION_MOVEFORWARD 0x0000200 -#define ACTION_MOVEBACK 0x0000800 -#define ACTION_MOVELEFT 0x0001000 -#define ACTION_MOVERIGHT 0x0002000 -#define ACTION_DELAYEDJUMP 0x0008000 -#define ACTION_TALK 0x0010000 -#define ACTION_GESTURE 0x0020000 -#define ACTION_WALK 0x0080000 -#define ACTION_AFFIRMATIVE 0x0100000 -#define ACTION_NEGATIVE 0x0200000 -#define ACTION_GETFLAG 0x0800000 -#define ACTION_GUARDBASE 0x1000000 -#define ACTION_PATROL 0x2000000 -#define ACTION_FOLLOWME 0x8000000 - -//the bot input, will be converted to an usercmd_t -typedef struct bot_input_s { - float thinktime; //time since last output (in seconds) - vec3_t dir; //movement direction - float speed; //speed in the range [0, 400] - vec3_t viewangles; //the view angles - int actionflags; //one of the ACTION_? flags - int weapon; //weapon to use -} bot_input_t; - -#ifndef BSPTRACE - -#define BSPTRACE - -//bsp_trace_t hit surface -typedef struct bsp_surface_s { - char name[16]; - int flags; - int value; -} bsp_surface_t; - -//remove the bsp_trace_s structure definition l8r on -//a trace is returned when a box is swept through the world -typedef struct bsp_trace_s { - qboolean allsolid; // if true, plane is not valid - qboolean startsolid; // if true, the initial point was in a solid area - float fraction; // time completed, 1.0 = didn't hit anything - vec3_t endpos; // final position - cplane_t plane; // surface normal at impact - float exp_dist; // expanded plane distance - int sidenum; // number of the brush side hit - bsp_surface_t surface; // the hit point surface - int contents; // contents on other side of surface hit - int ent; // number of entity hit -} bsp_trace_t; - -#endif // BSPTRACE - -//entity state -typedef struct bot_entitystate_s { - int type; // entity type - int flags; // entity flags - vec3_t origin; // origin of the entity - vec3_t angles; // angles of the model - vec3_t old_origin; // for lerping - vec3_t mins; // bounding box minimums - vec3_t maxs; // bounding box maximums - int groundent; // ground entity - int solid; // solid type - int modelindex; // model used - int modelindex2; // weapons, CTF flags, etc - int frame; // model frame number - int event; // impulse events -- muzzle flashes, footsteps, etc - int eventParm; // even parameter - int powerups; // bit flags - int weapon; // determines weapon and flash model, etc - int legsAnim; // mask off ANIM_TOGGLEBIT - int torsoAnim; // mask off ANIM_TOGGLEBIT -} bot_entitystate_t; - -//bot AI library exported functions -typedef struct botlib_import_s { - //print messages from the bot library - void (QDECL * Print) (int type, char *fmt, ...); - //trace a bbox through the world - void (*Trace) (bsp_trace_t * trace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int passent, - int contentmask); - //trace a bbox against a specific entity - void (*EntityTrace) (bsp_trace_t * trace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int entnum, - int contentmask); - //retrieve the contents at the given point - int (*PointContents) (vec3_t point); - //check if the point is in potential visible sight - int (*inPVS) (vec3_t p1, vec3_t p2); - //retrieve the BSP entity data lump - char *(*BSPEntityData) (void); - // - void (*BSPModelMinsMaxsOrigin) (int modelnum, vec3_t angles, vec3_t mins, vec3_t maxs, vec3_t origin); - //send a bot client command - void (*BotClientCommand) (int client, char *command); - //memory allocation - void *(*GetMemory) (int size); // allocate from Zone - void (*FreeMemory) (void *ptr); // free memory from Zone - int (*AvailableMemory) (void); // available Zone memory - void *(*HunkAlloc) (int size); // allocate from hunk - //file system access - int (*FS_FOpenFile) (const char *qpath, fileHandle_t * file, fsMode_t mode); - int (*FS_Read) (void *buffer, int len, fileHandle_t f); - int (*FS_Write) (const void *buffer, int len, fileHandle_t f); - void (*FS_FCloseFile) (fileHandle_t f); - int (*FS_Seek) (fileHandle_t f, long offset, int origin); - //debug visualisation stuff - int (*DebugLineCreate) (void); - void (*DebugLineDelete) (int line); - void (*DebugLineShow) (int line, vec3_t start, vec3_t end, int color); - // - int (*DebugPolygonCreate) (int color, int numPoints, vec3_t * points); - void (*DebugPolygonDelete) (int id); -} botlib_import_t; - -typedef struct aas_export_s { - //----------------------------------- - // be_aas_entity.h - //----------------------------------- - void (*AAS_EntityInfo) (int entnum, struct aas_entityinfo_s * info); - //----------------------------------- - // be_aas_main.h - //----------------------------------- - int (*AAS_Initialized) (void); - void (*AAS_PresenceTypeBoundingBox) (int presencetype, vec3_t mins, vec3_t maxs); - float (*AAS_Time) (void); - //-------------------------------------------- - // be_aas_sample.c - //-------------------------------------------- - int (*AAS_PointAreaNum) (vec3_t point); - int (*AAS_PointReachabilityAreaIndex) (vec3_t point); - int (*AAS_TraceAreas) (vec3_t start, vec3_t end, int *areas, vec3_t * points, int maxareas); - int (*AAS_BBoxAreas) (vec3_t absmins, vec3_t absmaxs, int *areas, int maxareas); - int (*AAS_AreaInfo) (int areanum, struct aas_areainfo_s * info); - //-------------------------------------------- - // be_aas_bspq3.c - //-------------------------------------------- - int (*AAS_PointContents) (vec3_t point); - int (*AAS_NextBSPEntity) (int ent); - int (*AAS_ValueForBSPEpairKey) (int ent, char *key, char *value, int size); - int (*AAS_VectorForBSPEpairKey) (int ent, char *key, vec3_t v); - int (*AAS_FloatForBSPEpairKey) (int ent, char *key, float *value); - int (*AAS_IntForBSPEpairKey) (int ent, char *key, int *value); - //-------------------------------------------- - // be_aas_reach.c - //-------------------------------------------- - int (*AAS_AreaReachability) (int areanum); - //-------------------------------------------- - // be_aas_route.c - //-------------------------------------------- - int (*AAS_AreaTravelTimeToGoalArea) (int areanum, vec3_t origin, int goalareanum, int travelflags); - int (*AAS_EnableRoutingArea) (int areanum, int enable); - int (*AAS_PredictRoute) (struct aas_predictroute_s * route, int areanum, vec3_t origin, - int goalareanum, int travelflags, int maxareas, int maxtime, - int stopevent, int stopcontents, int stoptfl, int stopareanum); - //-------------------------------------------- - // be_aas_altroute.c - //-------------------------------------------- - int (*AAS_AlternativeRouteGoals) (vec3_t start, int startareanum, vec3_t goal, int goalareanum, int travelflags, - struct aas_altroutegoal_s * altroutegoals, int maxaltroutegoals, int type); - //-------------------------------------------- - // be_aas_move.c - //-------------------------------------------- - int (*AAS_Swimming) (vec3_t origin); - int (*AAS_PredictClientMovement) (struct aas_clientmove_s * move, - int entnum, vec3_t origin, - int presencetype, int onground, - vec3_t velocity, vec3_t cmdmove, - int cmdframes, - int maxframes, float frametime, - int stopevent, int stopareanum, int visualize); -} aas_export_t; - -typedef struct ea_export_s { - //ClientCommand elementary actions - void (*EA_Command) (int client, char *command); - void (*EA_Say) (int client, char *str); - void (*EA_SayTeam) (int client, char *str); - // - void (*EA_Action) (int client, int action); - void (*EA_Gesture) (int client); - void (*EA_Talk) (int client); - void (*EA_Attack) (int client); - void (*EA_Use) (int client); - void (*EA_Respawn) (int client); - void (*EA_MoveUp) (int client); - void (*EA_MoveDown) (int client); - void (*EA_MoveForward) (int client); - void (*EA_MoveBack) (int client); - void (*EA_MoveLeft) (int client); - void (*EA_MoveRight) (int client); - void (*EA_Crouch) (int client); - - void (*EA_SelectWeapon) (int client, int weapon); - void (*EA_Jump) (int client); - void (*EA_DelayedJump) (int client); - void (*EA_Move) (int client, vec3_t dir, float speed); - void (*EA_View) (int client, vec3_t viewangles); - //send regular input to the server - void (*EA_EndRegular) (int client, float thinktime); - void (*EA_GetInput) (int client, float thinktime, bot_input_t * input); - void (*EA_ResetInput) (int client); -} ea_export_t; - -typedef struct ai_export_s { - //----------------------------------- - // be_ai_char.h - //----------------------------------- - int (*BotLoadCharacter) (char *charfile, float skill); - void (*BotFreeCharacter) (int character); - float (*Characteristic_Float) (int character, int index); - float (*Characteristic_BFloat) (int character, int index, float min, float max); - int (*Characteristic_Integer) (int character, int index); - int (*Characteristic_BInteger) (int character, int index, int min, int max); - void (*Characteristic_String) (int character, int index, char *buf, int size); - //----------------------------------- - // be_ai_chat.h - //----------------------------------- - int (*BotAllocChatState) (void); - void (*BotFreeChatState) (int handle); - void (*BotQueueConsoleMessage) (int chatstate, int type, char *message); - void (*BotRemoveConsoleMessage) (int chatstate, int handle); - int (*BotNextConsoleMessage) (int chatstate, struct bot_consolemessage_s * cm); - int (*BotNumConsoleMessages) (int chatstate); - void (*BotInitialChat) (int chatstate, char *type, int mcontext, char *var0, char *var1, char *var2, char *var3, - char *var4, char *var5, char *var6, char *var7); - int (*BotNumInitialChats) (int chatstate, char *type); - int (*BotReplyChat) (int chatstate, char *message, int mcontext, int vcontext, char *var0, char *var1, - char *var2, char *var3, char *var4, char *var5, char *var6, char *var7); - int (*BotChatLength) (int chatstate); - void (*BotEnterChat) (int chatstate, int client, int sendto); - void (*BotGetChatMessage) (int chatstate, char *buf, int size); - int (*StringContains) (char *str1, char *str2, int casesensitive); - int (*BotFindMatch) (char *str, struct bot_match_s * match, unsigned long int context); - void (*BotMatchVariable) (struct bot_match_s * match, int variable, char *buf, int size); - void (*UnifyWhiteSpaces) (char *string); - void (*BotReplaceSynonyms) (char *string, unsigned long int context); - int (*BotLoadChatFile) (int chatstate, char *chatfile, char *chatname); - void (*BotSetChatGender) (int chatstate, int gender); - void (*BotSetChatName) (int chatstate, char *name, int client); - //----------------------------------- - // be_ai_goal.h - //----------------------------------- - void (*BotResetGoalState) (int goalstate); - void (*BotResetAvoidGoals) (int goalstate); - void (*BotRemoveFromAvoidGoals) (int goalstate, int number); - void (*BotPushGoal) (int goalstate, struct bot_goal_s * goal); - void (*BotPopGoal) (int goalstate); - void (*BotEmptyGoalStack) (int goalstate); - void (*BotDumpAvoidGoals) (int goalstate); - void (*BotDumpGoalStack) (int goalstate); - void (*BotGoalName) (int number, char *name, int size); - int (*BotGetTopGoal) (int goalstate, struct bot_goal_s * goal); - int (*BotGetSecondGoal) (int goalstate, struct bot_goal_s * goal); - int (*BotChooseLTGItem) (int goalstate, vec3_t origin, int *inventory, int travelflags); - int (*BotChooseNBGItem) (int goalstate, vec3_t origin, int *inventory, int travelflags, - struct bot_goal_s * ltg, float maxtime); - int (*BotTouchingGoal) (vec3_t origin, struct bot_goal_s * goal); - int (*BotItemGoalInVisButNotVisible) (int viewer, vec3_t eye, vec3_t viewangles, struct bot_goal_s * goal); - int (*BotGetLevelItemGoal) (int index, char *classname, struct bot_goal_s * goal); - int (*BotGetNextCampSpotGoal) (int num, struct bot_goal_s * goal); - int (*BotGetMapLocationGoal) (char *name, struct bot_goal_s * goal); - float (*BotAvoidGoalTime) (int goalstate, int number); - void (*BotSetAvoidGoalTime) (int goalstate, int number, float avoidtime); - void (*BotInitLevelItems) (void); - void (*BotUpdateEntityItems) (void); - int (*BotLoadItemWeights) (int goalstate, char *filename); - void (*BotFreeItemWeights) (int goalstate); - void (*BotInterbreedGoalFuzzyLogic) (int parent1, int parent2, int child); - void (*BotSaveGoalFuzzyLogic) (int goalstate, char *filename); - void (*BotMutateGoalFuzzyLogic) (int goalstate, float range); - int (*BotAllocGoalState) (int client); - void (*BotFreeGoalState) (int handle); - //----------------------------------- - // be_ai_move.h - //----------------------------------- - void (*BotResetMoveState) (int movestate); - void (*BotMoveToGoal) (struct bot_moveresult_s * result, int movestate, struct bot_goal_s * goal, - int travelflags); - int (*BotMoveInDirection) (int movestate, vec3_t dir, float speed, int type); - void (*BotResetAvoidReach) (int movestate); - void (*BotResetLastAvoidReach) (int movestate); - int (*BotReachabilityArea) (vec3_t origin, int testground); - int (*BotMovementViewTarget) (int movestate, struct bot_goal_s * goal, int travelflags, float lookahead, - vec3_t target); - int (*BotPredictVisiblePosition) (vec3_t origin, int areanum, struct bot_goal_s * goal, int travelflags, - vec3_t target); - int (*BotAllocMoveState) (void); - void (*BotFreeMoveState) (int handle); - void (*BotInitMoveState) (int handle, struct bot_initmove_s * initmove); - void (*BotAddAvoidSpot) (int movestate, vec3_t origin, float radius, int type); - //----------------------------------- - // be_ai_weap.h - //----------------------------------- - int (*BotChooseBestFightWeapon) (int weaponstate, int *inventory); - void (*BotGetWeaponInfo) (int weaponstate, int weapon, struct weaponinfo_s * weaponinfo); - int (*BotLoadWeaponWeights) (int weaponstate, char *filename); - int (*BotAllocWeaponState) (void); - void (*BotFreeWeaponState) (int weaponstate); - void (*BotResetWeaponState) (int weaponstate); - //----------------------------------- - // be_ai_gen.h - //----------------------------------- - int (*GeneticParentsAndChildSelection) (int numranks, float *ranks, int *parent1, int *parent2, int *child); -} ai_export_t; - -//bot AI library imported functions -typedef struct botlib_export_s { - //Area Awareness System functions - aas_export_t aas; - //Elementary Action functions - ea_export_t ea; - //AI functions - ai_export_t ai; - //setup the bot library, returns BLERR_ - int (*BotLibSetup) (void); - //shutdown the bot library, returns BLERR_ - int (*BotLibShutdown) (void); - //sets a library variable returns BLERR_ - int (*BotLibVarSet) (char *var_name, char *value); - //gets a library variable returns BLERR_ - int (*BotLibVarGet) (char *var_name, char *value, int size); - - //sets a C-like define returns BLERR_ - int (*PC_AddGlobalDefine) (char *string); - int (*PC_LoadSourceHandle) (const char *filename); - int (*PC_FreeSourceHandle) (int handle); - int (*PC_ReadTokenHandle) (int handle, pc_token_t * pc_token); - int (*PC_SourceFileAndLine) (int handle, char *filename, int *line); - - //start a frame in the bot library - int (*BotLibStartFrame) (float time); - //load a new map in the bot library - int (*BotLibLoadMap) (const char *mapname); - //entity updates - int (*BotLibUpdateEntity) (int ent, bot_entitystate_t * state); - //just for testing - int (*Test) (int parm0, char *parm1, vec3_t parm2, vec3_t parm3); -} botlib_export_t; - -//linking of bot library -botlib_export_t *GetBotLibAPI(int apiVersion, botlib_import_t * import); - -/* Library variables: - -name: default: module(s): description: - -"basedir" "" l_utils.c base directory -"gamedir" "" l_utils.c game directory -"cddir" "" l_utils.c CD directory - -"log" "0" l_log.c enable/disable creating a log file -"maxclients" "4" be_interface.c maximum number of clients -"maxentities" "1024" be_interface.c maximum number of entities -"bot_developer" "0" be_interface.c bot developer mode - -"phys_friction" "6" be_aas_move.c ground friction -"phys_stopspeed" "100" be_aas_move.c stop speed -"phys_gravity" "800" be_aas_move.c gravity value -"phys_waterfriction" "1" be_aas_move.c water friction -"phys_watergravity" "400" be_aas_move.c gravity in water -"phys_maxvelocity" "320" be_aas_move.c maximum velocity -"phys_maxwalkvelocity" "320" be_aas_move.c maximum walk velocity -"phys_maxcrouchvelocity" "100" be_aas_move.c maximum crouch velocity -"phys_maxswimvelocity" "150" be_aas_move.c maximum swim velocity -"phys_walkaccelerate" "10" be_aas_move.c walk acceleration -"phys_airaccelerate" "1" be_aas_move.c air acceleration -"phys_swimaccelerate" "4" be_aas_move.c swim acceleration -"phys_maxstep" "18" be_aas_move.c maximum step height -"phys_maxsteepness" "0.7" be_aas_move.c maximum floor steepness -"phys_maxbarrier" "32" be_aas_move.c maximum barrier height -"phys_maxwaterjump" "19" be_aas_move.c maximum waterjump height -"phys_jumpvel" "270" be_aas_move.c jump z velocity -"phys_falldelta5" "40" be_aas_move.c -"phys_falldelta10" "60" be_aas_move.c -"rs_waterjump" "400" be_aas_move.c -"rs_teleport" "50" be_aas_move.c -"rs_barrierjump" "100" be_aas_move.c -"rs_startcrouch" "300" be_aas_move.c -"rs_startgrapple" "500" be_aas_move.c -"rs_startwalkoffledge" "70" be_aas_move.c -"rs_startjump" "300" be_aas_move.c -"rs_rocketjump" "500" be_aas_move.c -"rs_bfgjump" "500" be_aas_move.c -"rs_jumppad" "250" be_aas_move.c -"rs_aircontrolledjumppad" "300" be_aas_move.c -"rs_funcbob" "300" be_aas_move.c -"rs_startelevator" "50" be_aas_move.c -"rs_falldamage5" "300" be_aas_move.c -"rs_falldamage10" "500" be_aas_move.c -"rs_maxjumpfallheight" "450" be_aas_move.c - -"max_aaslinks" "4096" be_aas_sample.c maximum links in the AAS -"max_routingcache" "4096" be_aas_route.c maximum routing cache size in KB -"forceclustering" "0" be_aas_main.c force recalculation of clusters -"forcereachability" "0" be_aas_main.c force recalculation of reachabilities -"forcewrite" "0" be_aas_main.c force writing of aas file -"aasoptimize" "0" be_aas_main.c enable aas optimization -"sv_mapChecksum" "0" be_aas_main.c BSP file checksum -"bot_visualizejumppads" "0" be_aas_reach.c visualize jump pads - -"bot_reloadcharacters" "0" - reload bot character files -"ai_gametype" "0" be_ai_goal.c game type -"droppedweight" "1000" be_ai_goal.c additional dropped item weight -"weapindex_rocketlauncher" "5" be_ai_move.c rl weapon index for rocket jumping -"weapindex_bfg10k" "9" be_ai_move.c bfg weapon index for bfg jumping -"weapindex_grapple" "10" be_ai_move.c grapple weapon index for grappling -"entitytypemissile" "3" be_ai_move.c ET_MISSILE -"offhandgrapple" "0" be_ai_move.c enable off hand grapple hook -"cmd_grappleon" "grappleon" be_ai_move.c command to activate off hand grapple -"cmd_grappleoff" "grappleoff" be_ai_move.c command to deactivate off hand grapple -"itemconfig" "items.c" be_ai_goal.c item configuration file -"weaponconfig" "weapons.c" be_ai_weap.c weapon configuration file -"synfile" "syn.c" be_ai_chat.c file with synonyms -"rndfile" "rnd.c" be_ai_chat.c file with random strings -"matchfile" "match.c" be_ai_chat.c file with match strings -"nochat" "0" be_ai_chat.c disable chats -"max_messages" "1024" be_ai_chat.c console message heap size -"max_weaponinfo" "32" be_ai_weap.c maximum number of weapon info -"max_projectileinfo" "32" be_ai_weap.c maximum number of projectile info -"max_iteminfo" "256" be_ai_goal.c maximum number of item info -"max_levelitems" "256" be_ai_goal.c maximum number of level items - -*/ diff --git a/code/game/g_bot.c b/code/game/g_bot.c index 7901f43e..d0cc81c1 100644 --- a/code/game/g_bot.c +++ b/code/game/g_bot.c @@ -314,8 +314,7 @@ void G_AddRandomBot(int team) teamstr = "blue"; else teamstr = ""; - strncpy(netname, value, sizeof(netname) - 1); - netname[sizeof(netname) - 1] = '\0'; + Q_strncpyz(netname, value, sizeof(netname)); Q_CleanStr(netname); trap_SendConsoleCommand(EXEC_INSERT, va("addbot %s %f %s %i\n", netname, skill, teamstr, 0)); diff --git a/code/game/g_client.c b/code/game/g_client.c index 45e21a32..ed257a2f 100644 --- a/code/game/g_client.c +++ b/code/game/g_client.c @@ -858,7 +858,7 @@ TeamCount Returns number of players on a team ================ */ -team_t TeamCount(int ignoreClientNum, int team) +int TeamCount(int ignoreClientNum, int team) { int i; int count = 0; diff --git a/code/game/g_cmds.c b/code/game/g_cmds.c index 81438eee..78db62b3 100644 --- a/code/game/g_cmds.c +++ b/code/game/g_cmds.c @@ -2309,7 +2309,7 @@ void Cmd_Vote_f(gentity_t * ent) trap_Argv(1, msg, sizeof(msg)); - if (msg[0] == 'y' || msg[1] == 'Y' || msg[1] == '1') { + if ( tolower( msg[0] ) == 'y' || msg[0] == '1' ) { level.voteYes++; trap_SetConfigstring(CS_VOTE_YES, va("%i", level.voteYes)); } else { diff --git a/code/game/g_combat.c b/code/game/g_combat.c index a4fc172c..0c37f111 100644 --- a/code/game/g_combat.c +++ b/code/game/g_combat.c @@ -2343,6 +2343,8 @@ qboolean CanDamage(gentity_t * targ, vec3_t origin) vec3_t dest; trace_t tr; vec3_t midpoint; + vec3_t offsetmins = {-15, -15, -15}; + vec3_t offsetmaxs = {15, 15, 15}; // use the midpoint of the bounds instead of the origin, because // bmodels may have their origin is 0,0,0 @@ -2356,32 +2358,67 @@ qboolean CanDamage(gentity_t * targ, vec3_t origin) return qtrue; // this should probably check in the plane of projection, - // rather than in world coordinate, and also include Z + // rather than in world coordinate VectorCopy(midpoint, dest); - dest[0] += 15.0; - dest[1] += 15.0; + dest[0] += offsetmaxs[0]; + dest[1] += offsetmaxs[1]; + dest[2] += offsetmaxs[2]; trap_Trace(&tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID); + if (tr.fraction == 1.0) return qtrue; VectorCopy(midpoint, dest); - dest[0] += 15.0; - dest[1] -= 15.0; + dest[0] += offsetmaxs[0]; + dest[1] += offsetmins[1]; + dest[2] += offsetmaxs[2]; trap_Trace(&tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID); + if (tr.fraction == 1.0) return qtrue; VectorCopy(midpoint, dest); - dest[0] -= 15.0; - dest[1] += 15.0; + dest[0] += offsetmins[0]; + dest[1] += offsetmaxs[1]; + dest[2] += offsetmaxs[2]; trap_Trace(&tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID); + if (tr.fraction == 1.0) return qtrue; VectorCopy(midpoint, dest); - dest[0] -= 15.0; - dest[1] -= 15.0; + dest[0] += offsetmins[0]; + dest[1] += offsetmins[1]; + dest[2] += offsetmaxs[2]; trap_Trace(&tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID); + + if (tr.fraction == 1.0) + return qtrue; + + VectorCopy(midpoint, dest); + dest[0] += offsetmaxs[0]; + dest[1] += offsetmaxs[1]; + dest[2] += offsetmins[2]; + trap_Trace(&tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID); + + if (tr.fraction == 1.0) + return qtrue; + + VectorCopy(midpoint, dest); + dest[0] += offsetmaxs[0]; + dest[1] += offsetmins[1]; + dest[2] += offsetmins[2]; + trap_Trace(&tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID); + + if (tr.fraction == 1.0) + return qtrue; + + VectorCopy(midpoint, dest); + dest[0] += offsetmins[0]; + dest[1] += offsetmaxs[1]; + dest[2] += offsetmins[2]; + trap_Trace(&tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID); + if (tr.fraction == 1.0) return qtrue; diff --git a/code/game/g_fileio.c b/code/game/g_fileio.c deleted file mode 100644 index 843d2e01..00000000 --- a/code/game/g_fileio.c +++ /dev/null @@ -1,47 +0,0 @@ -//----------------------------------------------------------------------------- -// -// $Id$ -// -//----------------------------------------------------------------------------- -// -// $Log$ -// Revision 1.5 2002/06/16 20:06:14 jbravo -// Reindented all the source files with "indent -kr -ut -i8 -l120 -lc120 -sob -bad -bap" -// -// Revision 1.4 2002/01/11 19:48:30 jbravo -// Formatted the source in non DOS format. -// -// Revision 1.3 2001/12/31 16:28:42 jbravo -// I made a Booboo with the Log tag. -// -// -//----------------------------------------------------------------------------- -#include "../qcommon/q_shared.h" -#include "g_local.h" -#define MAX_ARENAS_TEXT 8192 -//Ok, here is how it works, you feed it a buffer in the form -//char buffer[MAX_ARENAS_TEXT]; -//and a file name in the form "test.cfg" or how ever you want -//so you would call it like this -//Cmd_ReadFile_f(mybuf,"motd.txt") -//it would then return a -1 if there is an error that I trapped, otherwise a 0 -//also, you will need to parse the file after you get it out! -int Cmd_ReadFile_f(char *buffer, char *fname) -{ - fileHandle_t f; - char tbuffer[MAX_ARENAS_TEXT]; //max text per line - int length; //The int for length of buffer - - length = trap_FS_FOpenFile(fname, &f, FS_READ); //Checks the file length - tbuffer[length] = 0; - if (length < 0) { - return -1; - } //If Length less than zero - if (length >= MAX_ARENAS_TEXT) { - return -1; - } - trap_FS_Read(tbuffer, length, f); - trap_FS_FCloseFile(f); - strcpy(buffer, tbuffer); - return 0; -} diff --git a/code/game/g_local.h b/code/game/g_local.h index 55326bbf..be8a855f 100644 --- a/code/game/g_local.h +++ b/code/game/g_local.h @@ -1230,7 +1230,7 @@ extern int tookShellHit[MAX_CLIENTS]; // // g_client.c // -team_t TeamCount(int ignoreClientNum, int team); +int TeamCount(int ignoreClientNum, int team); int TeamLeader(int team); team_t PickTeam(int ignoreClientNum); void SetClientViewAngle(gentity_t * ent, vec3_t angle); diff --git a/code/game/g_main.c b/code/game/g_main.c index 5a5f6499..73729408 100644 --- a/code/game/g_main.c +++ b/code/game/g_main.c @@ -915,6 +915,7 @@ void G_RegisterCvars(void) if (g_gametype.integer < 0 || g_gametype.integer >= GT_MAX_GAME_TYPE) { G_Printf("g_gametype %i is out of range, defaulting to 0\n", g_gametype.integer); trap_Cvar_Set("g_gametype", "0"); + trap_Cvar_Update( &g_gametype ); } // JBravo: lets disable the untested modes. if (g_gametype.integer != GT_FFA && g_gametype.integer != GT_TEAMPLAY && g_gametype.integer != GT_CTF && diff --git a/code/game/game.q3asm b/code/game/game.q3asm deleted file mode 100644 index c0600174..00000000 --- a/code/game/game.q3asm +++ /dev/null @@ -1,43 +0,0 @@ -g_main -..\g_syscalls -bg_misc -bg_lib -bg_pmove -bg_slidemove -q_math -q_shared -ai_dmnet -ai_dmq3 -ai_team -ai_main -ai_chat -ai_cmd -ai_vcmd -g_active -g_arenas -g_bot -g_client -g_cmds -g_combat -g_items -g_matchmode -g_mem -g_misc -g_missile -g_mover -g_parser -g_scripts -g_session -g_spawn -g_svcmds -g_target -g_team -g_teamplay -g_trigger -g_unlagged -g_utils -g_weapon -g_fileio -rxn_game -zcam -zcam_target diff --git a/code/game/game_ta.q3asm b/code/game/game_ta.q3asm deleted file mode 100644 index d699440f..00000000 --- a/code/game/game_ta.q3asm +++ /dev/null @@ -1,35 +0,0 @@ --o "\quake3\missionpack\vm\qagame" -g_main -..\g_syscalls -bg_misc -bg_lib -bg_pmove -bg_slidemove -q_math -q_shared -ai_dmnet -ai_dmq3 -ai_team -ai_main -ai_chat -ai_cmd -g_active -g_arenas -g_bot -g_client -g_cmds -g_combat -g_items -g_mem -g_misc -g_missile -g_mover -g_session -g_spawn -g_svcmds -g_target -g_team -g_trigger -g_utils -g_weapon -ai_vcmd diff --git a/code/game/make-game.bat b/code/game/make-game.bat deleted file mode 100644 index f98e8bd5..00000000 --- a/code/game/make-game.bat +++ /dev/null @@ -1,126 +0,0 @@ -@echo off - -REM *** NOTE: THIS BATCH FILE IS MEANT TO BE CALLED BY make-qvm.bat! -REM *** NOTE: THIS CANNOT BE RUN BY ITSELF WITHOUT %make-qvm-location% BEING DEFINED! - -cd vm -set cc=q3lcc.exe -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\ui - - -echo. -echo *** Running Q3LCC for GAME/QAGAME... - -%cc% ../g_main.c -@if errorlevel 1 goto quit -REM ***%cc% ../g_syscalls.c -REM *** cpp: ../g_syscalls.c:29 #error directive: "Do not use in VM build" -@if errorlevel 1 goto quit - -REM *** Makro - bg_materials.c needed for the new surfaceparm system -%cc% ../bg_materials.c -@if errorlevel 1 goto quit -%cc% ../bg_misc.c -@if errorlevel 1 goto quit -%cc% ../bg_lib.c -@if errorlevel 1 goto quit -%cc% ../bg_pmove.c -@if errorlevel 1 goto quit -%cc% ../bg_slidemove.c -@if errorlevel 1 goto quit - -%cc% ../q_math.c -@if errorlevel 1 goto quit -%cc% ../../qcommon/q_shared.c -@if errorlevel 1 goto quit - -%cc% ../ai_dmnet.c -@if errorlevel 1 goto quit -%cc% ../ai_dmq3.c -@if errorlevel 1 goto quit -%cc% ../ai_main.c -@if errorlevel 1 goto quit -%cc% ../ai_chat.c -@if errorlevel 1 goto quit -%cc% ../ai_cmd.c -@if errorlevel 1 goto quit -%cc% ../ai_team.c -@if errorlevel 1 goto quit -%cc% ../ai_vcmd.c -@if errorlevel 1 goto quit - -%cc% ../g_active.c -@if errorlevel 1 goto quit -%cc% ../g_arenas.c -@if errorlevel 1 goto quit -%cc% ../g_bot.c -@if errorlevel 1 goto quit -%cc% ../g_client.c -@if errorlevel 1 goto quit -%cc% ../g_cmds.c -@if errorlevel 1 goto quit -%cc% ../g_combat.c -@if errorlevel 1 goto quit -%cc% ../g_items.c -@if errorlevel 1 goto quit -%cc% ../g_matchmode.c -@if errorlevel 1 goto quit -%cc% ../g_mem.c -@if errorlevel 1 goto quit -%cc% ../g_misc.c -@if errorlevel 1 goto quit -%cc% ../g_missile.c -@if errorlevel 1 goto quit -%cc% ../g_mover.c -@if errorlevel 1 goto quit -%cc% ../g_parser.c -@if errorlevel 1 goto quit -%cc% ../g_scripts.c -@if errorlevel 1 goto quit -%cc% ../g_session.c -@if errorlevel 1 goto quit -%cc% ../g_spawn.c -@if errorlevel 1 goto quit -%cc% ../g_svcmds.c -@if errorlevel 1 goto quit -%cc% ../g_target.c -@if errorlevel 1 goto quit -%cc% ../g_team.c -@if errorlevel 1 goto quit -%cc% ../g_teamplay.c -@if errorlevel 1 goto quit -%cc% ../g_trigger.c -@if errorlevel 1 goto quit -%cc% ../g_utils.c -@if errorlevel 1 goto quit -%cc% ../g_unlagged.c -@if errorlevel 1 goto quit -%cc% ../g_weapon.c -@if errorlevel 1 goto quit -%cc% ../g_fileio.c -@if errorlevel 1 goto quit - -%cc% ../rxn_game.c -@if errorlevel 1 goto quit - -%cc% ../zcam.c -@if errorlevel 1 goto quit -%cc% ../zcam_target.c -@if errorlevel 1 goto quit - -echo. -echo *** Running Q3ASM for GAME/QAGAME... - -REM *** This tells q3asm to generate a vanilla q3-compatible qvm, generate a .map file, output -REM *** the resulting .qvm into "%make-qvm-location%bin\qvm\vm\qagame" (it will be called qagame.qvm), -REM *** and to compile the files listed in the game.q3asm script located in "%make-qvm-location%code/game/game". - -q3asm -vq3 -m -o "%make-qvm-location%bin\qvm\vm\qagame" -f "%make-qvm-location%code/game/game" - -:quit -if errorlevel 1 ( -echo. -echo ERROR IN Q3LCC PARSING! GAME/QAGAME COMPILATION HALTED! -echo. -) -echo. -cd .. diff --git a/code/libogg-1.3.0/include/ogg/config_types.h b/code/libogg-1.3.0/include/ogg/config_types.h new file mode 100644 index 00000000..e0dd8655 --- /dev/null +++ b/code/libogg-1.3.0/include/ogg/config_types.h @@ -0,0 +1,24 @@ +#ifndef __CONFIG_TYPES_H__ +#define __CONFIG_TYPES_H__ + +/* #define INCLUDE_INTTYPES_H 1 */ +#define INCLUDE_STDINT_H 1 +/* #define INCLUDE_SYS_TYPES_H 1 */ + +#if INCLUDE_INTTYPES_H +# include +#endif +#if INCLUDE_STDINT_H +# include +#endif +#if INCLUDE_SYS_TYPES_H +# include +#endif + +typedef int16_t ogg_int16_t; +typedef uint16_t ogg_uint16_t; +typedef int32_t ogg_int32_t; +typedef uint32_t ogg_uint32_t; +typedef int64_t ogg_int64_t; + +#endif diff --git a/code/libogg-1.3.0/include/ogg/ogg.h b/code/libogg-1.3.0/include/ogg/ogg.h new file mode 100644 index 00000000..cea4ebed --- /dev/null +++ b/code/libogg-1.3.0/include/ogg/ogg.h @@ -0,0 +1,210 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: toplevel libogg include + last mod: $Id: ogg.h 18044 2011-08-01 17:55:20Z gmaxwell $ + + ********************************************************************/ +#ifndef _OGG_H +#define _OGG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +typedef struct { + void *iov_base; + size_t iov_len; +} ogg_iovec_t; + +typedef struct { + long endbyte; + int endbit; + + unsigned char *buffer; + unsigned char *ptr; + long storage; +} oggpack_buffer; + +/* ogg_page is used to encapsulate the data in one Ogg bitstream page *****/ + +typedef struct { + unsigned char *header; + long header_len; + unsigned char *body; + long body_len; +} ogg_page; + +/* ogg_stream_state contains the current encode/decode state of a logical + Ogg bitstream **********************************************************/ + +typedef struct { + unsigned char *body_data; /* bytes from packet bodies */ + long body_storage; /* storage elements allocated */ + long body_fill; /* elements stored; fill mark */ + long body_returned; /* elements of fill returned */ + + + int *lacing_vals; /* The values that will go to the segment table */ + ogg_int64_t *granule_vals; /* granulepos values for headers. Not compact + this way, but it is simple coupled to the + lacing fifo */ + long lacing_storage; + long lacing_fill; + long lacing_packet; + long lacing_returned; + + unsigned char header[282]; /* working space for header encode */ + int header_fill; + + int e_o_s; /* set when we have buffered the last packet in the + logical bitstream */ + int b_o_s; /* set after we've written the initial page + of a logical bitstream */ + long serialno; + long pageno; + ogg_int64_t packetno; /* sequence number for decode; the framing + knows where there's a hole in the data, + but we need coupling so that the codec + (which is in a separate abstraction + layer) also knows about the gap */ + ogg_int64_t granulepos; + +} ogg_stream_state; + +/* ogg_packet is used to encapsulate the data and metadata belonging + to a single raw Ogg/Vorbis packet *************************************/ + +typedef struct { + unsigned char *packet; + long bytes; + long b_o_s; + long e_o_s; + + ogg_int64_t granulepos; + + ogg_int64_t packetno; /* sequence number for decode; the framing + knows where there's a hole in the data, + but we need coupling so that the codec + (which is in a separate abstraction + layer) also knows about the gap */ +} ogg_packet; + +typedef struct { + unsigned char *data; + int storage; + int fill; + int returned; + + int unsynced; + int headerbytes; + int bodybytes; +} ogg_sync_state; + +/* Ogg BITSTREAM PRIMITIVES: bitstream ************************/ + +extern void oggpack_writeinit(oggpack_buffer *b); +extern int oggpack_writecheck(oggpack_buffer *b); +extern void oggpack_writetrunc(oggpack_buffer *b,long bits); +extern void oggpack_writealign(oggpack_buffer *b); +extern void oggpack_writecopy(oggpack_buffer *b,void *source,long bits); +extern void oggpack_reset(oggpack_buffer *b); +extern void oggpack_writeclear(oggpack_buffer *b); +extern void oggpack_readinit(oggpack_buffer *b,unsigned char *buf,int bytes); +extern void oggpack_write(oggpack_buffer *b,unsigned long value,int bits); +extern long oggpack_look(oggpack_buffer *b,int bits); +extern long oggpack_look1(oggpack_buffer *b); +extern void oggpack_adv(oggpack_buffer *b,int bits); +extern void oggpack_adv1(oggpack_buffer *b); +extern long oggpack_read(oggpack_buffer *b,int bits); +extern long oggpack_read1(oggpack_buffer *b); +extern long oggpack_bytes(oggpack_buffer *b); +extern long oggpack_bits(oggpack_buffer *b); +extern unsigned char *oggpack_get_buffer(oggpack_buffer *b); + +extern void oggpackB_writeinit(oggpack_buffer *b); +extern int oggpackB_writecheck(oggpack_buffer *b); +extern void oggpackB_writetrunc(oggpack_buffer *b,long bits); +extern void oggpackB_writealign(oggpack_buffer *b); +extern void oggpackB_writecopy(oggpack_buffer *b,void *source,long bits); +extern void oggpackB_reset(oggpack_buffer *b); +extern void oggpackB_writeclear(oggpack_buffer *b); +extern void oggpackB_readinit(oggpack_buffer *b,unsigned char *buf,int bytes); +extern void oggpackB_write(oggpack_buffer *b,unsigned long value,int bits); +extern long oggpackB_look(oggpack_buffer *b,int bits); +extern long oggpackB_look1(oggpack_buffer *b); +extern void oggpackB_adv(oggpack_buffer *b,int bits); +extern void oggpackB_adv1(oggpack_buffer *b); +extern long oggpackB_read(oggpack_buffer *b,int bits); +extern long oggpackB_read1(oggpack_buffer *b); +extern long oggpackB_bytes(oggpack_buffer *b); +extern long oggpackB_bits(oggpack_buffer *b); +extern unsigned char *oggpackB_get_buffer(oggpack_buffer *b); + +/* Ogg BITSTREAM PRIMITIVES: encoding **************************/ + +extern int ogg_stream_packetin(ogg_stream_state *os, ogg_packet *op); +extern int ogg_stream_iovecin(ogg_stream_state *os, ogg_iovec_t *iov, + int count, long e_o_s, ogg_int64_t granulepos); +extern int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og); +extern int ogg_stream_pageout_fill(ogg_stream_state *os, ogg_page *og, int nfill); +extern int ogg_stream_flush(ogg_stream_state *os, ogg_page *og); +extern int ogg_stream_flush_fill(ogg_stream_state *os, ogg_page *og, int nfill); + +/* Ogg BITSTREAM PRIMITIVES: decoding **************************/ + +extern int ogg_sync_init(ogg_sync_state *oy); +extern int ogg_sync_clear(ogg_sync_state *oy); +extern int ogg_sync_reset(ogg_sync_state *oy); +extern int ogg_sync_destroy(ogg_sync_state *oy); +extern int ogg_sync_check(ogg_sync_state *oy); + +extern char *ogg_sync_buffer(ogg_sync_state *oy, long size); +extern int ogg_sync_wrote(ogg_sync_state *oy, long bytes); +extern long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og); +extern int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og); +extern int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og); +extern int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op); +extern int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op); + +/* Ogg BITSTREAM PRIMITIVES: general ***************************/ + +extern int ogg_stream_init(ogg_stream_state *os,int serialno); +extern int ogg_stream_clear(ogg_stream_state *os); +extern int ogg_stream_reset(ogg_stream_state *os); +extern int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno); +extern int ogg_stream_destroy(ogg_stream_state *os); +extern int ogg_stream_check(ogg_stream_state *os); +extern int ogg_stream_eos(ogg_stream_state *os); + +extern void ogg_page_checksum_set(ogg_page *og); + +extern int ogg_page_version(const ogg_page *og); +extern int ogg_page_continued(const ogg_page *og); +extern int ogg_page_bos(const ogg_page *og); +extern int ogg_page_eos(const ogg_page *og); +extern ogg_int64_t ogg_page_granulepos(const ogg_page *og); +extern int ogg_page_serialno(const ogg_page *og); +extern long ogg_page_pageno(const ogg_page *og); +extern int ogg_page_packets(const ogg_page *og); + +extern void ogg_packet_clear(ogg_packet *op); + + +#ifdef __cplusplus +} +#endif + +#endif /* _OGG_H */ diff --git a/code/libogg-1.3.0/include/ogg/os_types.h b/code/libogg-1.3.0/include/ogg/os_types.h new file mode 100644 index 00000000..d6691b70 --- /dev/null +++ b/code/libogg-1.3.0/include/ogg/os_types.h @@ -0,0 +1,147 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: #ifdef jail to whip a few platforms into the UNIX ideal. + last mod: $Id: os_types.h 17712 2010-12-03 17:10:02Z xiphmont $ + + ********************************************************************/ +#ifndef _OS_TYPES_H +#define _OS_TYPES_H + +/* make it easy on the folks that want to compile the libs with a + different malloc than stdlib */ +#define _ogg_malloc malloc +#define _ogg_calloc calloc +#define _ogg_realloc realloc +#define _ogg_free free + +#if defined(_WIN32) + +# if defined(__CYGWIN__) +# include + typedef int16_t ogg_int16_t; + typedef uint16_t ogg_uint16_t; + typedef int32_t ogg_int32_t; + typedef uint32_t ogg_uint32_t; + typedef int64_t ogg_int64_t; + typedef uint64_t ogg_uint64_t; +# elif defined(__MINGW32__) +# include + typedef short ogg_int16_t; + typedef unsigned short ogg_uint16_t; + typedef int ogg_int32_t; + typedef unsigned int ogg_uint32_t; + typedef long long ogg_int64_t; + typedef unsigned long long ogg_uint64_t; +# elif defined(__MWERKS__) + typedef long long ogg_int64_t; + typedef int ogg_int32_t; + typedef unsigned int ogg_uint32_t; + typedef short ogg_int16_t; + typedef unsigned short ogg_uint16_t; +# else + /* MSVC/Borland */ + typedef __int64 ogg_int64_t; + typedef __int32 ogg_int32_t; + typedef unsigned __int32 ogg_uint32_t; + typedef __int16 ogg_int16_t; + typedef unsigned __int16 ogg_uint16_t; +# endif + +#elif defined(__MACOS__) + +# include + typedef SInt16 ogg_int16_t; + typedef UInt16 ogg_uint16_t; + typedef SInt32 ogg_int32_t; + typedef UInt32 ogg_uint32_t; + typedef SInt64 ogg_int64_t; + +#elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */ + +# include + typedef int16_t ogg_int16_t; + typedef uint16_t ogg_uint16_t; + typedef int32_t ogg_int32_t; + typedef uint32_t ogg_uint32_t; + typedef int64_t ogg_int64_t; + +#elif defined(__HAIKU__) + + /* Haiku */ +# include + typedef short ogg_int16_t; + typedef unsigned short ogg_uint16_t; + typedef int ogg_int32_t; + typedef unsigned int ogg_uint32_t; + typedef long long ogg_int64_t; + +#elif defined(__BEOS__) + + /* Be */ +# include + typedef int16_t ogg_int16_t; + typedef uint16_t ogg_uint16_t; + typedef int32_t ogg_int32_t; + typedef uint32_t ogg_uint32_t; + typedef int64_t ogg_int64_t; + +#elif defined (__EMX__) + + /* OS/2 GCC */ + typedef short ogg_int16_t; + typedef unsigned short ogg_uint16_t; + typedef int ogg_int32_t; + typedef unsigned int ogg_uint32_t; + typedef long long ogg_int64_t; + +#elif defined (DJGPP) + + /* DJGPP */ + typedef short ogg_int16_t; + typedef int ogg_int32_t; + typedef unsigned int ogg_uint32_t; + typedef long long ogg_int64_t; + +#elif defined(R5900) + + /* PS2 EE */ + typedef long ogg_int64_t; + typedef int ogg_int32_t; + typedef unsigned ogg_uint32_t; + typedef short ogg_int16_t; + +#elif defined(__SYMBIAN32__) + + /* Symbian GCC */ + typedef signed short ogg_int16_t; + typedef unsigned short ogg_uint16_t; + typedef signed int ogg_int32_t; + typedef unsigned int ogg_uint32_t; + typedef long long int ogg_int64_t; + +#elif defined(__TMS320C6X__) + + /* TI C64x compiler */ + typedef signed short ogg_int16_t; + typedef unsigned short ogg_uint16_t; + typedef signed int ogg_int32_t; + typedef unsigned int ogg_uint32_t; + typedef long long int ogg_int64_t; + +#else + +# include + +#endif + +#endif /* _OS_TYPES_H */ diff --git a/code/libogg-1.3.0/src/bitwise.c b/code/libogg-1.3.0/src/bitwise.c new file mode 100644 index 00000000..68aca675 --- /dev/null +++ b/code/libogg-1.3.0/src/bitwise.c @@ -0,0 +1,857 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE Ogg CONTAINER SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2010 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: packing variable sized words into an octet stream + last mod: $Id: bitwise.c 18051 2011-08-04 17:56:39Z giles $ + + ********************************************************************/ + +/* We're 'LSb' endian; if we write a word but read individual bits, + then we'll read the lsb first */ + +#include +#include +#include +#include + +#define BUFFER_INCREMENT 256 + +static const unsigned long mask[]= +{0x00000000,0x00000001,0x00000003,0x00000007,0x0000000f, + 0x0000001f,0x0000003f,0x0000007f,0x000000ff,0x000001ff, + 0x000003ff,0x000007ff,0x00000fff,0x00001fff,0x00003fff, + 0x00007fff,0x0000ffff,0x0001ffff,0x0003ffff,0x0007ffff, + 0x000fffff,0x001fffff,0x003fffff,0x007fffff,0x00ffffff, + 0x01ffffff,0x03ffffff,0x07ffffff,0x0fffffff,0x1fffffff, + 0x3fffffff,0x7fffffff,0xffffffff }; + +static const unsigned int mask8B[]= +{0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff}; + +void oggpack_writeinit(oggpack_buffer *b){ + memset(b,0,sizeof(*b)); + b->ptr=b->buffer=_ogg_malloc(BUFFER_INCREMENT); + b->buffer[0]='\0'; + b->storage=BUFFER_INCREMENT; +} + +void oggpackB_writeinit(oggpack_buffer *b){ + oggpack_writeinit(b); +} + +int oggpack_writecheck(oggpack_buffer *b){ + if(!b->ptr || !b->storage)return -1; + return 0; +} + +int oggpackB_writecheck(oggpack_buffer *b){ + return oggpack_writecheck(b); +} + +void oggpack_writetrunc(oggpack_buffer *b,long bits){ + long bytes=bits>>3; + if(b->ptr){ + bits-=bytes*8; + b->ptr=b->buffer+bytes; + b->endbit=bits; + b->endbyte=bytes; + *b->ptr&=mask[bits]; + } +} + +void oggpackB_writetrunc(oggpack_buffer *b,long bits){ + long bytes=bits>>3; + if(b->ptr){ + bits-=bytes*8; + b->ptr=b->buffer+bytes; + b->endbit=bits; + b->endbyte=bytes; + *b->ptr&=mask8B[bits]; + } +} + +/* Takes only up to 32 bits. */ +void oggpack_write(oggpack_buffer *b,unsigned long value,int bits){ + if(bits<0 || bits>32) goto err; + if(b->endbyte>=b->storage-4){ + void *ret; + if(!b->ptr)return; + if(b->storage>LONG_MAX-BUFFER_INCREMENT) goto err; + ret=_ogg_realloc(b->buffer,b->storage+BUFFER_INCREMENT); + if(!ret) goto err; + b->buffer=ret; + b->storage+=BUFFER_INCREMENT; + b->ptr=b->buffer+b->endbyte; + } + + value&=mask[bits]; + bits+=b->endbit; + + b->ptr[0]|=value<endbit; + + if(bits>=8){ + b->ptr[1]=(unsigned char)(value>>(8-b->endbit)); + if(bits>=16){ + b->ptr[2]=(unsigned char)(value>>(16-b->endbit)); + if(bits>=24){ + b->ptr[3]=(unsigned char)(value>>(24-b->endbit)); + if(bits>=32){ + if(b->endbit) + b->ptr[4]=(unsigned char)(value>>(32-b->endbit)); + else + b->ptr[4]=0; + } + } + } + } + + b->endbyte+=bits/8; + b->ptr+=bits/8; + b->endbit=bits&7; + return; + err: + oggpack_writeclear(b); +} + +/* Takes only up to 32 bits. */ +void oggpackB_write(oggpack_buffer *b,unsigned long value,int bits){ + if(bits<0 || bits>32) goto err; + if(b->endbyte>=b->storage-4){ + void *ret; + if(!b->ptr)return; + if(b->storage>LONG_MAX-BUFFER_INCREMENT) goto err; + ret=_ogg_realloc(b->buffer,b->storage+BUFFER_INCREMENT); + if(!ret) goto err; + b->buffer=ret; + b->storage+=BUFFER_INCREMENT; + b->ptr=b->buffer+b->endbyte; + } + + value=(value&mask[bits])<<(32-bits); + bits+=b->endbit; + + b->ptr[0]|=value>>(24+b->endbit); + + if(bits>=8){ + b->ptr[1]=(unsigned char)(value>>(16+b->endbit)); + if(bits>=16){ + b->ptr[2]=(unsigned char)(value>>(8+b->endbit)); + if(bits>=24){ + b->ptr[3]=(unsigned char)(value>>(b->endbit)); + if(bits>=32){ + if(b->endbit) + b->ptr[4]=(unsigned char)(value<<(8-b->endbit)); + else + b->ptr[4]=0; + } + } + } + } + + b->endbyte+=bits/8; + b->ptr+=bits/8; + b->endbit=bits&7; + return; + err: + oggpack_writeclear(b); +} + +void oggpack_writealign(oggpack_buffer *b){ + int bits=8-b->endbit; + if(bits<8) + oggpack_write(b,0,bits); +} + +void oggpackB_writealign(oggpack_buffer *b){ + int bits=8-b->endbit; + if(bits<8) + oggpackB_write(b,0,bits); +} + +static void oggpack_writecopy_helper(oggpack_buffer *b, + void *source, + long bits, + void (*w)(oggpack_buffer *, + unsigned long, + int), + int msb){ + unsigned char *ptr=(unsigned char *)source; + + long bytes=bits/8; + bits-=bytes*8; + + if(b->endbit){ + int i; + /* unaligned copy. Do it the hard way. */ + for(i=0;iendbyte+bytes+1>=b->storage){ + void *ret; + if(!b->ptr) goto err; + if(b->endbyte+bytes+BUFFER_INCREMENT>b->storage) goto err; + b->storage=b->endbyte+bytes+BUFFER_INCREMENT; + ret=_ogg_realloc(b->buffer,b->storage); + if(!ret) goto err; + b->buffer=ret; + b->ptr=b->buffer+b->endbyte; + } + + memmove(b->ptr,source,bytes); + b->ptr+=bytes; + b->endbyte+=bytes; + *b->ptr=0; + + } + if(bits){ + if(msb) + w(b,(unsigned long)(ptr[bytes]>>(8-bits)),bits); + else + w(b,(unsigned long)(ptr[bytes]),bits); + } + return; + err: + oggpack_writeclear(b); +} + +void oggpack_writecopy(oggpack_buffer *b,void *source,long bits){ + oggpack_writecopy_helper(b,source,bits,oggpack_write,0); +} + +void oggpackB_writecopy(oggpack_buffer *b,void *source,long bits){ + oggpack_writecopy_helper(b,source,bits,oggpackB_write,1); +} + +void oggpack_reset(oggpack_buffer *b){ + if(!b->ptr)return; + b->ptr=b->buffer; + b->buffer[0]=0; + b->endbit=b->endbyte=0; +} + +void oggpackB_reset(oggpack_buffer *b){ + oggpack_reset(b); +} + +void oggpack_writeclear(oggpack_buffer *b){ + if(b->buffer)_ogg_free(b->buffer); + memset(b,0,sizeof(*b)); +} + +void oggpackB_writeclear(oggpack_buffer *b){ + oggpack_writeclear(b); +} + +void oggpack_readinit(oggpack_buffer *b,unsigned char *buf,int bytes){ + memset(b,0,sizeof(*b)); + b->buffer=b->ptr=buf; + b->storage=bytes; +} + +void oggpackB_readinit(oggpack_buffer *b,unsigned char *buf,int bytes){ + oggpack_readinit(b,buf,bytes); +} + +/* Read in bits without advancing the bitptr; bits <= 32 */ +long oggpack_look(oggpack_buffer *b,int bits){ + unsigned long ret; + unsigned long m; + + if(bits<0 || bits>32) return -1; + m=mask[bits]; + bits+=b->endbit; + + if(b->endbyte >= b->storage-4){ + /* not the main path */ + if(b->endbyte > b->storage-((bits+7)>>3)) return -1; + /* special case to avoid reading b->ptr[0], which might be past the end of + the buffer; also skips some useless accounting */ + else if(!bits)return(0L); + } + + ret=b->ptr[0]>>b->endbit; + if(bits>8){ + ret|=b->ptr[1]<<(8-b->endbit); + if(bits>16){ + ret|=b->ptr[2]<<(16-b->endbit); + if(bits>24){ + ret|=b->ptr[3]<<(24-b->endbit); + if(bits>32 && b->endbit) + ret|=b->ptr[4]<<(32-b->endbit); + } + } + } + return(m&ret); +} + +/* Read in bits without advancing the bitptr; bits <= 32 */ +long oggpackB_look(oggpack_buffer *b,int bits){ + unsigned long ret; + int m=32-bits; + + if(m<0 || m>32) return -1; + bits+=b->endbit; + + if(b->endbyte >= b->storage-4){ + /* not the main path */ + if(b->endbyte > b->storage-((bits+7)>>3)) return -1; + /* special case to avoid reading b->ptr[0], which might be past the end of + the buffer; also skips some useless accounting */ + else if(!bits)return(0L); + } + + ret=b->ptr[0]<<(24+b->endbit); + if(bits>8){ + ret|=b->ptr[1]<<(16+b->endbit); + if(bits>16){ + ret|=b->ptr[2]<<(8+b->endbit); + if(bits>24){ + ret|=b->ptr[3]<<(b->endbit); + if(bits>32 && b->endbit) + ret|=b->ptr[4]>>(8-b->endbit); + } + } + } + return ((ret&0xffffffff)>>(m>>1))>>((m+1)>>1); +} + +long oggpack_look1(oggpack_buffer *b){ + if(b->endbyte>=b->storage)return(-1); + return((b->ptr[0]>>b->endbit)&1); +} + +long oggpackB_look1(oggpack_buffer *b){ + if(b->endbyte>=b->storage)return(-1); + return((b->ptr[0]>>(7-b->endbit))&1); +} + +void oggpack_adv(oggpack_buffer *b,int bits){ + bits+=b->endbit; + + if(b->endbyte > b->storage-((bits+7)>>3)) goto overflow; + + b->ptr+=bits/8; + b->endbyte+=bits/8; + b->endbit=bits&7; + return; + + overflow: + b->ptr=NULL; + b->endbyte=b->storage; + b->endbit=1; +} + +void oggpackB_adv(oggpack_buffer *b,int bits){ + oggpack_adv(b,bits); +} + +void oggpack_adv1(oggpack_buffer *b){ + if(++(b->endbit)>7){ + b->endbit=0; + b->ptr++; + b->endbyte++; + } +} + +void oggpackB_adv1(oggpack_buffer *b){ + oggpack_adv1(b); +} + +/* bits <= 32 */ +long oggpack_read(oggpack_buffer *b,int bits){ + long ret; + unsigned long m; + + if(bits<0 || bits>32) goto err; + m=mask[bits]; + bits+=b->endbit; + + if(b->endbyte >= b->storage-4){ + /* not the main path */ + if(b->endbyte > b->storage-((bits+7)>>3)) goto overflow; + /* special case to avoid reading b->ptr[0], which might be past the end of + the buffer; also skips some useless accounting */ + else if(!bits)return(0L); + } + + ret=b->ptr[0]>>b->endbit; + if(bits>8){ + ret|=b->ptr[1]<<(8-b->endbit); + if(bits>16){ + ret|=b->ptr[2]<<(16-b->endbit); + if(bits>24){ + ret|=b->ptr[3]<<(24-b->endbit); + if(bits>32 && b->endbit){ + ret|=b->ptr[4]<<(32-b->endbit); + } + } + } + } + ret&=m; + b->ptr+=bits/8; + b->endbyte+=bits/8; + b->endbit=bits&7; + return ret; + + overflow: + err: + b->ptr=NULL; + b->endbyte=b->storage; + b->endbit=1; + return -1L; +} + +/* bits <= 32 */ +long oggpackB_read(oggpack_buffer *b,int bits){ + long ret; + long m=32-bits; + + if(m<0 || m>32) goto err; + bits+=b->endbit; + + if(b->endbyte+4>=b->storage){ + /* not the main path */ + if(b->endbyte > b->storage-((bits+7)>>3)) goto overflow; + /* special case to avoid reading b->ptr[0], which might be past the end of + the buffer; also skips some useless accounting */ + else if(!bits)return(0L); + } + + ret=b->ptr[0]<<(24+b->endbit); + if(bits>8){ + ret|=b->ptr[1]<<(16+b->endbit); + if(bits>16){ + ret|=b->ptr[2]<<(8+b->endbit); + if(bits>24){ + ret|=b->ptr[3]<<(b->endbit); + if(bits>32 && b->endbit) + ret|=b->ptr[4]>>(8-b->endbit); + } + } + } + ret=((ret&0xffffffffUL)>>(m>>1))>>((m+1)>>1); + + b->ptr+=bits/8; + b->endbyte+=bits/8; + b->endbit=bits&7; + return ret; + + overflow: + err: + b->ptr=NULL; + b->endbyte=b->storage; + b->endbit=1; + return -1L; +} + +long oggpack_read1(oggpack_buffer *b){ + long ret; + + if(b->endbyte >= b->storage) goto overflow; + ret=(b->ptr[0]>>b->endbit)&1; + + b->endbit++; + if(b->endbit>7){ + b->endbit=0; + b->ptr++; + b->endbyte++; + } + return ret; + + overflow: + b->ptr=NULL; + b->endbyte=b->storage; + b->endbit=1; + return -1L; +} + +long oggpackB_read1(oggpack_buffer *b){ + long ret; + + if(b->endbyte >= b->storage) goto overflow; + ret=(b->ptr[0]>>(7-b->endbit))&1; + + b->endbit++; + if(b->endbit>7){ + b->endbit=0; + b->ptr++; + b->endbyte++; + } + return ret; + + overflow: + b->ptr=NULL; + b->endbyte=b->storage; + b->endbit=1; + return -1L; +} + +long oggpack_bytes(oggpack_buffer *b){ + return(b->endbyte+(b->endbit+7)/8); +} + +long oggpack_bits(oggpack_buffer *b){ + return(b->endbyte*8+b->endbit); +} + +long oggpackB_bytes(oggpack_buffer *b){ + return oggpack_bytes(b); +} + +long oggpackB_bits(oggpack_buffer *b){ + return oggpack_bits(b); +} + +unsigned char *oggpack_get_buffer(oggpack_buffer *b){ + return(b->buffer); +} + +unsigned char *oggpackB_get_buffer(oggpack_buffer *b){ + return oggpack_get_buffer(b); +} + +/* Self test of the bitwise routines; everything else is based on + them, so they damned well better be solid. */ + +#ifdef _V_SELFTEST +#include + +static int ilog(unsigned int v){ + int ret=0; + while(v){ + ret++; + v>>=1; + } + return(ret); +} + +oggpack_buffer o; +oggpack_buffer r; + +void report(char *in){ + fprintf(stderr,"%s",in); + exit(1); +} + +void cliptest(unsigned long *b,int vals,int bits,int *comp,int compsize){ + long bytes,i; + unsigned char *buffer; + + oggpack_reset(&o); + for(i=0;i +#include +#include + +/* A complete description of Ogg framing exists in docs/framing.html */ + +int ogg_page_version(const ogg_page *og){ + return((int)(og->header[4])); +} + +int ogg_page_continued(const ogg_page *og){ + return((int)(og->header[5]&0x01)); +} + +int ogg_page_bos(const ogg_page *og){ + return((int)(og->header[5]&0x02)); +} + +int ogg_page_eos(const ogg_page *og){ + return((int)(og->header[5]&0x04)); +} + +ogg_int64_t ogg_page_granulepos(const ogg_page *og){ + unsigned char *page=og->header; + ogg_int64_t granulepos=page[13]&(0xff); + granulepos= (granulepos<<8)|(page[12]&0xff); + granulepos= (granulepos<<8)|(page[11]&0xff); + granulepos= (granulepos<<8)|(page[10]&0xff); + granulepos= (granulepos<<8)|(page[9]&0xff); + granulepos= (granulepos<<8)|(page[8]&0xff); + granulepos= (granulepos<<8)|(page[7]&0xff); + granulepos= (granulepos<<8)|(page[6]&0xff); + return(granulepos); +} + +int ogg_page_serialno(const ogg_page *og){ + return(og->header[14] | + (og->header[15]<<8) | + (og->header[16]<<16) | + (og->header[17]<<24)); +} + +long ogg_page_pageno(const ogg_page *og){ + return(og->header[18] | + (og->header[19]<<8) | + (og->header[20]<<16) | + (og->header[21]<<24)); +} + + + +/* returns the number of packets that are completed on this page (if + the leading packet is begun on a previous page, but ends on this + page, it's counted */ + +/* NOTE: + If a page consists of a packet begun on a previous page, and a new + packet begun (but not completed) on this page, the return will be: + ogg_page_packets(page) ==1, + ogg_page_continued(page) !=0 + + If a page happens to be a single packet that was begun on a + previous page, and spans to the next page (in the case of a three or + more page packet), the return will be: + ogg_page_packets(page) ==0, + ogg_page_continued(page) !=0 +*/ + +int ogg_page_packets(const ogg_page *og){ + int i,n=og->header[26],count=0; + for(i=0;iheader[27+i]<255)count++; + return(count); +} + + +#if 0 +/* helper to initialize lookup for direct-table CRC (illustrative; we + use the static init below) */ + +static ogg_uint32_t _ogg_crc_entry(unsigned long index){ + int i; + unsigned long r; + + r = index << 24; + for (i=0; i<8; i++) + if (r & 0x80000000UL) + r = (r << 1) ^ 0x04c11db7; /* The same as the ethernet generator + polynomial, although we use an + unreflected alg and an init/final + of 0, not 0xffffffff */ + else + r<<=1; + return (r & 0xffffffffUL); +} +#endif + +static const ogg_uint32_t crc_lookup[256]={ + 0x00000000,0x04c11db7,0x09823b6e,0x0d4326d9, + 0x130476dc,0x17c56b6b,0x1a864db2,0x1e475005, + 0x2608edb8,0x22c9f00f,0x2f8ad6d6,0x2b4bcb61, + 0x350c9b64,0x31cd86d3,0x3c8ea00a,0x384fbdbd, + 0x4c11db70,0x48d0c6c7,0x4593e01e,0x4152fda9, + 0x5f15adac,0x5bd4b01b,0x569796c2,0x52568b75, + 0x6a1936c8,0x6ed82b7f,0x639b0da6,0x675a1011, + 0x791d4014,0x7ddc5da3,0x709f7b7a,0x745e66cd, + 0x9823b6e0,0x9ce2ab57,0x91a18d8e,0x95609039, + 0x8b27c03c,0x8fe6dd8b,0x82a5fb52,0x8664e6e5, + 0xbe2b5b58,0xbaea46ef,0xb7a96036,0xb3687d81, + 0xad2f2d84,0xa9ee3033,0xa4ad16ea,0xa06c0b5d, + 0xd4326d90,0xd0f37027,0xddb056fe,0xd9714b49, + 0xc7361b4c,0xc3f706fb,0xceb42022,0xca753d95, + 0xf23a8028,0xf6fb9d9f,0xfbb8bb46,0xff79a6f1, + 0xe13ef6f4,0xe5ffeb43,0xe8bccd9a,0xec7dd02d, + 0x34867077,0x30476dc0,0x3d044b19,0x39c556ae, + 0x278206ab,0x23431b1c,0x2e003dc5,0x2ac12072, + 0x128e9dcf,0x164f8078,0x1b0ca6a1,0x1fcdbb16, + 0x018aeb13,0x054bf6a4,0x0808d07d,0x0cc9cdca, + 0x7897ab07,0x7c56b6b0,0x71159069,0x75d48dde, + 0x6b93dddb,0x6f52c06c,0x6211e6b5,0x66d0fb02, + 0x5e9f46bf,0x5a5e5b08,0x571d7dd1,0x53dc6066, + 0x4d9b3063,0x495a2dd4,0x44190b0d,0x40d816ba, + 0xaca5c697,0xa864db20,0xa527fdf9,0xa1e6e04e, + 0xbfa1b04b,0xbb60adfc,0xb6238b25,0xb2e29692, + 0x8aad2b2f,0x8e6c3698,0x832f1041,0x87ee0df6, + 0x99a95df3,0x9d684044,0x902b669d,0x94ea7b2a, + 0xe0b41de7,0xe4750050,0xe9362689,0xedf73b3e, + 0xf3b06b3b,0xf771768c,0xfa325055,0xfef34de2, + 0xc6bcf05f,0xc27dede8,0xcf3ecb31,0xcbffd686, + 0xd5b88683,0xd1799b34,0xdc3abded,0xd8fba05a, + 0x690ce0ee,0x6dcdfd59,0x608edb80,0x644fc637, + 0x7a089632,0x7ec98b85,0x738aad5c,0x774bb0eb, + 0x4f040d56,0x4bc510e1,0x46863638,0x42472b8f, + 0x5c007b8a,0x58c1663d,0x558240e4,0x51435d53, + 0x251d3b9e,0x21dc2629,0x2c9f00f0,0x285e1d47, + 0x36194d42,0x32d850f5,0x3f9b762c,0x3b5a6b9b, + 0x0315d626,0x07d4cb91,0x0a97ed48,0x0e56f0ff, + 0x1011a0fa,0x14d0bd4d,0x19939b94,0x1d528623, + 0xf12f560e,0xf5ee4bb9,0xf8ad6d60,0xfc6c70d7, + 0xe22b20d2,0xe6ea3d65,0xeba91bbc,0xef68060b, + 0xd727bbb6,0xd3e6a601,0xdea580d8,0xda649d6f, + 0xc423cd6a,0xc0e2d0dd,0xcda1f604,0xc960ebb3, + 0xbd3e8d7e,0xb9ff90c9,0xb4bcb610,0xb07daba7, + 0xae3afba2,0xaafbe615,0xa7b8c0cc,0xa379dd7b, + 0x9b3660c6,0x9ff77d71,0x92b45ba8,0x9675461f, + 0x8832161a,0x8cf30bad,0x81b02d74,0x857130c3, + 0x5d8a9099,0x594b8d2e,0x5408abf7,0x50c9b640, + 0x4e8ee645,0x4a4ffbf2,0x470cdd2b,0x43cdc09c, + 0x7b827d21,0x7f436096,0x7200464f,0x76c15bf8, + 0x68860bfd,0x6c47164a,0x61043093,0x65c52d24, + 0x119b4be9,0x155a565e,0x18197087,0x1cd86d30, + 0x029f3d35,0x065e2082,0x0b1d065b,0x0fdc1bec, + 0x3793a651,0x3352bbe6,0x3e119d3f,0x3ad08088, + 0x2497d08d,0x2056cd3a,0x2d15ebe3,0x29d4f654, + 0xc5a92679,0xc1683bce,0xcc2b1d17,0xc8ea00a0, + 0xd6ad50a5,0xd26c4d12,0xdf2f6bcb,0xdbee767c, + 0xe3a1cbc1,0xe760d676,0xea23f0af,0xeee2ed18, + 0xf0a5bd1d,0xf464a0aa,0xf9278673,0xfde69bc4, + 0x89b8fd09,0x8d79e0be,0x803ac667,0x84fbdbd0, + 0x9abc8bd5,0x9e7d9662,0x933eb0bb,0x97ffad0c, + 0xafb010b1,0xab710d06,0xa6322bdf,0xa2f33668, + 0xbcb4666d,0xb8757bda,0xb5365d03,0xb1f740b4}; + +/* init the encode/decode logical stream state */ + +int ogg_stream_init(ogg_stream_state *os,int serialno){ + if(os){ + memset(os,0,sizeof(*os)); + os->body_storage=16*1024; + os->lacing_storage=1024; + + os->body_data=_ogg_malloc(os->body_storage*sizeof(*os->body_data)); + os->lacing_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->lacing_vals)); + os->granule_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->granule_vals)); + + if(!os->body_data || !os->lacing_vals || !os->granule_vals){ + ogg_stream_clear(os); + return -1; + } + + os->serialno=serialno; + + return(0); + } + return(-1); +} + +/* async/delayed error detection for the ogg_stream_state */ +int ogg_stream_check(ogg_stream_state *os){ + if(!os || !os->body_data) return -1; + return 0; +} + +/* _clear does not free os, only the non-flat storage within */ +int ogg_stream_clear(ogg_stream_state *os){ + if(os){ + if(os->body_data)_ogg_free(os->body_data); + if(os->lacing_vals)_ogg_free(os->lacing_vals); + if(os->granule_vals)_ogg_free(os->granule_vals); + + memset(os,0,sizeof(*os)); + } + return(0); +} + +int ogg_stream_destroy(ogg_stream_state *os){ + if(os){ + ogg_stream_clear(os); + _ogg_free(os); + } + return(0); +} + +/* Helpers for ogg_stream_encode; this keeps the structure and + what's happening fairly clear */ + +static int _os_body_expand(ogg_stream_state *os,int needed){ + if(os->body_storage<=os->body_fill+needed){ + void *ret; + ret=_ogg_realloc(os->body_data,(os->body_storage+needed+1024)* + sizeof(*os->body_data)); + if(!ret){ + ogg_stream_clear(os); + return -1; + } + os->body_storage+=(needed+1024); + os->body_data=ret; + } + return 0; +} + +static int _os_lacing_expand(ogg_stream_state *os,int needed){ + if(os->lacing_storage<=os->lacing_fill+needed){ + void *ret; + ret=_ogg_realloc(os->lacing_vals,(os->lacing_storage+needed+32)* + sizeof(*os->lacing_vals)); + if(!ret){ + ogg_stream_clear(os); + return -1; + } + os->lacing_vals=ret; + ret=_ogg_realloc(os->granule_vals,(os->lacing_storage+needed+32)* + sizeof(*os->granule_vals)); + if(!ret){ + ogg_stream_clear(os); + return -1; + } + os->granule_vals=ret; + os->lacing_storage+=(needed+32); + } + return 0; +} + +/* checksum the page */ +/* Direct table CRC; note that this will be faster in the future if we + perform the checksum simultaneously with other copies */ + +void ogg_page_checksum_set(ogg_page *og){ + if(og){ + ogg_uint32_t crc_reg=0; + int i; + + /* safety; needed for API behavior, but not framing code */ + og->header[22]=0; + og->header[23]=0; + og->header[24]=0; + og->header[25]=0; + + for(i=0;iheader_len;i++) + crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->header[i]]; + for(i=0;ibody_len;i++) + crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->body[i]]; + + og->header[22]=(unsigned char)(crc_reg&0xff); + og->header[23]=(unsigned char)((crc_reg>>8)&0xff); + og->header[24]=(unsigned char)((crc_reg>>16)&0xff); + og->header[25]=(unsigned char)((crc_reg>>24)&0xff); + } +} + +/* submit data to the internal buffer of the framing engine */ +int ogg_stream_iovecin(ogg_stream_state *os, ogg_iovec_t *iov, int count, + long e_o_s, ogg_int64_t granulepos){ + + int bytes = 0, lacing_vals, i; + + if(ogg_stream_check(os)) return -1; + if(!iov) return 0; + + for (i = 0; i < count; ++i) bytes += (int)iov[i].iov_len; + lacing_vals=bytes/255+1; + + if(os->body_returned){ + /* advance packet data according to the body_returned pointer. We + had to keep it around to return a pointer into the buffer last + call */ + + os->body_fill-=os->body_returned; + if(os->body_fill) + memmove(os->body_data,os->body_data+os->body_returned, + os->body_fill); + os->body_returned=0; + } + + /* make sure we have the buffer storage */ + if(_os_body_expand(os,bytes) || _os_lacing_expand(os,lacing_vals)) + return -1; + + /* Copy in the submitted packet. Yes, the copy is a waste; this is + the liability of overly clean abstraction for the time being. It + will actually be fairly easy to eliminate the extra copy in the + future */ + + for (i = 0; i < count; ++i) { + memcpy(os->body_data+os->body_fill, iov[i].iov_base, iov[i].iov_len); + os->body_fill += (int)iov[i].iov_len; + } + + /* Store lacing vals for this packet */ + for(i=0;ilacing_vals[os->lacing_fill+i]=255; + os->granule_vals[os->lacing_fill+i]=os->granulepos; + } + os->lacing_vals[os->lacing_fill+i]=bytes%255; + os->granulepos=os->granule_vals[os->lacing_fill+i]=granulepos; + + /* flag the first segment as the beginning of the packet */ + os->lacing_vals[os->lacing_fill]|= 0x100; + + os->lacing_fill+=lacing_vals; + + /* for the sake of completeness */ + os->packetno++; + + if(e_o_s)os->e_o_s=1; + + return(0); +} + +int ogg_stream_packetin(ogg_stream_state *os,ogg_packet *op){ + ogg_iovec_t iov; + iov.iov_base = op->packet; + iov.iov_len = op->bytes; + return ogg_stream_iovecin(os, &iov, 1, op->e_o_s, op->granulepos); +} + +/* Conditionally flush a page; force==0 will only flush nominal-size + pages, force==1 forces us to flush a page regardless of page size + so long as there's any data available at all. */ +static int ogg_stream_flush_i(ogg_stream_state *os,ogg_page *og, int force, int nfill){ + int i; + int vals=0; + int maxvals=(os->lacing_fill>255?255:os->lacing_fill); + int bytes=0; + long acc=0; + ogg_int64_t granule_pos=-1; + + if(ogg_stream_check(os)) return(0); + if(maxvals==0) return(0); + + /* construct a page */ + /* decide how many segments to include */ + + /* If this is the initial header case, the first page must only include + the initial header packet */ + if(os->b_o_s==0){ /* 'initial header page' case */ + granule_pos=0; + for(vals=0;valslacing_vals[vals]&0x0ff)<255){ + vals++; + break; + } + } + }else{ + + /* The extra packets_done, packet_just_done logic here attempts to do two things: + 1) Don't unneccessarily span pages. + 2) Unless necessary, don't flush pages if there are less than four packets on + them; this expands page size to reduce unneccessary overhead if incoming packets + are large. + These are not necessary behaviors, just 'always better than naive flushing' + without requiring an application to explicitly request a specific optimized + behavior. We'll want an explicit behavior setup pathway eventually as well. */ + + int packets_done=0; + int packet_just_done=0; + for(vals=0;valsnfill && packet_just_done>=4){ + force=1; + break; + } + acc+=os->lacing_vals[vals]&0x0ff; + if((os->lacing_vals[vals]&0xff)<255){ + granule_pos=os->granule_vals[vals]; + packet_just_done=++packets_done; + }else + packet_just_done=0; + } + if(vals==255)force=1; + } + + if(!force) return(0); + + /* construct the header in temp storage */ + memcpy(os->header,"OggS",4); + + /* stream structure version */ + os->header[4]=0x00; + + /* continued packet flag? */ + os->header[5]=0x00; + if((os->lacing_vals[0]&0x100)==0)os->header[5]|=0x01; + /* first page flag? */ + if(os->b_o_s==0)os->header[5]|=0x02; + /* last page flag? */ + if(os->e_o_s && os->lacing_fill==vals)os->header[5]|=0x04; + os->b_o_s=1; + + /* 64 bits of PCM position */ + for(i=6;i<14;i++){ + os->header[i]=(unsigned char)(granule_pos&0xff); + granule_pos>>=8; + } + + /* 32 bits of stream serial number */ + { + long serialno=os->serialno; + for(i=14;i<18;i++){ + os->header[i]=(unsigned char)(serialno&0xff); + serialno>>=8; + } + } + + /* 32 bits of page counter (we have both counter and page header + because this val can roll over) */ + if(os->pageno==-1)os->pageno=0; /* because someone called + stream_reset; this would be a + strange thing to do in an + encode stream, but it has + plausible uses */ + { + long pageno=os->pageno++; + for(i=18;i<22;i++){ + os->header[i]=(unsigned char)(pageno&0xff); + pageno>>=8; + } + } + + /* zero for computation; filled in later */ + os->header[22]=0; + os->header[23]=0; + os->header[24]=0; + os->header[25]=0; + + /* segment table */ + os->header[26]=(unsigned char)(vals&0xff); + for(i=0;iheader[i+27]=(unsigned char)(os->lacing_vals[i]&0xff); + + /* set pointers in the ogg_page struct */ + og->header=os->header; + og->header_len=os->header_fill=vals+27; + og->body=os->body_data+os->body_returned; + og->body_len=bytes; + + /* advance the lacing data and set the body_returned pointer */ + + os->lacing_fill-=vals; + memmove(os->lacing_vals,os->lacing_vals+vals,os->lacing_fill*sizeof(*os->lacing_vals)); + memmove(os->granule_vals,os->granule_vals+vals,os->lacing_fill*sizeof(*os->granule_vals)); + os->body_returned+=bytes; + + /* calculate the checksum */ + + ogg_page_checksum_set(og); + + /* done */ + return(1); +} + +/* This will flush remaining packets into a page (returning nonzero), + even if there is not enough data to trigger a flush normally + (undersized page). If there are no packets or partial packets to + flush, ogg_stream_flush returns 0. Note that ogg_stream_flush will + try to flush a normal sized page like ogg_stream_pageout; a call to + ogg_stream_flush does not guarantee that all packets have flushed. + Only a return value of 0 from ogg_stream_flush indicates all packet + data is flushed into pages. + + since ogg_stream_flush will flush the last page in a stream even if + it's undersized, you almost certainly want to use ogg_stream_pageout + (and *not* ogg_stream_flush) unless you specifically need to flush + a page regardless of size in the middle of a stream. */ + +int ogg_stream_flush(ogg_stream_state *os,ogg_page *og){ + return ogg_stream_flush_i(os,og,1,4096); +} + +/* Like the above, but an argument is provided to adjust the nominal + page size for applications which are smart enough to provide their + own delay based flushing */ + +int ogg_stream_flush_fill(ogg_stream_state *os,ogg_page *og, int nfill){ + return ogg_stream_flush_i(os,og,1,nfill); +} + +/* This constructs pages from buffered packet segments. The pointers +returned are to static buffers; do not free. The returned buffers are +good only until the next call (using the same ogg_stream_state) */ + +int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og){ + int force=0; + if(ogg_stream_check(os)) return 0; + + if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */ + (os->lacing_fill&&!os->b_o_s)) /* 'initial header page' case */ + force=1; + + return(ogg_stream_flush_i(os,og,force,4096)); +} + +/* Like the above, but an argument is provided to adjust the nominal +page size for applications which are smart enough to provide their +own delay based flushing */ + +int ogg_stream_pageout_fill(ogg_stream_state *os, ogg_page *og, int nfill){ + int force=0; + if(ogg_stream_check(os)) return 0; + + if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */ + (os->lacing_fill&&!os->b_o_s)) /* 'initial header page' case */ + force=1; + + return(ogg_stream_flush_i(os,og,force,nfill)); +} + +int ogg_stream_eos(ogg_stream_state *os){ + if(ogg_stream_check(os)) return 1; + return os->e_o_s; +} + +/* DECODING PRIMITIVES: packet streaming layer **********************/ + +/* This has two layers to place more of the multi-serialno and paging + control in the application's hands. First, we expose a data buffer + using ogg_sync_buffer(). The app either copies into the + buffer, or passes it directly to read(), etc. We then call + ogg_sync_wrote() to tell how many bytes we just added. + + Pages are returned (pointers into the buffer in ogg_sync_state) + by ogg_sync_pageout(). The page is then submitted to + ogg_stream_pagein() along with the appropriate + ogg_stream_state* (ie, matching serialno). We then get raw + packets out calling ogg_stream_packetout() with a + ogg_stream_state. */ + +/* initialize the struct to a known state */ +int ogg_sync_init(ogg_sync_state *oy){ + if(oy){ + oy->storage = -1; /* used as a readiness flag */ + memset(oy,0,sizeof(*oy)); + } + return(0); +} + +/* clear non-flat storage within */ +int ogg_sync_clear(ogg_sync_state *oy){ + if(oy){ + if(oy->data)_ogg_free(oy->data); + memset(oy,0,sizeof(*oy)); + } + return(0); +} + +int ogg_sync_destroy(ogg_sync_state *oy){ + if(oy){ + ogg_sync_clear(oy); + _ogg_free(oy); + } + return(0); +} + +int ogg_sync_check(ogg_sync_state *oy){ + if(oy->storage<0) return -1; + return 0; +} + +char *ogg_sync_buffer(ogg_sync_state *oy, long size){ + if(ogg_sync_check(oy)) return NULL; + + /* first, clear out any space that has been previously returned */ + if(oy->returned){ + oy->fill-=oy->returned; + if(oy->fill>0) + memmove(oy->data,oy->data+oy->returned,oy->fill); + oy->returned=0; + } + + if(size>oy->storage-oy->fill){ + /* We need to extend the internal buffer */ + long newsize=size+oy->fill+4096; /* an extra page to be nice */ + void *ret; + + if(oy->data) + ret=_ogg_realloc(oy->data,newsize); + else + ret=_ogg_malloc(newsize); + if(!ret){ + ogg_sync_clear(oy); + return NULL; + } + oy->data=ret; + oy->storage=newsize; + } + + /* expose a segment at least as large as requested at the fill mark */ + return((char *)oy->data+oy->fill); +} + +int ogg_sync_wrote(ogg_sync_state *oy, long bytes){ + if(ogg_sync_check(oy))return -1; + if(oy->fill+bytes>oy->storage)return -1; + oy->fill+=bytes; + return(0); +} + +/* sync the stream. This is meant to be useful for finding page + boundaries. + + return values for this: + -n) skipped n bytes + 0) page not ready; more data (no bytes skipped) + n) page synced at current location; page length n bytes + +*/ + +long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){ + unsigned char *page=oy->data+oy->returned; + unsigned char *next; + long bytes=oy->fill-oy->returned; + + if(ogg_sync_check(oy))return 0; + + if(oy->headerbytes==0){ + int headerbytes,i; + if(bytes<27)return(0); /* not enough for a header */ + + /* verify capture pattern */ + if(memcmp(page,"OggS",4))goto sync_fail; + + headerbytes=page[26]+27; + if(bytesbodybytes+=page[27+i]; + oy->headerbytes=headerbytes; + } + + if(oy->bodybytes+oy->headerbytes>bytes)return(0); + + /* The whole test page is buffered. Verify the checksum */ + { + /* Grab the checksum bytes, set the header field to zero */ + char chksum[4]; + ogg_page log; + + memcpy(chksum,page+22,4); + memset(page+22,0,4); + + /* set up a temp page struct and recompute the checksum */ + log.header=page; + log.header_len=oy->headerbytes; + log.body=page+oy->headerbytes; + log.body_len=oy->bodybytes; + ogg_page_checksum_set(&log); + + /* Compare */ + if(memcmp(chksum,page+22,4)){ + /* D'oh. Mismatch! Corrupt page (or miscapture and not a page + at all) */ + /* replace the computed checksum with the one actually read in */ + memcpy(page+22,chksum,4); + + /* Bad checksum. Lose sync */ + goto sync_fail; + } + } + + /* yes, have a whole page all ready to go */ + { + unsigned char *page=oy->data+oy->returned; + long bytes; + + if(og){ + og->header=page; + og->header_len=oy->headerbytes; + og->body=page+oy->headerbytes; + og->body_len=oy->bodybytes; + } + + oy->unsynced=0; + oy->returned+=(bytes=oy->headerbytes+oy->bodybytes); + oy->headerbytes=0; + oy->bodybytes=0; + return(bytes); + } + + sync_fail: + + oy->headerbytes=0; + oy->bodybytes=0; + + /* search for possible capture */ + next=memchr(page+1,'O',bytes-1); + if(!next) + next=oy->data+oy->fill; + + oy->returned=(int)(next-oy->data); + return((long)-(next-page)); +} + +/* sync the stream and get a page. Keep trying until we find a page. + Suppress 'sync errors' after reporting the first. + + return values: + -1) recapture (hole in data) + 0) need more data + 1) page returned + + Returns pointers into buffered data; invalidated by next call to + _stream, _clear, _init, or _buffer */ + +int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){ + + if(ogg_sync_check(oy))return 0; + + /* all we need to do is verify a page at the head of the stream + buffer. If it doesn't verify, we look for the next potential + frame */ + + for(;;){ + long ret=ogg_sync_pageseek(oy,og); + if(ret>0){ + /* have a page */ + return(1); + } + if(ret==0){ + /* need more data */ + return(0); + } + + /* head did not start a synced page... skipped some bytes */ + if(!oy->unsynced){ + oy->unsynced=1; + return(-1); + } + + /* loop. keep looking */ + + } +} + +/* add the incoming page to the stream state; we decompose the page + into packet segments here as well. */ + +int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){ + unsigned char *header=og->header; + unsigned char *body=og->body; + long bodysize=og->body_len; + int segptr=0; + + int version=ogg_page_version(og); + int continued=ogg_page_continued(og); + int bos=ogg_page_bos(og); + int eos=ogg_page_eos(og); + ogg_int64_t granulepos=ogg_page_granulepos(og); + int serialno=ogg_page_serialno(og); + long pageno=ogg_page_pageno(og); + int segments=header[26]; + + if(ogg_stream_check(os)) return -1; + + /* clean up 'returned data' */ + { + long lr=os->lacing_returned; + long br=os->body_returned; + + /* body data */ + if(br){ + os->body_fill-=br; + if(os->body_fill) + memmove(os->body_data,os->body_data+br,os->body_fill); + os->body_returned=0; + } + + if(lr){ + /* segment table */ + if(os->lacing_fill-lr){ + memmove(os->lacing_vals,os->lacing_vals+lr, + (os->lacing_fill-lr)*sizeof(*os->lacing_vals)); + memmove(os->granule_vals,os->granule_vals+lr, + (os->lacing_fill-lr)*sizeof(*os->granule_vals)); + } + os->lacing_fill-=lr; + os->lacing_packet-=lr; + os->lacing_returned=0; + } + } + + /* check the serial number */ + if(serialno!=os->serialno)return(-1); + if(version>0)return(-1); + + if(_os_lacing_expand(os,segments+1)) return -1; + + /* are we in sequence? */ + if(pageno!=os->pageno){ + int i; + + /* unroll previous partial packet (if any) */ + for(i=os->lacing_packet;ilacing_fill;i++) + os->body_fill-=os->lacing_vals[i]&0xff; + os->lacing_fill=os->lacing_packet; + + /* make a note of dropped data in segment table */ + if(os->pageno!=-1){ + os->lacing_vals[os->lacing_fill++]=0x400; + os->lacing_packet++; + } + } + + /* are we a 'continued packet' page? If so, we may need to skip + some segments */ + if(continued){ + if(os->lacing_fill<1 || + os->lacing_vals[os->lacing_fill-1]==0x400){ + bos=0; + for(;segptrbody_data+os->body_fill,body,bodysize); + os->body_fill+=bodysize; + } + + { + int saved=-1; + while(segptrlacing_vals[os->lacing_fill]=val; + os->granule_vals[os->lacing_fill]=-1; + + if(bos){ + os->lacing_vals[os->lacing_fill]|=0x100; + bos=0; + } + + if(val<255)saved=os->lacing_fill; + + os->lacing_fill++; + segptr++; + + if(val<255)os->lacing_packet=os->lacing_fill; + } + + /* set the granulepos on the last granuleval of the last full packet */ + if(saved!=-1){ + os->granule_vals[saved]=granulepos; + } + + } + + if(eos){ + os->e_o_s=1; + if(os->lacing_fill>0) + os->lacing_vals[os->lacing_fill-1]|=0x200; + } + + os->pageno=pageno+1; + + return(0); +} + +/* clear things to an initial state. Good to call, eg, before seeking */ +int ogg_sync_reset(ogg_sync_state *oy){ + if(ogg_sync_check(oy))return -1; + + oy->fill=0; + oy->returned=0; + oy->unsynced=0; + oy->headerbytes=0; + oy->bodybytes=0; + return(0); +} + +int ogg_stream_reset(ogg_stream_state *os){ + if(ogg_stream_check(os)) return -1; + + os->body_fill=0; + os->body_returned=0; + + os->lacing_fill=0; + os->lacing_packet=0; + os->lacing_returned=0; + + os->header_fill=0; + + os->e_o_s=0; + os->b_o_s=0; + os->pageno=-1; + os->packetno=0; + os->granulepos=0; + + return(0); +} + +int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno){ + if(ogg_stream_check(os)) return -1; + ogg_stream_reset(os); + os->serialno=serialno; + return(0); +} + +static int _packetout(ogg_stream_state *os,ogg_packet *op,int adv){ + + /* The last part of decode. We have the stream broken into packet + segments. Now we need to group them into packets (or return the + out of sync markers) */ + + int ptr=os->lacing_returned; + + if(os->lacing_packet<=ptr)return(0); + + if(os->lacing_vals[ptr]&0x400){ + /* we need to tell the codec there's a gap; it might need to + handle previous packet dependencies. */ + os->lacing_returned++; + os->packetno++; + return(-1); + } + + if(!op && !adv)return(1); /* just using peek as an inexpensive way + to ask if there's a whole packet + waiting */ + + /* Gather the whole packet. We'll have no holes or a partial packet */ + { + int size=os->lacing_vals[ptr]&0xff; + long bytes=size; + int eos=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */ + int bos=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */ + + while(size==255){ + int val=os->lacing_vals[++ptr]; + size=val&0xff; + if(val&0x200)eos=0x200; + bytes+=size; + } + + if(op){ + op->e_o_s=eos; + op->b_o_s=bos; + op->packet=os->body_data+os->body_returned; + op->packetno=os->packetno; + op->granulepos=os->granule_vals[ptr]; + op->bytes=bytes; + } + + if(adv){ + os->body_returned+=bytes; + os->lacing_returned=ptr+1; + os->packetno++; + } + } + return(1); +} + +int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){ + if(ogg_stream_check(os)) return 0; + return _packetout(os,op,1); +} + +int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op){ + if(ogg_stream_check(os)) return 0; + return _packetout(os,op,0); +} + +void ogg_packet_clear(ogg_packet *op) { + _ogg_free(op->packet); + memset(op, 0, sizeof(*op)); +} + +#ifdef _V_SELFTEST +#include + +ogg_stream_state os_en, os_de; +ogg_sync_state oy; + +void checkpacket(ogg_packet *op,long len, int no, long pos){ + long j; + static int sequence=0; + static int lastno=0; + + if(op->bytes!=len){ + fprintf(stderr,"incorrect packet length (%ld != %ld)!\n",op->bytes,len); + exit(1); + } + if(op->granulepos!=pos){ + fprintf(stderr,"incorrect packet granpos (%ld != %ld)!\n",(long)op->granulepos,pos); + exit(1); + } + + /* packet number just follows sequence/gap; adjust the input number + for that */ + if(no==0){ + sequence=0; + }else{ + sequence++; + if(no>lastno+1) + sequence++; + } + lastno=no; + if(op->packetno!=sequence){ + fprintf(stderr,"incorrect packet sequence %ld != %d\n", + (long)(op->packetno),sequence); + exit(1); + } + + /* Test data */ + for(j=0;jbytes;j++) + if(op->packet[j]!=((j+no)&0xff)){ + fprintf(stderr,"body data mismatch (1) at pos %ld: %x!=%lx!\n\n", + j,op->packet[j],(j+no)&0xff); + exit(1); + } +} + +void check_page(unsigned char *data,const int *header,ogg_page *og){ + long j; + /* Test data */ + for(j=0;jbody_len;j++) + if(og->body[j]!=data[j]){ + fprintf(stderr,"body data mismatch (2) at pos %ld: %x!=%x!\n\n", + j,data[j],og->body[j]); + exit(1); + } + + /* Test header */ + for(j=0;jheader_len;j++){ + if(og->header[j]!=header[j]){ + fprintf(stderr,"header content mismatch at pos %ld:\n",j); + for(j=0;jheader[j]); + fprintf(stderr,"\n"); + exit(1); + } + } + if(og->header_len!=header[26]+27){ + fprintf(stderr,"header length incorrect! (%ld!=%d)\n", + og->header_len,header[26]+27); + exit(1); + } +} + +void print_header(ogg_page *og){ + int j; + fprintf(stderr,"\nHEADER:\n"); + fprintf(stderr," capture: %c %c %c %c version: %d flags: %x\n", + og->header[0],og->header[1],og->header[2],og->header[3], + (int)og->header[4],(int)og->header[5]); + + fprintf(stderr," granulepos: %d serialno: %d pageno: %ld\n", + (og->header[9]<<24)|(og->header[8]<<16)| + (og->header[7]<<8)|og->header[6], + (og->header[17]<<24)|(og->header[16]<<16)| + (og->header[15]<<8)|og->header[14], + ((long)(og->header[21])<<24)|(og->header[20]<<16)| + (og->header[19]<<8)|og->header[18]); + + fprintf(stderr," checksum: %02x:%02x:%02x:%02x\n segments: %d (", + (int)og->header[22],(int)og->header[23], + (int)og->header[24],(int)og->header[25], + (int)og->header[26]); + + for(j=27;jheader_len;j++) + fprintf(stderr,"%d ",(int)og->header[j]); + fprintf(stderr,")\n\n"); +} + +void copy_page(ogg_page *og){ + unsigned char *temp=_ogg_malloc(og->header_len); + memcpy(temp,og->header,og->header_len); + og->header=temp; + + temp=_ogg_malloc(og->body_len); + memcpy(temp,og->body,og->body_len); + og->body=temp; +} + +void free_page(ogg_page *og){ + _ogg_free (og->header); + _ogg_free (og->body); +} + +void error(void){ + fprintf(stderr,"error!\n"); + exit(1); +} + +/* 17 only */ +const int head1_0[] = {0x4f,0x67,0x67,0x53,0,0x06, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0x15,0xed,0xec,0x91, + 1, + 17}; + +/* 17, 254, 255, 256, 500, 510, 600 byte, pad */ +const int head1_1[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0x59,0x10,0x6c,0x2c, + 1, + 17}; +const int head2_1[] = {0x4f,0x67,0x67,0x53,0,0x04, + 0x07,0x18,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0x89,0x33,0x85,0xce, + 13, + 254,255,0,255,1,255,245,255,255,0, + 255,255,90}; + +/* nil packets; beginning,middle,end */ +const int head1_2[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0xff,0x7b,0x23,0x17, + 1, + 0}; +const int head2_2[] = {0x4f,0x67,0x67,0x53,0,0x04, + 0x07,0x28,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0x5c,0x3f,0x66,0xcb, + 17, + 17,254,255,0,0,255,1,0,255,245,255,255,0, + 255,255,90,0}; + +/* large initial packet */ +const int head1_3[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0x01,0x27,0x31,0xaa, + 18, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,10}; + +const int head2_3[] = {0x4f,0x67,0x67,0x53,0,0x04, + 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0x7f,0x4e,0x8a,0xd2, + 4, + 255,4,255,0}; + + +/* continuing packet test */ +const int head1_4[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0xff,0x7b,0x23,0x17, + 1, + 0}; + +const int head2_4[] = {0x4f,0x67,0x67,0x53,0,0x00, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0xf8,0x3c,0x19,0x79, + 255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255}; + +const int head3_4[] = {0x4f,0x67,0x67,0x53,0,0x05, + 0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,2,0,0,0, + 0x38,0xe6,0xb6,0x28, + 6, + 255,220,255,4,255,0}; + + +/* spill expansion test */ +const int head1_4b[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0xff,0x7b,0x23,0x17, + 1, + 0}; + +const int head2_4b[] = {0x4f,0x67,0x67,0x53,0,0x00, + 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0xce,0x8f,0x17,0x1a, + 23, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,10,255,4,255,0,0}; + + +const int head3_4b[] = {0x4f,0x67,0x67,0x53,0,0x04, + 0x07,0x14,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,2,0,0,0, + 0x9b,0xb2,0x50,0xa1, + 1, + 0}; + +/* page with the 255 segment limit */ +const int head1_5[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0xff,0x7b,0x23,0x17, + 1, + 0}; + +const int head2_5[] = {0x4f,0x67,0x67,0x53,0,0x00, + 0x07,0xfc,0x03,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0xed,0x2a,0x2e,0xa7, + 255, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10}; + +const int head3_5[] = {0x4f,0x67,0x67,0x53,0,0x04, + 0x07,0x00,0x04,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,2,0,0,0, + 0x6c,0x3b,0x82,0x3d, + 1, + 50}; + + +/* packet that overspans over an entire page */ +const int head1_6[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0xff,0x7b,0x23,0x17, + 1, + 0}; + +const int head2_6[] = {0x4f,0x67,0x67,0x53,0,0x00, + 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0x68,0x22,0x7c,0x3d, + 255, + 100, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255}; + +const int head3_6[] = {0x4f,0x67,0x67,0x53,0,0x01, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0x01,0x02,0x03,0x04,2,0,0,0, + 0xf4,0x87,0xba,0xf3, + 255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255}; + +const int head4_6[] = {0x4f,0x67,0x67,0x53,0,0x05, + 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,3,0,0,0, + 0xf7,0x2f,0x6c,0x60, + 5, + 254,255,4,255,0}; + +/* packet that overspans over an entire page */ +const int head1_7[] = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0xff,0x7b,0x23,0x17, + 1, + 0}; + +const int head2_7[] = {0x4f,0x67,0x67,0x53,0,0x00, + 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0x68,0x22,0x7c,0x3d, + 255, + 100, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255}; + +const int head3_7[] = {0x4f,0x67,0x67,0x53,0,0x05, + 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,2,0,0,0, + 0xd4,0xe0,0x60,0xe5, + 1, + 0}; + +void test_pack(const int *pl, const int **headers, int byteskip, + int pageskip, int packetskip){ + unsigned char *data=_ogg_malloc(1024*1024); /* for scripted test cases only */ + long inptr=0; + long outptr=0; + long deptr=0; + long depacket=0; + long granule_pos=7,pageno=0; + int i,j,packets,pageout=pageskip; + int eosflag=0; + int bosflag=0; + + int byteskipcount=0; + + ogg_stream_reset(&os_en); + ogg_stream_reset(&os_de); + ogg_sync_reset(&oy); + + for(packets=0;packetsbyteskip){ + memcpy(next,og.header,byteskipcount-byteskip); + next+=byteskipcount-byteskip; + byteskipcount=byteskip; + } + + byteskipcount+=og.body_len; + if(byteskipcount>byteskip){ + memcpy(next,og.body,byteskipcount-byteskip); + next+=byteskipcount-byteskip; + byteskipcount=byteskip; + } + + ogg_sync_wrote(&oy,next-buf); + + while(1){ + int ret=ogg_sync_pageout(&oy,&og_de); + if(ret==0)break; + if(ret<0)continue; + /* got a page. Happy happy. Verify that it's good. */ + + fprintf(stderr,"(%d), ",pageout); + + check_page(data+deptr,headers[pageout],&og_de); + deptr+=og_de.body_len; + pageout++; + + /* submit it to deconstitution */ + ogg_stream_pagein(&os_de,&og_de); + + /* packets out? */ + while(ogg_stream_packetpeek(&os_de,&op_de2)>0){ + ogg_stream_packetpeek(&os_de,NULL); + ogg_stream_packetout(&os_de,&op_de); /* just catching them all */ + + /* verify peek and out match */ + if(memcmp(&op_de,&op_de2,sizeof(op_de))){ + fprintf(stderr,"packetout != packetpeek! pos=%ld\n", + depacket); + exit(1); + } + + /* verify the packet! */ + /* check data */ + if(memcmp(data+depacket,op_de.packet,op_de.bytes)){ + fprintf(stderr,"packet data mismatch in decode! pos=%ld\n", + depacket); + exit(1); + } + /* check bos flag */ + if(bosflag==0 && op_de.b_o_s==0){ + fprintf(stderr,"b_o_s flag not set on packet!\n"); + exit(1); + } + if(bosflag && op_de.b_o_s){ + fprintf(stderr,"b_o_s flag incorrectly set on packet!\n"); + exit(1); + } + bosflag=1; + depacket+=op_de.bytes; + + /* check eos flag */ + if(eosflag){ + fprintf(stderr,"Multiple decoded packets with eos flag!\n"); + exit(1); + } + + if(op_de.e_o_s)eosflag=1; + + /* check granulepos flag */ + if(op_de.granulepos!=-1){ + fprintf(stderr," granule:%ld ",(long)op_de.granulepos); + } + } + } + } + } + } + } + _ogg_free(data); + if(headers[pageno]!=NULL){ + fprintf(stderr,"did not write last page!\n"); + exit(1); + } + if(headers[pageout]!=NULL){ + fprintf(stderr,"did not decode last page!\n"); + exit(1); + } + if(inptr!=outptr){ + fprintf(stderr,"encoded page data incomplete!\n"); + exit(1); + } + if(inptr!=deptr){ + fprintf(stderr,"decoded page data incomplete!\n"); + exit(1); + } + if(inptr!=depacket){ + fprintf(stderr,"decoded packet data incomplete!\n"); + exit(1); + } + if(!eosflag){ + fprintf(stderr,"Never got a packet with EOS set!\n"); + exit(1); + } + fprintf(stderr,"ok.\n"); +} + +int main(void){ + + ogg_stream_init(&os_en,0x04030201); + ogg_stream_init(&os_de,0x04030201); + ogg_sync_init(&oy); + + /* Exercise each code path in the framing code. Also verify that + the checksums are working. */ + + { + /* 17 only */ + const int packets[]={17, -1}; + const int *headret[]={head1_0,NULL}; + + fprintf(stderr,"testing single page encoding... "); + test_pack(packets,headret,0,0,0); + } + + { + /* 17, 254, 255, 256, 500, 510, 600 byte, pad */ + const int packets[]={17, 254, 255, 256, 500, 510, 600, -1}; + const int *headret[]={head1_1,head2_1,NULL}; + + fprintf(stderr,"testing basic page encoding... "); + test_pack(packets,headret,0,0,0); + } + + { + /* nil packets; beginning,middle,end */ + const int packets[]={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1}; + const int *headret[]={head1_2,head2_2,NULL}; + + fprintf(stderr,"testing basic nil packets... "); + test_pack(packets,headret,0,0,0); + } + + { + /* large initial packet */ + const int packets[]={4345,259,255,-1}; + const int *headret[]={head1_3,head2_3,NULL}; + + fprintf(stderr,"testing initial-packet lacing > 4k... "); + test_pack(packets,headret,0,0,0); + } + + { + /* continuing packet test; with page spill expansion, we have to + overflow the lacing table. */ + const int packets[]={0,65500,259,255,-1}; + const int *headret[]={head1_4,head2_4,head3_4,NULL}; + + fprintf(stderr,"testing single packet page span... "); + test_pack(packets,headret,0,0,0); + } + + { + /* spill expand packet test */ + const int packets[]={0,4345,259,255,0,0,-1}; + const int *headret[]={head1_4b,head2_4b,head3_4b,NULL}; + + fprintf(stderr,"testing page spill expansion... "); + test_pack(packets,headret,0,0,0); + } + + /* page with the 255 segment limit */ + { + + const int packets[]={0,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,50,-1}; + const int *headret[]={head1_5,head2_5,head3_5,NULL}; + + fprintf(stderr,"testing max packet segments... "); + test_pack(packets,headret,0,0,0); + } + + { + /* packet that overspans over an entire page */ + const int packets[]={0,100,130049,259,255,-1}; + const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL}; + + fprintf(stderr,"testing very large packets... "); + test_pack(packets,headret,0,0,0); + } + + { + /* test for the libogg 1.1.1 resync in large continuation bug + found by Josh Coalson) */ + const int packets[]={0,100,130049,259,255,-1}; + const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL}; + + fprintf(stderr,"testing continuation resync in very large packets... "); + test_pack(packets,headret,100,2,3); + } + + { + /* term only page. why not? */ + const int packets[]={0,100,64770,-1}; + const int *headret[]={head1_7,head2_7,head3_7,NULL}; + + fprintf(stderr,"testing zero data page (1 nil packet)... "); + test_pack(packets,headret,0,0,0); + } + + + + { + /* build a bunch of pages for testing */ + unsigned char *data=_ogg_malloc(1024*1024); + int pl[]={0, 1,1,98,4079, 1,1,2954,2057, 76,34,912,0,234,1000,1000, 1000,300,-1}; + int inptr=0,i,j; + ogg_page og[5]; + + ogg_stream_reset(&os_en); + + for(i=0;pl[i]!=-1;i++){ + ogg_packet op; + int len=pl[i]; + + op.packet=data+inptr; + op.bytes=len; + op.e_o_s=(pl[i+1]<0?1:0); + op.granulepos=(i+1)*1000; + + for(j=0;j0)error(); + + /* Test fractional page inputs: incomplete fixed header */ + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+3, + 20); + ogg_sync_wrote(&oy,20); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + /* Test fractional page inputs: incomplete header */ + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+23, + 5); + ogg_sync_wrote(&oy,5); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + /* Test fractional page inputs: incomplete body */ + + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+28, + og[1].header_len-28); + ogg_sync_wrote(&oy,og[1].header_len-28); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,1000); + ogg_sync_wrote(&oy,1000); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body+1000, + og[1].body_len-1000); + ogg_sync_wrote(&oy,og[1].body_len-1000); + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + + fprintf(stderr,"ok.\n"); + } + + /* Test fractional page inputs: page + incomplete capture */ + { + ogg_page og_de; + fprintf(stderr,"Testing sync on 1+partial inputs... "); + ogg_sync_reset(&oy); + + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, + og[1].header_len); + ogg_sync_wrote(&oy,og[1].header_len); + + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, + og[1].body_len); + ogg_sync_wrote(&oy,og[1].body_len); + + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, + 20); + ogg_sync_wrote(&oy,20); + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+20, + og[1].header_len-20); + ogg_sync_wrote(&oy,og[1].header_len-20); + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, + og[1].body_len); + ogg_sync_wrote(&oy,og[1].body_len); + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + + fprintf(stderr,"ok.\n"); + } + + /* Test recapture: garbage + page */ + { + ogg_page og_de; + fprintf(stderr,"Testing search for capture... "); + ogg_sync_reset(&oy); + + /* 'garbage' */ + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, + og[1].body_len); + ogg_sync_wrote(&oy,og[1].body_len); + + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, + og[1].header_len); + ogg_sync_wrote(&oy,og[1].header_len); + + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, + og[1].body_len); + ogg_sync_wrote(&oy,og[1].body_len); + + memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header, + 20); + ogg_sync_wrote(&oy,20); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header+20, + og[2].header_len-20); + ogg_sync_wrote(&oy,og[2].header_len-20); + memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body, + og[2].body_len); + ogg_sync_wrote(&oy,og[2].body_len); + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + + fprintf(stderr,"ok.\n"); + } + + /* Test recapture: page + garbage + page */ + { + ogg_page og_de; + fprintf(stderr,"Testing recapture... "); + ogg_sync_reset(&oy); + + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, + og[1].header_len); + ogg_sync_wrote(&oy,og[1].header_len); + + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, + og[1].body_len); + ogg_sync_wrote(&oy,og[1].body_len); + + memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header, + og[2].header_len); + ogg_sync_wrote(&oy,og[2].header_len); + + memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header, + og[2].header_len); + ogg_sync_wrote(&oy,og[2].header_len); + + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + + memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body, + og[2].body_len-5); + ogg_sync_wrote(&oy,og[2].body_len-5); + + memcpy(ogg_sync_buffer(&oy,og[3].header_len),og[3].header, + og[3].header_len); + ogg_sync_wrote(&oy,og[3].header_len); + + memcpy(ogg_sync_buffer(&oy,og[3].body_len),og[3].body, + og[3].body_len); + ogg_sync_wrote(&oy,og[3].body_len); + + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + + fprintf(stderr,"ok.\n"); + } + + /* Free page data that was previously copied */ + { + for(i=0;i<5;i++){ + free_page(&og[i]); + } + } + } + + return(0); +} + +#endif diff --git a/code/libs/macosx/libSDL-1.2.0.dylib b/code/libs/macosx/libSDL-1.2.0.dylib index e3ea15fa50f4dcab80044af0df09e391263178ab..686a5405a6f9d1ec0b5469f2a674f455a871434a 100755 GIT binary patch delta 56524 zcmZ^s30PIt*TxT5gp1<^hXko`792pc60^dz(lRBr67yeJT4JV@mSPs9W~gN3z$;3I zV}MvV0;WdgJS3*6m?oJ6;1HUnDAo6_a~5*F@bx_MTkqO?uf6tghI{VNncdOT_C_Z* z4sz>a7)Bj8!|)_)7+wK};q_ap`1sHAHE__^Xxf^vM;hCDbeS91xUC~>#KaM=zB7K< zE2Bre96fCONc`Kz>#hz>*`!I(=Sx3+JhX}T6E6*!>zlE;KYcdw8y-L95YHI)x+e_d z&%x`;8$VfN?w5XD=Jxa(KKB>Dk#iR{9Xj{Xrh}(mZ~F1|rf&RasoB&k=fTU#&>I7TkO@>Xg`f6XFOW88dBNW_~@#g-4n*DYY};d0rQY3 z$VZ;w7nBMvBH*k?3$L3Rxf}s!Jp5X}<5?N@ox7`sZ5d)1@4SqJvy3nXn+4Nwk%8P& z;5f&$zIJNAw`%)VrH1itT?{_QhD{MK=!_h}(6COodQ$}}eoQhOxrVb(mXDX0A= zCbLn8p&fFszpfFIW|xj7E65NAr5U8FgZm|mh10j%@;w!f{5qb^JdLNr===um7uo+ltE_J#B3a*~Un+}E zVz?Atwu+vOGn>^n21K*0+;R?xM&VnY&FUKi6AdG#uH_t4<{r;6xtM#<@)Cy` zj6sCg!&Z%mFf)CRhbbEP<5X~hOlZL8eZnk`Vn1;R)?Kh{84o| zUS*3(A&9%o?jJ%HQMb3%y|kM&7#A6&)40~|R2~x+&^67nCvwRrC0TY%ciJngt+19g zCv8C3AMATaW#5xdSM58R1ADI};{RaZ_aR3Rh9W_KG$|z_(OWPY69p5ICYX+6f(5W& zA(o@7U=2nJzQqE;UhKNU?vLq4&0;raG&^qE_x@CSv|&uP!Ex22dF#pbDpQ@@QBw`) zn042FKy&ij7<`q{rz2jFgdD*#6bZgYlRt?(^cMVxiGq_z6BOgvpB^n5UDwH)Y#8sm zX==x;^T+!>mEFG|QnmZINVXY=@N0}V9dUwWWC=1*c#Y?yJRMTB#{1DJ-o>i%J}fni z4}#J6FGhGAlLh}nreG{i2&SOU-^6@$7o=mfAQvfu-Pk8MhH}A0w7vXrlX2Aovc-^B#pNiAR3B!mTps9|h{fgQXX^&Hz(-RwO*`I=@q~72G)1q=B;(At7HJ?@ElggOtB7_K5BT}#xiGl;j6BMFUP>O(? z9P5WQ5pJ>x;%?I29$A7OC=?8YURXJ{|6?7z7( zAFe?(L$u1P%>BcYn)|cH?LE1SRj1sGoLlU)BZ>qMqe(dtj^2VdFj4RU(gaC3CRhpk zKOQZf-KyPPWsC!A^D;T*7q$PUeO~PwwEtH7reRF2sdhPSZ?*rmHr~{`D|4P2S~cg4 zIJTLD&Hpfycw7`D!T(?4OZ5Gh>$TCT{o$(ZR|gozw7Zb`FHdkm$R}DoSlMFQfT}IN z3SooAPzuVb(~o4k#9!4%{OK0%RSF`Cr$Y~hxL z?nH-goT3#}jkYt(Fh2IT&i^~JkaeC{#hu({AGcLsDI81XO13MN&Mua7SE_mG_1Vp} z`8dq-nRZ_Ucrb%u2p7DGI6(}u1XEEcm<@*~k&G};&lX-Q^b9%8+Dsp>sm%7{168xl zFEosJA7pxRVd7ihghc9sI7<4;a;9CTK!g;Q~W7E$z-~x2N3` zk+qrj3zccld{@&RXxu)RoJwTXZ;)1-$?U>0!ExB@5GCj;D96Y;oaR||vB2a#*d^`| z+z^DKZC#=l1`GNjUJ!vC!Eh7_#-d3*;zRVV$L;tTMiU(tRc1A7W0kDjnui$1tn22E zqAfRF&FZ_g3^R;`nwGPrd5a{@d^#JbGaq4BJeqmBwJM~uEqc}We5k`il|3a4uG&*z z9;+_0+6U$#uNF7CTTm&TD=cS_?tHg)sdRpAIoqYm-Cpy0?Kyi1xt6beqIHP4b&x!N zu$&#jG-StUI`b`O$7n>eb=_d8c+&C(Beou zE7O?$rl#?HWg3y3!`WFF)R4h#tTMZxgZXQ z1q|H75|tSiEsuwj412}U4G@HPqs)8X(X79vdW6`}=Okt#Thd_hT)A9I^y zAjD*2M4Ie~L_d~xMV{bklnS0hKvQBQ!UgXjPA~;of+Q3QGU4zi_9IMi5z+pPKGzee z{+`Wa=iXzTXD4MD#@r5S^VV$cW0pNd>=!J1rr4t`dyd#2TJ}P*Q(E)nX?U#QpSi0n zdnG+{H>ur)_HNw?k+hGPHhSFcc~7gem2*1xKb_OTx3`1swLHU^_b8^_&Gh-&=WZUt zFITphH(6UmRJIr|Ext968QXXs!gYBF+r}5t`J*}ut=DF@ck=194mjFc^BpeYJnLLz zd#BVoTx}Bq3}e2B)qFw#0?zZaVw(_6=Us5Wms2{w1G?PnS@Dw17FUX_a;Y;ljCBTK zo|KKS+J9tNrzP8T2g}~UH7T2BmBm}HHtXAFNV|EKb4Hl;64W*`gwExd7QhA@t+Ipw z7vEeq{eBF+qGaioCNlq_OlPX@KIxW*D%q}Spo11ZA zkKv+#r!@|le7vxmUGLwtFpd7thGg`7ICYtm?n#sFy%w${G+jus&C5NJY8;0yz88Ug8 zh8!aEY(5aPt>gSBufX^=mD^!GpGe3h%eIlTo4n21BO4>-Q3svb(%@&yna$Vw<}S{b zn&;4^Eu;KpmF482ur)7dx#5Pf&~Ev1D|Y6lFgkrL=cX`(y)E5s$*0r0H>7P|pgnEh z7Sj1JS_X2ep2i@-P)sAd-nN?W!-2ZF5|7GUy^r>993eIwR@qW;H*|X<_em4>R{gebk2oH9VWwxBVPV zU!>*xIa&{~BMv&pVR$2(o?cVxRv%p)q!KUWM*?3%ROVYRy!py$$SVRY)CuZ1CtyU^42S0SBeFesS8{=~Fk z4)gOmR>PaTV`KIWY`3xu6RW?$MyO_o2MTiSw7XKnEgoou~9~7Ew3r8o>k0Pv-=R>UqRz_M}@u>Jkqv9~E z;U8%ji`OBw6C>?KzTo$y&is1|A)OiKiw1}^*$#;&dm>MYUqq>390KkmW+7a#3~_>Q zkR>>TLc#BFbRqsiSQo}iwIkYO6Qr8#fP9lZlJ4hgr-9Z~Waw+B)X2*0Q>W-WIAtHk zsZ8C8(f6~10;C8oV4vV0l;6+pmUyH61HzUVYVrXjnCy+s53t%WTolB>|3P97`U+NK zvfw*p3JP#Sa1nL7GSE^tbT`=;qfNF)ipgHs*Ok>GP%d~A?L&zv7#hkK2+4XG%Q1|l z8M@fKq%F-=do=BXYU{JFrN38>d|53W`OwOB3lA}jWzXWG^zthFyK$u_IJNk^nik<~ z@jE7WV~cCZ?8dNC*PVwjA)6 z-dZmXbuN1N)%voPZuRvD=;7J4RcPg$eOYn2{GW0AIDIjnA-+Uv7-u3I`GVa^J-F(> zRJKd2sdN2OWxM||?X-S~?7;>vBT*2AJi&C73ephp7?Fc;!A`^pjv?zY&lV4#*L}N> zG4#1_N}*w-H&lNq?GVfUoL#0rp*H(We-VzJ+zR6>(@U>-Tg)lF3304?3WIyH(`$(D z$xWEyi5!!DC^8v>CcVVp6TMA7kBPlleH7AqaX(DLKBB|i%6>8`uDp@V$-3L95leHG zyR`zbhP6_$Omo$J>eCgC4WQ4u@YIM6uwJXz_%MXd0anEiLy#!TJcYqmy<+*ML|Or- zMAJ7xebMTRqtCh`)tC}z`aGs2(zgu5pWu~ftyTRa^Ua`U^=nL*M0Z-w>4vrSrc3|7 zsxQQh;WIsqzCY9__J0U@lCv@ik%9yy3R00LScg)b{a6+&Yb)NEU;k&MN4d(9g%y?Efpc^58 z_OIy8;#LfALaNE`$T!(P=^5631tEfoh!k+91fL^M@D)m*;X$>zGTE=s zX|k_YCi{J~VPpj(ydOKw3P)T&wtN>^f`up)YDCI75N781&flx z`FAfu1eXyR&MIrYkr>XG4Qo48X0W!OX7Ea727AK|W9?@sm8L5Y@GQY2_*pK)e!Y%x z8P@7sN2@2&zK8@Cce-8~cU=>W`+8;E{fxWrMQf=|do&6q_$P1-Ao$u}unN(FO-L0S zM84p3(m?*@ZNos0V|`sjnrw6i@81ZCV6=_yh&0&{i6&bk&tzAWntU7q zL!@2=!iTWgNW=-oBTEp6LO}u?FA|FpCg58q0(L53r-GA7L;3dtLIl?lIg~N8-H>Rq z4)RR;q10qs1pH6RA4Isx#}Q}pd1U>M&7)8#mqsWT~KQBSp>YsYQqsOh(?^? zePjs|P$-xW$Lquw2orD<3HBpZ@C)(<=aWYA@1F=6$-cgEL!?O`B%0(VGRZzoauY>K zy%!K3#b)m!PB0x=0-kjQ>);qg>_M2|9HK|@dCD!l&p2ino89%~FqyWm+Hth+Q+pb1 zeV21}Jng~iPoO@#v(n}gwRu+B z{Eym9XiI&ynb4Ms_W_vDmiyGtgtk1cHWS)1NNpyxML)rDlL>7Zqy7c7-)|jjet70) z3WdH=c{7#vYOS=Kc8=OupE0Qjxtb$(7ZFxn$bJJ#b?FNzo~=uJC8?Y^{is&9qUUZeg&w0EdIn0A5MLuu@rMYMy|zR3OmLq(>gEO=TAuF-x@?HjaTRlA(_Tb51J_(78{cc-l% zdMLNk)&Z2)p{)ZbchJ@WlsBYpew-!N@F;IWaZrQ$)BauU0NQ`5-O@0&)lj=FZC|z9 z(|%Cx5ZX_w-G%n^YImjmirU?2>%J)uqa8a_3wlxLZZGdmJ6-*KX>V3LoVHGN`5@Xw z>K|+v+YPmc(srmFNxQk)!)fa|qkJT7J!inZ}+n-~x{oh1-Tu4Z9my8o zqW4?8ZtcZH!7-!>if~NuFYIsg^0&i*t|psfq{*&W@HXEJ+R4sLsWR%DH$rfK7N4HjcyIfPBH8r1AV)h!6qqPR8>k!miqt zQ@X32h9N4Zv8Zj(0iFyS))+vIU~w zWoNsc9#8D9$l0m0fpLbhdkOO2Wr#IN6ZrQ#ga{5HQg9xLf}6;j!03DGqSRz_1WXit zKf+Bui8zxH$ePINZ=p~S4@V4C8KZYsn9hx+WeN04%U>FA8-D*Mm5J`p(nO<-+lfvO zXPdt;^aFxg!>X1iO4mpeFf$b>#keU1h#}uLnVS*cop2BhF*G8&I zzT0UsIBBZ5A4Z7DXAn7+hgkm5%6{_S*M8op>}N}yVdUo_Zz?0_qf~GT0n>;p2%pA) z2WukEWK(3B?2JN_Pr&h!XY+0chgx&8%5E43^&GjX3GH`v?1yPv*E>)5W3;XNBv1Df z*4iITs!Z_U)~X5a7nvV1m!Eub!enREnJ&5yx|@6zqo*_FSfmJmeS)u0F4&It z9}~Y}sNi2De9V@I{IJ<%M_e@d1pMR0|04Rvdp3XSP{q--%`gsG_oJTfg|w}Upr`v8 z+7+WJqHSFdJ>4(To~t7-rM(n6@jPcZeOl|#aUJC7%2oI+z%ULsO`5?B4hJK|` zXR+C=qy+w5ju1gEA_e(K6r4t$;6IcmFwhY{1biZFi*S>VA?_3Ifg?k74{#Vq^f+JD zlJ*Ss^Y}e7PiKY4&XGlG>sJJhWLEBhBl%UPr>31Vd9*S7XS464tO$IbHfX9{pcsoTG6X=gr>(dUwIJ(_DSJ6&d#xQjv={jt=>hOsxeI9l4=sSm& zpYloS4XdagpQOtB#Wm}P8OAZ|{a@NhWc|AJ3+b~?l{M=lmLClCtm$yj*9>PqWy;6y zN5e#(PLK7rf;9+7*b4UDFq(A+TfTuracjRMSo9*rfrFVN*PF4-Ck7vy1{;1IS6&f%Ki23pQxUIjHVXpU#|S_OJq zTQ$f!Bnw(pPGdpes?*pe)i4TXBX15veU4JWRs_r?P9j|JFXHAh{&Ai%Om;z`$!Fl0 zC;lje&11D0h!(6ss$d)P1%*lTS>+cugqZY4q{&bunjDNgljBf2pS3?lKoYSE;euU= z6P!g>5_iK1o9;f2=EOZ}kEE@i+gQaLsuR|049}Vkt)ZV7Q91Mz6>klWF)FS^HHUL~ zPHaIK*v$b%3ks1cxQ=`<@sstF76_Un#AH`QntTR{CSOIKN#?(Rt)?O%nV5@k0pIBq ztVfn$8wv$S;8;lffv|-P{HrITP2P)ClMf=_WZ$GkQv5nXOvWN|5nIhcq96@m%NKf1Ieqx#R1e)APII&% zk!_|RA%#7DhRuQuToi1B|K~&@`U?KVqR~M7ebKTQu5# zA)Jb#U$E1;ND!o9v)~(C6dZ2&+b?oU5g zwR`!f%IQT&O=aYj$QNu*TEf2v5h6H+NWq^-T*71YcTcOQ)w|5-oqzYPjQ;zBRim%Z zGmPISS*HxsPK13a!+nRYf+H9yIEMv-YuL4vgFoYj8zvi}?K0jwoM~R!$C;<9_L0Md zKJzK!moY>tas+EpB-n~3%lU@K9;fzKsCSO9H$vBiswNwOr zMdTt}Z~$?F3&{G4Z7=fH$mG3nd@cH6gqeI1(I#V%`ZcRBK)xU+DT{v(BSgSg$XRT1 zsSy%Qc0`^@zGaZbDZlhTo$@ei$}f$s9Ok9jRfl;c&oC|>z|b`e{WB5-C$U-ZCoZmG zN0$xwuNBrsUy}itY_bzFO?Jl#lTV_~I;r<8x|(I!7cipkHgZ=Gk0|1HuNGKGe5 zIYV>pMcevNzh}+fw5_M7o;CZ@wjSAd)(odzsPzZYE>?Rm?Z4F?YK{31r&I19ZK{mf z!w4{pKi)*bdZzowhuCZqxVWC9&Vc_0Vk`Oz4r8+5JTf=%u>YrWDoa~v*m1XajE61N zFiJJ#usNF%uGGgxlL7G0 z5#0%WbNDpqN)H`uq+wj?qc#(}GC*zKTU@aox_Z{+&Ha^8>W`*vJ!ti;Ii9w@0;)NY zw)O1Hv*u*lE46+c?Oe5|$tZ`r@h>jrc=~kMSveC|E>xX~x;%EShL~pwkGgvM=uyu> zr}gC%+ScdnJnALV+0Uw3FVXxsUpXE?FPmxj!OS4?VapiPWDS~M(ylFH$A_s5nEf6 zkBXzO!cK6qlb!4gCwq&NeaOi^=VX^v+N11Fw(o7bpE0V{ZDEYM-^uRbWDjz(Uw5*j zo$M*J@#KG=>u!(fjS`O8T0i5BE0y->22S>aPWDjFqt+k&wv&H`lfATZu1BXk**UjU z2{J}=Csa)4=%Y^d87KQ1?fJ{>!M+tW-+Z&O^v!o@Z@6Ip!dADIuFBX;Zbq$a)Uap! z*#3MnJG`;|>ZH2E$Br2j6WnXWxHra+jmDa}_QrViGkcS&{#ID^nSFUxe{00eu~!qP zHQLR!zjtT-Y{uW_cBfDJY?r-izCELwg4UQ0`y*8ww8mes=T+xFKf}idzB7G%@%Id$ z0CY;W|5#nMkcIXGRsC(yFu^Cjs=qb%C-~IMzOl%jT5Xb!WoBq+&C7=CLn!T=TL9Gg_Kz}oD?8sna_jx zWWD{F>RQ#_U=Md~#d!?GryK3#TpG~dCc8_vy^U)Fv;Tw~d#-E3X8-SgW1sI5$!ySl zv;9=Hk@{}6KUZy}f4}yLtR@mZ&GKo0vU`2Jvp@dM9^e}D;1Apb1>f5*-Ptso{(D{P z$`H|Sy^jNfW;bn!C$`)B-q}hH>(=;Vy-$PeBirr$UE5cbdSK|zDx2|kVfN%*_PcBR zKY=~6^Y_{p{r`bGZ1M5W?tj1if*aBg*xR~BIm@+6%=4)YN4|YVHHF#x^X=_?sw-&! zyM1+)ZqIV-*E?%paA$+;HD~$g?M@%)3(WR9Z=YCQ0RsMM+Bo~i$LuyY>@T+Wucj@+ zOYDcL^Jo3n)GIskf_+}Kf!kiPZ>y$NcEDwO?J5oC+M6S}hJWMiF@M;PR$IEEroT6~ zpXU1B+uPp8hAn^EC%c3-caOin7lQo!@6Ntl)2q4*X>+j37x~H1#k+p>UeFgCcW&%b-k+WIy3JrE&LtXzBE6FyOZE}8}5&@s-ju^+J&FMJi;g>yqtm8AcZuCDB-fP6@VKL8* z86P#;Y~$%4_Hw_0eaF5oD&JD!W2455?=xn=h*zxuo_=`tEyvy6*}mV12^CZ7d0X}z zJz|(Sb*18yG4!}&L2l5E{F(M9`2H=&3vF2Ext>pth#Bui)qX$J< z)0k@a%MN?nvBB2ZH|*uHuZ(*2Z& zp5X{?wv3TlH)NBCj>_&k8bA#PX9j%MEaOfjFyO*$xgZ; zSMWH>1OpK|ix`HOSq}L*o^+y93?EK7NB)$$x}iDztjGu9mB1jy=p*!;A%v;66ocB#RPvx3wtORp+U; z$5`cI_gdwCqPZvmx+p=aBQfkVN1IL$Q99@J0=0~&N>1|a0{)kbh-4;{hGao53Ix00 zyO8)95rWf57F$`KWC?ZB7(5-^CSyDcRXVA zeh#8N z!8L>~WxuuF$E2kkr$2Hj`D<)tf}RLnMhroWAPTvHi6|2!AauDSI4b3RYjq~->ZFTi z;;FhCxvJAt?@^tn`iSbnb=GR0Rb8t3PtlFJvGH9BH>Sr2cTPl0>gpyU`V(s+UPs^x z9-)(5nl033bzC+>sWv->^c5WA6%-RT_gDn24PX1Jc+@jdzoe#Q*JCF~ab z1Fuz%;9-rp$t3Mbnnp|2lU3iR`UBOEs*Y3rwCX9UhpL{YdL)wBO{ej6I}az3y1LrXL?u^xry4qOjR;)1yUF`_=`jFLRr14m?iW5BB zB}%$Rsq32V1 zTAzXM2I4P75H{l@EZo3;9UtNN21iF*^N&z#qoZS|4jM#=|NpxK8ZW59;cyCE~C!J48d~j7OaEUCSn`<2zWdR&SJOVFL-^!Yq#ge z)-Frc{ohb^n(Ah%vs8Cdy)p^z~9Z2bX+>E8JF71$gR@&S@-!K{8J8mWpBSOHd zwcsWS2%94wep@(0_r_xg>DB?sTO7f$-T4lWoX@7|`K-TcekgpCG^=@uo{uhPx?-^w>iUl(f_yh3;qJD7n@4VV2)*g-J zI@-uKR;;?SQ1Sy;?ygw~+D0~;g;BzGvyegZR;zd$qd$hg?L>b>35FtF@CJ$n?;~&r z@fo6aID)+w&*B=?VwQo{8m>Y*-JLhl?Ys&{sb!1~msKd`TTb$yUjl0FWF9RO@RYD) z0%nr@wWr-X+1X?8+C}t7AHh(}5JX|O;9Yp_CO$$R0Wf2?BiMHp-(Zxq;xw%ds`IdB zhoepB?F#baIe{Olwd8=1^ZAe zIETP}#D9n)Y)xh(W1oy}HcCjjRoKtc7ZJ6eC)07W?@TI@T9Rtul9XeomDC{=OY8Fp z{E@hYD8g3%Q)K+eF7EvlCBpkZMbH6u^)#Xmu+}g>%_SzFSnw$V^ND0c2{Mr`*ob1m zZUi1Ajvz|#JJJQbDh~Ns{#>1SpUKKjn(h(KaccZxy?vJ!B5<6+4MUv=Rs9afA_oJ5fja=HtJz};03}uHn8>t9AOl(4oU^j9F$519HM(EF+DPs;M z{mh=c=U|ht%^chmJ~#*6j+i?j<_K#)k6giPC=$9zt8p6b6;7piuj%lJGQ7wO5hf$CCApeKLyRC1xq@XV6Rbn%31Ty11Y9k_&nOd|L+DB3Z^RHbuld+? zl8e-IK5h!z&qudk`6BGm`PLL&!?0t#{dZD-dADq#a zDL5|do&vv8&g>vWl(N=nBnzgYKrj!!SBRB}5Nt%UU^fZ`zryz_aTO6)d5h%!Ic8qv zEt2==cjkW|b#?hC){vhI;m^yXSfcRW=ucuXq68a}F4%)&!C3@eBmPAcVQah?8P}M1 z@M4q*A6tx|zs&rj{$j1ykuHcqu^kQZW z3zP`Eeu1DHj*fv(ePQj0Fx>$|RrgXoUUhFYo5?fFR7&R^kwIPU@atK_zk-4r?7c=R z{K|N|-j#Z1^M|RWxu47GXKC}PNG{_T=Al5a0=_qiZxA8KN3!573Iu#icZ(g>UxFdG zIJ|%*SSakY1jmJsFM(e_E~o+M*YJ+nlD9$@PVZ$5%yh*pnuut%ZU1yeZGx!!AB_mmt8MfYIPlFcHQ|a zO6RVBrmn8*u*O!`{>w1wKlTx_44Z^cEW=IG?Zx?_-t20A4F67_pUb}s=a=#C8icxe z2YYQ_X7!qC^;$sb+^gI2>U+&^V)gpua_n*QeuPhuylf2m2Kv~%`*(Vet(>E*&?x>c ziyGi(MY)XK()vGm)$ryeZ3UjH;m!N}6__dPy#jkk>BF71Mxu{kB4)UI2Sb)xE9qIte6x6XGBSKc|2Zq%|0OM zxj9G|tU$3K2Z0{Menbg)dn))F#e}Wamk9Fo?r8J-5<|#N_kDS1heN5Q!+Tsh3<$G2 zT#j5%MmvNu!EXq)o3UdETkSM#vU38Pr{ShBG!5On$fwdUiR5dOTrbv+MwwtLLTeH8 z5hF-Lu3#g|2=5(f*2N_MajVxO=u?{=Je!W0wHfF&?55;T+IrO?rlXI5uWkf9z%A;CNjo*eL^k^~lFEFr=P$$36oyxG1c7 z1~tZt=A!56qJ1E`4$FhBi`ti}141mlPc$!bdDbRBPU*ZojaAjpao%VvyT?}{s6Nwq zeicTMd@+|^pJRCs#R8tl9YhkM1YaXvunWb4UlHg{TtgILvu7g1n{j+IQ6db=M34{p za3)3x!&y#pI*WbSY7zn)5VH^^NJe@CZ}}*40nz!J%sYp0mRhz+GnZ|W_@Om~j;qnF zA-m|e8k0!An#yg+pleVj$VX@+;u>NIo8v2NYQ(w^e1)4NUpj_1W+^v@U^{XJMJOX| zUSFfzUEUpswg1{$f!;df&!~=8JxcWg)$>*7sot!*NcAbz{AEXT#s9_byS#%twa>b9 z*w0YQumfC%T^Mf-n^(goOqN$eK@QTJcn1gWVo=+_lE)Gu)-m{FzptLs%|*yF$N#C|`D-fOJ7JiUk=6^doW+CCEp*;5QTtcoAvJ zsjagXqndIV{MI5v7`PTC!ftC3f~0`Df~Axe;rbU_Y^1v?RV z4{;1pf+C~~cp@TfHP<2NUWRM14x@xk*C9jLd>u-Jomd_~KEiV0(<~PbVmZl88`zA| z#vw{D6X}94P%K!7z~;mch!SwLf^#Sq{Dr_4?7qf&jB3Gf4b~$=*lImWgb%JqP)o8G z%Y}nkPV%m&xFuVULtra{r(MA;qzgVru^E3;unqAyq6nL@0U2!= zy!Hl^2z@sos4dxM14aoSV7agt%Z1OeJkXr-s6a-UfOG+`nzntwD0`DVu;v;MxImoz=eKgBKiSWK0 z1a%?9b1+KyD$7a!&jyOSu+?M)-cRtvCzywH!D18(xRo9t_904e9O(jXCBan$J}9f1 zi%}0Us&_6jgspN>A`H$&P**aP<-#XfE*#8qlDB|?p^P#EQ39TC1*=gk*nz-q#7RU6 z%8=g8J20uI$Cuf)#FtURn4FMG*5bCR8Lm@k?J^0 z#~NR#W13c2FPb+m#t&A2ovQ7s3sgH)pI6;Pb(!h_)n4CN@!G0xraHvbv4(MS)pI-}qh~6Scxms^e6bs*YFfvDq3? zqUy$~7pQKnI#qR7)oH5xsLrC6{*A%v$k7TTRp+Umpn8|;IMw;8<5eG1y+C!L>XoXC zRIgWE`h%z0zp+&vH?+b*)y6h!51dkMSAAWzLv`IP){Hb!-CT8m>ibl;Roz2%$hKIk zgTd4+;QaxDpSE?gbZ&p20^+DCqvFi9u9TQbwRvoAMmg;!b z_N}@HR5w+TBcb!?V8UQ$Pn>Ni#Ash*^Im+FsH=d1oq^)c0{stZ+r zt-46{x0a4IO4aeBR=AfWjoRfnryu6nTQjjAJ6?^iuib&2R$p6R01@t;)p@G3RPR!~Q+2-T0@cS< zUs7GD`aji0s`*xNta+|4RY$;g)`)MYZm-(dVeNqjRNGZQsoJ4BTy+!GLsbW;9-+Fe z>apL&S{;U{W4c!8s(QZaFx6?Qd#nCNb-3!Ist2nsQ5~t;{=L=TNY(za>WEfHpz4XL zA5N1Ey!)f-gjsoth~m+B*`^HpC^ zeN6S=stZ-S{b0>Nk);P14t11jh32YnsJ>sdvD4ZE&#AVneoeJQ^?OL}$yZtP>2`j_ zlS?hHvRb&j;&J>|!;t^}Ls?JWch%m8ZoPOv)pQ#s2|H}VCSlKQxG8*&<&TrEu$<%* zoZQEG7ZtyaqvFf2RK1BwSG`>IUeP?#0yN1Js#~hQraDBm+jgsdm}(!@k*e>h(0k2E z8DO-la2&8^sjKSYsvlQ9QuVW{N2~sy>S)!kBlii;Vhr8G&H1tZq)^K&wse_Aqk+3w z;Wzj`$$QJ|h#+jWcVOX@oUDKyI4-<@2mE?__v`fZjyt2iK`l{RxkL@P%Zj=h$-NnM zD+&ZZ!M6`lj0nMhNG5CzcH(#+cF}ex{GKAa@5B&cznxepe3j)-vFn(fcXpjZEnT;E z={l=z#egE7W-nKeOxSAf!ttjWt;sI<^(8y(!VqEDE-VxdW;w~%0KU(#)l@_Xl8`Lm zd#8d;@a;$JLxkW2lKXiFhhExc?VmK=FK)Z7^`EHA;jKDOwZH0keD{QRn@(*gotNn; zY8h1lOhPBb4*95x?LblyVgoP8m+ zWZ%{$`^dpo_O13}(m?jvWiK`f`|ZU|;VXO5Z4h%9kC;L1oS(rIEJWEL=8(D9${|a0 z$Q8{aGSQsD&O0cbb10^k90FZ(2p?wU&~YCYKF2=0@56Cn-+l0Vo_uK^h6tlsPRb`) zo@Wws;QIox3=x7{Bn$SUK)^S81{0--5O6;ewtD+%PsAU?0T&5v%wlxh`5jup~ z^39n^Lzt!akJu!<_eb0mcKH$AUL8D7?Ob|| z{@m*I5^{%fs{TP4VXJch-Tud*_Z+|^Vdn$bB^YP zlJD7tMshGIh!JEVSFjId0)D7rm>h%$F=-f^_#eb3;e7{jQ`q|;y1haUV>!v`%zec> zIBLd0Yk+yW)e}W?fX8$|sj3TAr>ibfy;gOp>TguvP`yocxiuk&DV-hI7nIkuKPTV!=TKjv&q=O7IWT37hvJl#F1@ zc83u38X0;BqlAMFAw&2U%Sm~v{W@DMN0eX_(gi=ESa1e`BME+rhp;&gBV#061|CL< z@R7p^iX!_T#wg*dERXW;*yH`f*3?Go-bqqDQuPwmajLULbLx$J>u}u)-%)(>eSmJ~ zDf^RJrmTa@l!cwKrY!VlOd7>Bp8gq|MtOJieeq{2Y>0*(r#cMHM)7hGN9i1X8MTBD zb_wq|Z-p;H#2cK8t4Jnn`~bo6H`tla5%`TJTOPp>;R8poP}rO0!vC@SP4X?4libM3 zZ!*eU6bP2VcMP!>5rXfKEXYTJ;CJ|rCH_VPVY45_!m*6wcNE8kK}X>i&3BU?Jc_5t zPEQ=Yb2MYAWi%nKqj9fk-h-?`dNiZwp;&MVfp4)B;}}N0#o%`zLx!;1F_Z{jIEJ9N z$#Epq44=>@p?c4_Q-Ei1c@v1V2qi*!WZSK@*s8gI_R8*zOl(2p{_eCBnfhpGb~k zx$u3KlU&*2iHwqlz!)M2QG&fl7x1yapbUYN*h9k;7&VD415Y4B*y99Bgb^nY^d9*Z z%Sm~{{vKPUpjeQJz{$iGL<#mIU2qb`lf8rcTsmP*Se#CnanjO>s_Tp91jgxvHBp_a zy1i&lV6-)X4^cW#;Bac0!24V#Fl@9nfh&;vK9kvsGQoa?en1o>hOpK66`MZbpnQMD zP2mH-qFXFE=vPbGXb=sV|JTI_1}} zK4x@&uv<`wWWiMweC*x7bB*8cj1@#(U99MtR;)3R; z9ub1=NS?viKfA;(|9@haCRni_I|IL&j6LuSh6rChgN4FzXK-Bj5zA+>PktO~7JJD+ zvS1Sm1iRszz;|{}@*9@CzFj?Y=dkWMYYpo`mnlk|V|D%7S!5)zi%DluB1}AspikJ< zN<@9a;9HO`IEG>Y-}ai#WirlT)NIymd=44Hj^|J^+qkAA1_9?dE_g_m?Vs2Imx%2%I2}vR(`dTIL@zD61Vu(O2%kff}8VM zH?#!ZlE?uim?V6w1e=7PvYg~Hgo3U3-Alo*$Q4{e8DaCkfNl#|_sI*GB#gX(O~SYf zxVeD0DoGc(95whqg=p+y$bTzE^R$s;oyRs%Ixo*rYMF#?E|U(6@**bxHNWUcY~~joiEaF%Be4g`g5xMi z;Uk?h7p=rc`C5rzQ$1O=`z4mU%NOme@&=+gusppdyGQjd)g4vmtA14VG1Yxk7h2lS z7@&?Kt?;tyQfp&JQ993DBDKuiLoPFyxZRq$BPjcvqq~UE#l(MzA#9BL#jdlv@4yTiVa4uZ{q%&|Gy(>v@L!-_o5|W)QVZ z+QTlBW*oF8Ex8na%egl*5wV=JmWO1)AruJC!FL70OO$|@D8g3%3XZSv?%3S-ij`T2 zCem7USJfS^WCyMEt~t=HR(434_ZRN5yydk1+do2n0Ko0GE^yK3T=aDpZT>L7Q~Q9| z?u>Vzi+;k?v6UT~zu4*&;5C;9Z@Xyo$AX>eo4@$zq?fqVU+-K#$u4 zw~dsDy_XchP^So*(IR zZ>QT)?u#;$y{!jY`gRs?tDc|5R=2(DU1}Y6(Iu9yljP>(G@{2w-8nJCUG#gFzMab) zm-1CEI!`s?*iDby$<=@3&TiVe=$@vo+&2SNqtMMKxLK`=`Tf?V+RlnT)+;H|I zpUi5iWUrjh-$Fyj_$t5kW_D4{57n7|?-@QT?u?dA|D&!yu|r=Qbe`ptb!T0eF+vtq z`H3p=XY*I-zN#irYgF@tbY=toAl>WLHOS^~(FIml0R9eL9o#d=XQ)eFZgZJ$<{Y1= z?(}EV|68?z8qD|k@Xor{*mlZ~s9m1#v#`3tZ&ujrVP}$$%TJP-Ewj(U=ZR{&;&0Q{ z$sU>P<5q2HN;*e0A&?v5kF8Cs-3#3_>;v)gT|T|>^CF)|tIO-jRrX~lO7ZDjUEwpC z_K57l@0zx%uKVnpi+$?3{`!)+$iJ+y*G8`;)pghgFRZou zSu%5G&NWVJeZS59Z5US>%ucFi#;r2cbzW;b&z3W*4I7+}WXn2(VvqWcdyLOJ9O}@sXG;gna6+SL*$a84R zvhwjhX1x3?)V&SHG&40ptx)%JIC|Dp4ac__q8ut%c2m?=!!U<(mn=gA96rD)(PbE3 zN_A&h%Pe>0ur18p8&Q#_3HaydmvR$YHeotP zU3MBAGq|x$%#NoFy&Nao61m(prawCy!GXqiH+8`~XAE_mMf&}kdnKId&JTsx zUw5zPYzzIL?ta)9ZF-EFH@N?vpEWqT842U-|(}uioQke{4I#rxo;}D)^NNgvSvUgv*t~4LF-sUGwi=)2z@z7 zKqgb?{p@&X^I&`x>Fzb!pw~4+%m1vE$(4JY3^D-BkXIj-S{vLlv-_C3>ELzCF!?|0 z%6<*V%(-QFDPf*v#rQ(QO9}HVE0{2^tdk~#5LBhcftQ;ILJjX41NE&ud$ySGMYP6C<&$>MQl$jp#qB z|HmVS_x)&a|2}bjhYt)HJm{nM+I0#JYuKn^Xv2P^xu}`=s;WBw&1*d(@YJCE(W$K$ z2ZcTDXL)8<$|KI}waJu(YVKN@=b4SFz4DeT&KqB8%->*LQs1KwDwtjwY@ZMBlzwvH zE0Y7OOb+y(99VU7V71AC)wc!ubUJMQD8BS9)faSmJ2l-qzbjw4TXL91yuu%%#<1Hy z@?#Rog5x+TxD1y<;x@trFVMHpC(y?ufp44KHLb=vy=D;S3%!K(dMyx3xZ2!^MYi{E z?dgt9{5V7s0!TSdU1-4vY}|jFcjuK;GIsOqeg)MJsj^t$@?`Ix62`#V%+o z=#OD{SbsR?5#}iqN_(?{?%10+U;fGi@}=Svc;591(RqA>)^~jxx>UyyF1oymC4$z- z74$%fU@(I35nm%l@EsBbNyrjxM4{jieD4z%5hW}w6)$0jpqP(I^5Alt4&w`-hB|L%C?Q>#`S1nTw!&J$ zyT}vto9AKVPh-z(&i}ugH;Df)pSO_zZ<=?Q|7Xv8!v9a^>kR+}c;?LLiJ2I?SO$38d55J4v_5yT)@Fcc+%cm%r=GZ7<5MxtOFvIIv^D7XmU zGQ@pEl`#f}mr1maJdPtbigV-%97$c}`|s$rrpgQG5z22r;E9A(hA{VGk!_S?=`u?D zt|z7Nx0g{YjpoAaMw~~q;0`7cx^gqH&CS?Q=Q{(}Nv3r1)^lwnBK5|=4ly&Voho93 zgO%Twz?XE#0Dc=ajTuSG8Uy*6j;A~4=ZsyAd#c6^yImWa&SxkP?QRV5 zY&%O`LRi!VvsuIkQgQ^Na8EE9{&G;yMK{3;Ob~3wCP5A^2~MDLIpRFp3T|SU;0cn6 z@~*S3@gufq2x(*t@Y1v^mkro=&Y?TT?fNr+-H+w+A*T3c zhNEkE+M@WwSNk#70mhi2_{rWafNn2a}>5gsP z{Y5_9?O%!UcVM325Do}_N3q}r%$12Jh$eI%b1}Ix+wz%5 zZF;2gy7Xw}4e0&hVPL1eVv(&=bLi5knRW+T!bwd#jcx`u{3j*|9%Bcx1rqxu11*fck()>xgFAjVO*^XX%E%RoI!n zm@W7cIf99}CzuC+Z(=pN3DPk^@Dnx(4&ai2r%YAi5406r$1uTTBojI};Mc0$FVz5D zHDf@zI^ZaH#ND+Xapo{C+q&0@?l|EZe^ezAL#i=i5|#+kkSo}Sl4?8?PTJKkQuXbJ zcY+D0!WN)+bsm2$kyxEIBatQOfect)2&%(k236YX5I*2s_`?Qu=;F1$^|hlmsmzzD&YND(C9 zv>*{~HHbxMB3O(5f}b$2hB2_}aV92_S**)Ge-1lY2ApN9-o~ilI=}z6;-4 z#Ak>S#A947Ug_~;X+O5oWm4wY_2X`li}ncltf4Er7+!u1>$@1Og|98fP?9fqmiRGX zALI(YLWy7kg8hlPh!HGBqF@uU1iMiv_yxWJ#92fMiZCv~7}!_0gmdP~EYW=3TFvI) z=(PqmpRU*1+WZH-*2CtDcy$oxe8+OWzfhh)pP;;8xt`zTbqVCLu#82v>EA(@Vb8T2 zwqGBe_5>XQ<(jn=V*-sW%sxv?t2CuMRtX)f)0hF0Rrn93)>?+?!jNUyN%HO3O|Ew744)vPH#!L7Fj|nn$9#EFnzf9B z=7lJM7oTM16X~hSr_!^Oe@{QAJc*vKJez)7oENU1yeK_`e;rOznWWMY`_UaooIPEq zeZ=RA*_q*3D42}H0)Cx9z^`i6<;lO(F3j&L%sjif4xOvhjLDc@mjiE*jGd%Q1a8)4 z1m^vFmG}@H1OqWzFp3W$6W<|E@FP6x5zJyG;9Lu`uuyOehXoh#L~xIfBy+A^m*a!_ zY^us~Os{VY(A8OvG}0WtymYj^=rUUSZu+g!Y0FT|5d2n)xdD-ZXhAk634TFF1CI8* zU6`jT%zV4i&f2KcTCYIWV2-j2B7<2o79#}1kRq6f(}Fp0Ye*!ciC{DO3vw_|@GA}o zZlIXZ=~f~rgafLy5YUSD`7%yz~7VbL)PXCm4zYf+;8# z%!j!Nk%DN#Gi#OgPknl!j(-4VH{r|TLKeyOVQY$Bdo0e=rhtcj+0|Cpcz4IN8t0nu zXsE+7+XbR6-Es1=-CeZ_@Ndcnfo_8Jm>}4TO@cGH)RdRk+je2ft+9rI-O-?Vx@w)# z_I1|y1jAl82F53FE4cuM{;1c!Q{IfeKzRf`MR|LAy7I2{Eag4vN0i6X&nO>AzpOlt zUZi{!{h8J4XbD_!Uu*5eRQfB*XVLwXFZj{=S1g#zwpr>(mszqOUMRB#C1P|l4v*>S z1zE@woQ6kpq7cmqo!dHm+MIjYcO4c9o2~euS9U$twPZNcdYo&?Gd*}co|EPl>q~q6A>FapCtA8{$%t&lNLw&M zz?*e~i#RR#8*bqY@3jFZPk{qm%>-t}f_Ru)6SEO5Scyr3Ok@ZS zL5{9PYjIezw^bri-8%-jNfj(cRS`S)39<-B`*QPJQ zFs=^Tz#`k8`He1PTwr(LCA4?dj7)#Rh`I)8xD~+*Mnqa^odI;mI!Uav0Ug@1ugp>| zIEJ-?tH={Di`*MBFB{R~4Td#u#HYe$8?i{(VIz)^d>{3MoAKm*^-ba%yf2uKX>amf z$7-Y!LEHKM($@QYx?@kYC|4~o9S`4R*rw?SYDd14jvgdmhfHe6fFqD0_zu?uOW_?! zY(iutTj70kB1F=m*jjl`msS?q&C#r`u3F?K^^T#dD_%_Hn?#nqk4qBlb5wqd_!eyi z3ouNu5y^ssI4L*>m$!|99z_fy7n=td7Rfs%y3M8S)}uSNoBf_Ezk)pEZ3g%TO9XR~ z`!@f!thB3mOjTTD*I~bpT(xRj_{jjLqwW^;7B<>~8A4_+*-i4VOksOVVBZeJY(xo? zF|LC#uys1$Da*CzE>HDb<=SGsc2jvJ`U~ZL^eS7e+lSI?Z^eZU@@JG~wn_b%E`zi0 zqvYvX19L~V`V*oB$1q872^oTixJKwIWT5Ih>~^gTyd``s10&zzIs9e@7Ln!;GfJD8 zM3-ik*iA)O=BUZVrFR(dA5`wd_kQKJS@&ezbXQc&;4J`dQA?F2uq?#Q=wERb3mdCK zx@DKkhVQ7dB$j>Nn1=z&K7vaW!+(h|!6ft*EW~WV2IL5K}m}0dX#A$liyNT&22k6cI8ZU z+>SBA7^WH_`FcOEt1&QOEN?ah=``)PZv0y!&ix$A{kB@1$7Y!|*4v<(<4MKj@AV zoBflk=C=dAyRnI|9hf0(w*$L{J$9godXs!7me`%Oh9j#x|HewP5L=Ho(xu1C z><$ILUtP7w@Qr2z)qg_gXa;)!CyXa~BRZAEeD{_w*bUDf#5sf$I&Bw*_TaW5yRcN) zXBUov5a(T1CLiQo)<)S}v^5}UAY_og*fkJ)-c_r;+j=yJH`$G} zp6qpx-MAq9csIP>XXC>W{yrQ37DEJ!utcyPxq|&D5%A6A2gFsx2>wPQp)0coyFXwY zpFJoN*4~4fy~sv;&{^1a55^07??D>Lvm(D2YkvdJ4~f|b7c9pR!DcKGWFuE_93_H$ z1ji895F@yaM8Pv;5jyv56vZ&OcQ$JFCTnJ+voJIpw;vZs zzOV57j8VQqxF8-w1XHm@uoSt14JZ-pM(|+b1Y!h#AyH6*EJ9~IfTF>S8hijXhmg$= zptJC;0~jxiK7ce~?*q6%@{OnGP}b)0B$$sOf|Xbz;PE8bg%ZIL1bIc_msQSW0Y5*$0@HwAFsR$eLg*2f>!6k2DPFF zJx948{a59+=>^K`(jO^rKreg5+PP4ARppK8b(A-ww@}`S9;H0ui9TNIr54(8MV#{X z^aSOd=!wd^(ibW3PG7COCw-^#59!C0$I>q=??=C@d?3BV;@tm(xln2E6EMUPeTb=w*&sM^KyY zrMxcPth@oevGP#*+sYf$KTzI`K2mury5t=Qis$GfxUgESXh;7^d3*XH<(=qfly{|H zSKgg|S9wqRGvy!BD<8LZI+k8vc|Up!xpDT!SJKBRUqhd+Je~fd@@)EQn?KiUTWzi@tK}%)Pd{e$y4oQwoKq`~(yuE&LBFf~ zl&&n6-SP1;>wYbr3Nu}%V!8cP3@)SbrPvsbGXYBkd=D>JixL4}o_uX=8Fb1n%mWo> zg0gRn|0-=OqpiTCZy9YfG6Y9)O;7;ui3D!}61p;HF>)fiTKz0mO*95nt9RDgR2-Xn zU7T}u)pjJdV}Y&BPw3L-D!VpA_mtsXJKsqRzY|e{BN!(*k5oYs@(CT!O0UUmvr-;f z3v1*qQ1gDT8xP@zir|_Q66Qk@OrES!uOB-wK+R!vN?Xy2Hayr}i z8Y$CRb2?577Q^j3A{|Wx2hm?}4)X-}aNs-M%PcEN33y%W%1Q7R=Ok2cEvxw{uSBnZ z9$w$`_-Vp2+hAkp(vh|H9jWBT8@$oqGx`op5}ZJW;0CS{I$b`hCUWN(^YNCjVLnC* zJLY4R@RNL;A^GE}ZZlYmpIQqxp}*iD<_Rw1fZ!>LXYfm7WhKJ^dq0+ko|ia#U!6U! zsk{cgj&eVGsPfwM=F02R-%#EFv!D5x%GSGE)11<1#rv13($h(HF3}!)?ST;f?YT)$mI{$ z5|{AmTw`FPX9d<-i{(DAa>?rb=(Ut5(3^;JHbXf(tuA5wT<-rUmf5Cd7+t1iz1_5= zN4ja5I53wj9Y!%*^3GFHA{gbK@^+Rv4tj1E%>S}A*arJx?cKBimoao6#};=PONH^5 zag5}BgOYh{WI2N86I&4@IEX~SS!4+cQAp@`+oC2|v&t2876x9yc;RbTkS2WN3N8q{ zU4hpEvfmZ77LL4vp`?7DVF9BpM6Q50Di-hteFpp&^3>UXrF1$9=`tOub|df`;HHIK z#it7yuQd}92xG3|h;aN>JSF-0@T-d$csqaJmf%nO3GQJBp{u}50*kn9{cC*wn|$jU zItu$-!x-TxW*i{dxx61)Ya2Wk6ThOl;0^{6x=PovXfd~Ka2-d4?_9@I;V0KoZwc#8 z;ZN1_v-B0$xwrM2c9fqz?h)rXmCd8zr1AoK5t6xSkp9ooQ3ujx)En(a9s8r3*85M~ zVszc-f5NzwO!yNWNv4$|`cfbgALm@oX~77hw0+`>bWAKjW)vg2D3E%+6a z1h|#%Gb}@n78mv5tJ_Ru;+}X)2vUM?=E?wMY z*TvA&ZrVRcNntA$ZsSY}Tk*dQ{VKBYZ8Q~jxQzkA4{u|>aKvpKTxAUKnQ`0Ni>vI# zDslFrfGzKV%W6(eE{kj}KcqXhTx)8l`dsJD^qaUUND2j0hY;rRR5N%Gyv&5f+RfxlhL9eo7hM9|s$rOmqhZEZHguGwrC zz1HDxOipK@0e@qg@Y}y}o#giby*DvnCL#rAFhcMMDTL1Z0nTjVwoM*DznSdz08NFT zKEMFs^aq$v^3TtK&8)Qx#hZCZoP1E)8?D&dn{9TziS^)3o?`Ua!U%(kFLJbudp?9dgB<-3O-Ww;`)6?LOw1FUzyZM> z6caknM+n-+ZEHV54`KKtOcusG!ZzX9N4PHh;Ss84GS*H+X0rA*j1W9WN+v%ZuJV|B z+e3aYOI{l_4CJD1XGhXyXK%L~XIwSjiDkKby*I8J(l!|by;uZQlvGWRi=jq;w@TIJ znmKGc8~Pc^f?sh`kPnv~1Rv}WJVjrkeAy@J>^JIBE7<6-4>jpE-zV6+!`QHVJ+;!$ zUym+DKK>QE`twb?Dx~8$U#fetteGmC#j<#ILLXOKueE=IZ+033V&3IS`PeaG8SmVR zbIfD;x@EBP1o~Lz6X}V{r_!PPdwP=cS@cxpb1ichlF3Ee++Co{-0iTRJ2P(vP z)}v25_M2rbR9QC5J`d*?gJb!}I!YDB2BG&BPBM!=w$%+{-PWwjvaeKGI?I+-;)lqg z{GrY1s*sL5g+2jgSeAsoyNoSEwsMuNkLT#p$DMY4oW)IRJ+tXO8dv^i|HQ9 zljxO|ucZ4cUqf%Hd;|SW<>~Zp%D2*Ely9fUDc?osnW6RLSCM{v=2O``o-1tgy`1hi z-<87j+MoO_VRri|JhJ8DS%MbXJZt?+@TstI2^I<4l;DUkssvAkF(s&%V+=5UQequi zHk%%4?ZpB?Y*G5~n!9NvDAwHIRqg9dgcY^ZFcAlm= zI&(QGJN>n#ip6i(`9I1t|EXx&UeTpEGozNtV~WF5$P?C>s^a1*lViRUmOIUN!t&C5 zC!G+z#^nEU#N?NYf?&&XGTZUVWeNH32~I2xI!SP1DIb<Vy$IKZSsrhrPL;twOfvv<~xkg z5^l_Klc%$;XZ}BOo>&4)&J!@_$sV-WXz<3&uiOpjve973Jn@^Um9xljk_W{SiFr_R zF!PM*TPOX**}crn!CWZsBKvhyd&Gyhm&MM_hGx#TeYDTLnxsalhtK>C<&k#Qlz1b z*&>sfQRX_W>LeqICFFn2h{7!_8By*y3F$l!iX~>MdyR2U2AA2(qsBsKk^VnI#QYbQmKZ5Hq^Jowf;r&CD{6{U z3S#027%Jv$rkE3`CFTgJp;?MjeeXJFAy@G0dE~d=wfA0o?ctnz?z#7#Cj1z2VShwi zo#w_I!!WA47={~J!EpCA4EJ+1jjH@-`D!}ot94;r&KpDK9`<2;Gxxf!3?DYAJ8ICZg6i*fTDG!X*WjSBKMbMICVs>9=XBx?!(Q!-VcbmL zP+aG=3bRLe_nY0p`zf?<;qE^Bg7*irm-+OV{i09k_}e~{Z~M6LpN;=2@Lxs#tCV)z z$2EITI-p7XF(rx^{uc%#GaTtc-!*qxKjH|!7`nz02z4OE$=qj*bjGzWm z1YS6E-nF4u%O;iC$Tg*_VGMhwNfoiz+@k#&>Rxbd*!Z2&&W44T@9eQ4R!u?Z1qR%L zIKcsA367&sa0$K_T^qXJ(#XZ|z2NHIWVlOd*x`?8*m3Mz$IvLiFowU2sTUdHV`K`( z;3@;T%z@()(^~1&erNgijSCIqiwfvh%Ramp#82j z59^9)e}pk?)_7>?P)5wsp^Pt`il?$z^*DCrv!hG6mG9chHsTH%6}bAlS8Zf2_zMB? z`K}FIU*MQWK8^`2ad`?GrNZl0h1VhwT2h7kG|>Z%R}5H`nm+ux5V;w2}X8RxB70z>p^s`Ma8S^Kg%lX8i!EU zcYQOFMMuz2ihi?-x<{MMY8Y=tu&mH>z7>JI&)w?RFy4+cj7S&D`F0$#-Q60v_GEIA zo@jK9!)%BignMhNMo5sEzH3M}YjnWIYp%~ZZ{NrvyMgLq;efGkFH^sJ(5d4YLaC~ zwx>PU+6wDgbJPk1{lUIBOAPD3Q9qaOJAwln?TMH_*mr%T3tHid;Ca+7B;G_PL2rx{ ze2i6sVaO3og8c?D3vC69F+i{e^8^{#cSDA*8#R^P{H)n=(~dr;b~x=qIBvQ&XfnFE zG}STnG}VbrT@T=~G{?M;UN;$i2x0`|kS>^kD}n{6`zMitPJ%5MDcFxyg5${f)3ssk z^Ez2$80wm)mSdei#{65_{g)-(Pblp^I@B<}{2zjEF=z_n1j4qJRc?NkRsr? zM15k} zg>kgMP@7vXY65!Q;ku%9bWxkik1o!aRsTlf9Ud?4rB$Q-wCbeNd5z-^j1G@4VyaOH z5X?lVU@77R8;~W~g+jqG_}=AMqw^7LvKY~K>2@Gh&=`4wXW_W#+VJ_#y1;pc@zn=9 zgoU&}v+Ntd7|#wx*= z$Ps)Edj(=1+6tCofM5gW33gzgARBioxV39C@j~hFCb^U!UWUUkCcT7S71^XKVg!AV zF8Bmj1S3(ml3PQUDQHi$oa+>AgGP%fo!-5vjCRX9{qIdh>Sewt?&UU{Y^aZC%cb%{ zwl9%ReYxJ3Xuk4#?&sP}u4`2^?MCo*Wd?x=7QBLJL3gAI-b0??V>sN1&k^M2*3kV+ zJwZ;eHq+$T(rhQMET3(59y`2(6gMu+?1b0 z&FbqI%_{bORxS+!4CCv)=8mE**Ie~$xHJl)^SI?~WL_bOGn>xy>dZ#a4cGc^E{*f( zyn~K4+@5P$rL?E1&B~46#V^Y+riNMV{j!i%nVa0Dc_E!cEoXDx`7Tc+(rH~w(w2+8 z2Gv_|_NGp@Dz=ET4iT4@%ya5Y%h@tWL$->bbCKn26@du0uI4WlS6e=R_*ZjlSUtd( zu5`;4;A>WM4UlYhqmc)fVd^pTFnI|RJlq=8nR?gSA;}KInC7lF4?lTpGObSO(5F4A zL;u<+S$dae64_=LiaoeGW6{Esh(RC0EKC(FM5Z7KR|T67mzJg;x4nGor@1mS4FuO^!$%M;Xo*xoJLC!8gu{#Y z5J7@35Fwa^M8QI23)aVbGq;)h5Mc6Ggqr*tao#L7kR_;zLcyc(^&tWfEO;K#f-XoE zypKG=FgWTFa}gxih=_WOKI$x?Ensv!K&yGqpj9GuF%}cY{l`VUm*pFNG6tSPO z>{()Ww(R+0_iMtFr{TJSe`XK0>~HCrJx=YXXwTH05K7xRzu~1v-5zVargTnc@6|b- zd4D_DKF%_XIh8QsQKnxT8z1E%+_<#GoR_u5tkM?4q{Vpin6VAxAzY1zux(f#owL-L zXT3GE4bP@?iRB!gtu=>p5$Alb&O+;OwTWmLEjJb6&N6P%HvWbRuTCz=Yuq+U_q^y%w7Gu5HtYM3lcD*cT zY>@R1)HWr6&H!{aQ%Kt;x#;jfgV+8e)B4~p%jd^l-CB6yI4ZTaVoHw$3mML89d0Wt_38T&1jgcm^ zvC8CWjb91QN>7X-B8d$GHv=MFY;xwtb6i+o{lyz2v^ep5x;mcV@FpG9szKoKcxh05B z>t)xrB?v)7q`R%zbY8G(Zp}7dpxtcS^XM!>BR@`+8+r)pVgljb%BuMzFBsX6>p|u< zzY{L_@!;-LI*s#7rg5%uf3c4yva0ohXgivSLb(#K9b@_YpRAb240Bv`N>J-&4DAwU zD4o`It?d}6g}qlh#@rWF(AGFy!L30J+wlncye;4H2tCA3IOuGNeot^9uV4=0{*G1U zRGc+or+r!DW6O8i*BadERQg7tQ43a|VHN!nBp1p|{Ff}2Emvojo>qR9Zql)_gR!acyMay3sb^4abhhp_Nf%XzKjOm~gFF6@bZt=R5k%pu$(tSUDQP3)Gm(+zja zSI?!lg6Pyi-wHx1ccGi@uRJ;zp@%<%t-%C;4s+oiE81ONu`&CawtK0p^Q+}F?Lrj# z^N6T!orRK_&o^FrM(RkrncAIbw@2FmR_#=}k-qs*51!JERN)b3@l7J41DM5Tqz3S? z{N@1iOymM?*qV{PLbf0wz77AbLqHpb zS+pOaCeI`C}@dd!OLjTo(Mr7K{%!gzC>nwzL-o$9?^JlX(r2emCvL{v|+5U zquKLp=!0H@)`$_jhIB!1ToHVRx-Ssp&`A)FkuR`|BrJTvtwF05nWcTKIIn%oE1jQS z9PPKw%ww=ZuV4f`&sT(Asr0p1Un)XPUm<;OtFO?yw5kx2N9RDx8Ip(Kj%?i9LEl)* z*V}3qa=;4VyBgLIQwxMK1I>UI==K028!#>kGW?!c;! z+z`GvNVE(rordI+Gv@Nrexhh5>#{`gjfgB&6w^#TX)Q~XE@_l6eHYc|YrR>o@Kpev ze_PJ40uU#S$AuckYFEoQF4PJ*E`mNE^+l*Jnm+4ws=~Nv)8{%aj=tB>@74P+!WAZ( z9|qO0QDG7jUHz#QW0GO*y-DnU^*Hqfm@zyj1<^NKePS;|z-ye9#}F!DmV%DR61Nn| z6;->qHS~J7Nd@Na`o=KBSTj^Nf-h|zzbtMXSGquJHtRlhTAwI?)Nig1(3rj6kYj8uA2-;ONSnzgveOlUax`c@T*ve?_**8}VDod>zsZ($kSb`0JV6K? z-H1p82^Jut8>^oAI!g>B0w-5p~0-OZXM!+`MzP@Po){GyROrg4Ylscn67s&yXz`8~--{0s(Jx92=4lYBCLRCifuA+__N%TaJpdTUx!;vVMh-|^^_;(m(<5C2egTk`B4O$JcnqLH<9{3Hm`&{K`l7m zCmJ9~&x^ZH zGr0{}CbLm!@)~?UW;LFk1yvC(@ItDf8S(_J;rN7j4nYELA^|V71tX9x7#}}?e`g?I z0Q=hV4MI(Rhd7hmL?+p%Np7MrsrM&>!`RFd(Sim@6+DAHK{q%C5+5T-Fb)v|c|!$y zp^;-4-zVw`VGQj}YDd#Pto8)j=hTj&eM{}BhLKrC?Ks-rYR{qFL~o+-iZ(MyZC=r4 z_O$G%yAc#0YXQ$nnUmD!St&C?Z6=htT5TqjxkYUzlzCWfCX}fkdf%0V3e_(O{i8M$ z+FDs{UJh>cY7$k2XE)co3n`w|f<)S#)m~1!huS>DZ+&0w6xxH-PNh9Y?Txf!)lR4V zjoO*CzgIhp_93-*@ycUsfr@>!OENuZ7~34`&!+vj+Q(??H-7GN$+neD=^5H3N$1hl z>Aib_c1hA#Xb;vnS7}GmX8*2t3n}!o*}J!B>$e>4-l6@iHYlc@ZrS%ZW!ny_U6J;$ zYTIf5rFK=r*j`0#2km-l*P`7aieLZC~1b)ow(4sM^hF>*rYaTF{32 z188fa_nxAyQ+=;3ZT&FmUVGYqX#F6=$Z|35DA#)(DQas$C)&-_?n+yy`d%>YH`L#Q z_J?ZsqCH&gKD2cf?}gHyrT%`jm#95}wtf_SFP!%7C@qMfIH~q9+LzQGN&9cL#~8+r zN@_>buBG+_+P-SX(0)SgskGaw9Y^~$wdc^*O?@wF9!1G$7Sh(QBHT-)Jw+QVr>#5r z-YVM3>QAAargkdrU21QneN63i+WBf{(!Q;BmSOzBLs720UGMFpcvK7a(Qc*oLE6u& zolU!B369b3r~Vw;L)1P)d%W6twCAaPf%bQ5U!lE6?W^4XKa^xz$O8S?|K2UyH?-0n z+W)CtY#2MMSvE~$rzTxok#=MC+iB|nimTGr0TerE>i~*t(e5MlqYT&Lx)h&j<9f7p zPZayoo}vCmv=^)0jP@qAThKnLb^z`3YClC=KQ1k9OZ#8-w>OMkx^IeuXh${Cf{qlr z+lxEVentIVY4=h)n6^%JaSz%P)ZdHtLbdzQPEk9Q_BOTq(bjWD@c`O-&VcLZZuOe% zy1`=oZ+C6Io?T6cbwyqA(NM$K9fD4u^L48~Mhb>tm0%ol1oL1Y!k53@$!Kdb69Y{C zjCn)&Y0&Q9^c88IVeF}>_CnevYZgJfWb`9x>!DIShPECm#S>_U>u6$Vk2GyJL+pu` zT~Tc7xOb~KmA18HP2DQSQCP2FZWZUywhkM&ijvR{ZM@KWufOML>16ErTPGu>bTXdz zHH^K1NF2&>zkzJQhw;PscO(J?(-1n0?-BMcD-E-Er-qTwK6FlB;+*cQfGlZJ7li`e zuNzK0k6^)Dh!%W|RKXbJ31-9b1t)snN(7nAK*Sg9Y~SJ1&i38Z&Pv}nRD3(yF!n!< z>@OJNmG}|-+Y`10?;ClQh z_E8xDf?5a__#sXZh%CYDC=`UkcQi2!!Gh_C9?j-IE=Q`#4ahUO4~{Y7KaHR2oQjGwG)6t{{g*53W;(b6gXDM+VuopFCkCk3<3c=Q>|a6j?0cazJJX>vWT zn*0IvqNMyNx|+OV}n!34DU%B{g$ zhvKc<4vRUYLrbkOB;TQJy&$_)MqHoyd}!#(c=>!|;XH4#UAOA|cONfX>un&6L|i6fJcGLg9) zS%Nbrx1j1I(MQnU7(ZKAA8r-%4C83Ys4mcU*O6SI?Wy)v+CFL*(r%9Q7@jno zZY3Tqxs|xNbdcwKS#?Q#EHgN|2>~V#BGe?mf^CwYlEiWVbxBygGkIb@>P=_gCz8>1I!{I?^q{N6eRpC%#?aU5#JSQqCo5{4wENRssS5Kr z`I>nGqaDADVXB7GWqoQ{sVeWe(&t(=i@pJ9G=uk2t*;eSs?K|<@{w_+8bK_ZVuh#? zggDl(RwIwTIqE|czZ>XQ$>E@H87|CV$|uuMD~{*Wlhzj|D%A`|&GQNI*7h|6y4GQGIrZ_>OfK1z=qGp? za|AuHOE3Vp1pM@M7W2xPj2^Sx8dT1S*JbKq9g;aKN~baBkWM4db9xa_scE8NeuG4l zn~-htK>PwJzK8&m{~&Y$TR9LXXo4)kGbmi()-bS>j(?tE{Q92SysrIqu-f}*k5v00 z?a4Yv{PbJCH}|X4SCM}$`PSE#(m9$J$2R|B>O%Hd4Vi)_xGD%jy>Ey<=qeb6G2bxd zv++nVnTj(e_o3<{@n1swMXXi<;fr`Nqn~cC=1WN4lbYNa+HYER3Qq%h)>~4yN-eBJ z^Tw1eX5Io_Os7Ow=CRFj6iaV;1!%EY_z(IlX0O#SRnP#Lf~Rp+@Fwadx;3o-iFR4l zFwRA(%_H=j^~TYyQd_J0bKjPBf9`Pk?&a$$ztu!yA|pSBY{66UOZc}l0tD|ORPZU{ zmhd3`O?z6i521-}KCPX;0{mOaXLR3}F2cqv2Dg4?Q%UUeuCOm)glY#FZ|&d)0y!1*j4fKwmoT<8lG5VMRSY9U?F1Xl!YPy$q?n*R_OAD;C@GgGom1pK^yHe>}t3Gt&Z>nlk+8s@wp8j`7$A8Nc`0gya@~mpR zvk<+UzCGL$m#j|(EA0s|!@2GWGK|aBuzVF?jUKnE@8hS9@g0%(l1o;^i5o6L&ei{5VcB=ga>hTS7b*pUl6{AwbXzp~;-QE5i|Iaw@V+ zu12BBgYaD~J8f0o<*N^4E;Q&3SL2`;5}Sj$BwQIK)voauBrAzB-__EDWOx?(IuU|%{ z$$xNlBS-B(y-h?TbQQG27{MDz*~G*CqtdW{#A?_b_ovd;mS`A%@CzrK8TOAeXm9c= z!c7)q;bumvii3j3P%H>Qi!>q#eFWVxRqzoq(-@&}D6X2EfO_eo=b~#m?*|pG(7}cp zM&TN@nONawwRvq(Xx+JTs}xS#x?k^BDT4MDtuu_a^&x{>rIED%RsR^nxWPM{9Ftq6 zXxb%E{YJx|N@aYCLvsSYID;t)`ccuGJlMTJPm)TVJ(vtsX~b zs(C)4ZGNM#x@(O9I<4>ey4Jv1{%o{{YmHR;4p|jzq?+F_tnMn8w>QpNP6yWVlDCGd zBbdIw)E5kgeC^KF!O6O5S7#`{pXcp;vt;wdu*gftJe776q;BC?su$sR`=ul?t? z;r^IDE#R1~^)o)bQEG?Rbh4jyvioozwSM>zCx5Jyy|i?$!;_rs^!uqaH^R9SN+vV> zq?3KY$-YHX_B2o1&7`#8I`*5R zs*LLU>8Jj~280dzWGK3)+3TSHOncq3-o{uv)4sf{w+SZAvX_g{1Z!9MR722g`=Ig- z&Q9>GmUex%eWuGp%POU%&9x^#q%1YY^M&#)D$TQJmG>6KdV1oCDV|=iPx16chXnhf z@|9ls+Or1Up8v4+ep5YT%QZ-|Ewq34ki_;(_v}!vGTP7ZbfkqXvcLO~7AN97Q?NME z{$=@Q-Imw~l=uEL%k%Z}-q&Y)x?^YyA5Z+!!2WXD?xpq)59#c=<@T@2wrz^S<@O)S zdYjaDatU%sETsjKYO%DZte$v(Jzph3y@Q{}y* zSKE)5_io+c6Owi&#a{f7=!16p)J%J9t$mlRe7oA~?On=y3zv94nznYmef>kCom%Gk zEPmW*f1_NpwAVM;gUhvOio=`j!<{Rq@%VYOT)if!v5K4iY`Q(=A$e~5-agkkh8%-U z(k5lv&z29AHgB7~=R;!n?y!fJiviygJ~dJFxTiG*7sj|W`u z`ZUAV9zKu2|E^DM}RAu#bEoR7q9Wv_EgyvmUZFpK!0| zf!nw2;SV&EJ&x1v^{S#md(WC_qr2GKyC9&wXGOHDQm@?uRi%ft4{qCCAKWmed+uHP zj0gHmqx(p?DQJK%YSycc7ym22vHj)_a!+}nzwW#3eh7AP|E0WlTb+8<5Mgug_dwA( zoBQqu9OmE_-ST`4w=1|Gd9aAV)BdgK&M!ZfdD(4{*2mR7ySy88yJLI3dhOE^?e0e& z7_FQt8l)vwaWB7P8l!zR_Xqb0^K72>e0BG-ue>te4;t00p62Orzg}Zz=%UTO?pbcU zd$FUbyZ=KTCgjbh`0xs+F8}$Bj#-nR*lAhZTPv<^PYm-xKr{D_wt0nVUo>-XQepOK zZ+HCig!>0r_=Ni_c+{und&u#r*#pCTYKE@s(aSbD)!&`}D)V0z{;SG=)%dSE|J6uK z^>++x?c$y0)7SB~OWHplIzF`V&TaUIj)t}@H_ZId5mw3gJjTTdq z@36sU-8+@M5I)G^)z)nCTK{1k`VQ+GKKPT)gFYVo^6+r8ZH#M4VMi89#5enX)?cE= zxq4wMTR&1#K?>gv8)X(Ivhdm<$0NPW!fp}$2bCm~Y6TRRb1vzY`>pn9W!0p(f>wp$Nu4cBYO@S z78Y){aeFlAgE!yqI`|V&*_H|(95!fJ=Rt4v|Hum9=7sK`J05M%_HXtdQ8J}&_hpCh z{(a4BB+ck5-l#I%;mv*0WVoYE&DM86H;mHv zVun$9h+%wexELw>$9I#x05gX%pk?*GW3;M%7mKcf7f^moy%*Fm# zhkyOWjMStSn>;TM-r~3XMc3xt*cU9F0k0_z|JM8Hc23~e|0jV^Pcw?~7$T>zlUB$O zyoe&f8wmWGcn^_ZJLHQANkr?RLm!MBOZ~8+Ie37|fBWG+l|jy-v*0#jr!tl+GKkh* zd{6J3<!j2FCtga3tn-K7d-|KH_Xq83Lm%n`VwJu^ULB%f_2D`bNIiM#Y*PAARkw= z)=#4OY_QO#*6inq=IYpWbuNpp&8i)&@;?zWljE-N#e?H+KrQ25Q)YX_HMMf-kBpg2 z;tLcBVh}isScpi$T4V@zp-6BVfwPHgh$L+PeSs~rIs9rU67OROoI|umq~Jwl2!c^0 z=!?L)#1KRZqLCq(i6X&L1jZ8^5GmM!48buJ#XGvSzBJ;&q1bq9=3zsLc*7dX%ZLOw zKroVs*6*;k^9J}_TYpz(B2vwxhQ|xs=dtgt=q%WW*m(~B&N*x(ixT~)wJ4WWXQ{rU zI_Pn$ymF+qD89NV-l{{nA9kb9#+hMpQ1R53LbRMo0paiARE9C2|Fu;WeMw zi4Z|H5(HTAh))Ix|Hx@kCvX zC8}4cUavY!^)}Uc8?4p*Np+#>)1vEeV`IlcZp`bH&J$5}?87G_VwyD(Z@_N_kI+z7 zb8Z%`%~H#3hC*$&6GyH$Qw zH0LJKnwxu+&V#HQZOu*DK}IaG=B5`qCo#EC5G(is`vtLZPbQY5vmgzzg2UJ^I1BgH z4*$Nl8CTLArD?cw(}^CVy0+@Es_UzcR^3wdIMpwxo}ju564*`acj$H=&Jb$Z^Xtm2 zS%TyMMrHGO`#fSul2-ngb=n1<1v3d z`~P!1P6_`R5AO};whr0ATD6fNXoy_Fv+&wTyo!*GoX2-2JU9bGsUNx~>#Z5sfLv+4 z4PKjw!w4a4rzT+jCiYt}0jD-OTG@&xpz>x%tJZFOE}--DHl~)~>&q;7be0wTV}xyH z)FDVBJjSxN%(7#LRXPPlQo0y{X~b$o3eu1v*oh*+PY6tBKDiSyDxLXUn20Uu%;%4Z zC?H$kE0d4cq=)Adx5w(SH#%o9>ZgbmjKY2akEbofd~_D9My%j_>=*n9_wV`I{R`vD zE=$z?U!Z!G>f5SQRl7~L>Tgv2i0UkBm-NX61EGI;k{LM%w+T?`Mr~btq%Vv2S0+5^VtMFpEXp?Urw8$pHV$kbr;bb z=)NDU^7mC|s~)I2NA*b6d8%VY^L)4Oh}j-{7dq;<`G!vC;bv0Ha5t72uJ6y*aQ}-IRBwwX@poZf0`NiV%jdO`ePQ2x6*70nMY9UH<9u#-AS68Ixu&>4O|5`7US z7=t81Jn{vp@H);aypU^v5U*oQ6T(hI+`D5S2YoKn6>MrD(bfxoaKuAd62$~xLu-~x|-8gHBQU@ zEnUAvKWph{O7x4CenqrwrsmdWdP}vh>b|Ojo-oU8Mg($y=5C9k-+4I`sAcB1l%2UJ zZDw94R8pOsuNW6c@^fElT~M_&QP7FdY@>XjIZd)^`z=TOXHIq zNB!1$bUIITG4;bHDl5dAsP@Rn;ShSDNboTNbBSSy6ih-!F3(_dWVhkb$vB(h2MUmiJ z1pY#7MkHa|KL=ZW;Ub-$gS*13bI|Trz6twpjx|NM&^L#df3@d6nE8{`56j&53oG;C z*#9d#iH7@G;%jsk#3NR)1pCkO6tKQb$ZQR{wajD$e`$sEMCUxVZiraHQ`j$f1@7kv zUd{`6IWJ)6f=O`yjhKthf^QK^*fQgB;5Ux*L_8{=CojaKi?ApjQ_l17sD=jz>PIaD z-Bu>6hT z#M<776|};BK?k^BCO9y`V8jZ>W4~Yy+^-OPpCaJ<6vB3R9u8b#)C==aIiI{W4_!$9 zXeTzGwI0EKK~uOF5YM2qAPBL75Pq6N41oLZ#0YdIJZ23mStod59YEj()V+8rTRnbRjo5R68y zU>3Zt5#J)@8uw8qLpX=b)sWlEtXSSjD$ zd5N@TA*S5qCDPu759XgwEjuo&O#X2duzd`fAn7x!V^Wk@! zNJSW7+r0?Mw`E!up+I78B3IB8UU!L45h932f?zIk z1u5{l$BwoqqW3)xFFO(Qh367+O88eIyo))Dt_Ue+ZEqwL^IdbRCDvd=G4mz|_ade9 z;QCR^;L2uK=xGgZ75x5TpWiRRz<;FAB}f)tSb_rK-6d%LFZ-;9uz%U7FOmdLBL81@ z-Fd0ib+p-an?97zU5}@JSl2;ytgiPh#i;+-$C;(rBD}d2cS#qwxq%+Mbv!qcf7{H> z;NMs07V+=@5a{CJ@BaBRtJg%U*NK$Qy{@5tSg+Z2tzK^|!vPl$xfXY~F=%acws~}G z-FW$fQMyq}l$~W3)z{mK5|91TdL`T|c)Vy^w;Ww6c)Vacx*Su4h0Ae(SdyNzALuQcbSyV^YI(? z!$uO+)*1;fk1H{`wn!4Zj(oxU@N*@GB1{mAB*8-D6SmZE(cI0Wl`ZRA^d?*9e*0jD zwv|?gd&^E;kkw%)WVkWf2own>BG69EM}= zb95Fwhgd-;>=*Qedo|)CbS6AL=e;Vq;StfpiWh|hx^26XaH<*;Je~ya>g1&)^sesF zs`G7Dm**kf`Kyw73ay!JEqazNS_9ElS?+JWsJ*V*H^9;nqWL11Wo`1Yl+KH~oLUyO z>>Ou>TiIPsM)Mj>=T0&PlDrU3s=={5ihMx}_&JES2orQil3*b61<~;HAmR~5*pgQx z*@JPuUyTCc!PRK)NuFJefx??CCwXGe_hhSj@T*C*M3~??B-QkgpD*MRZT^??;1DKL z%McEf*(PycSwlFKf_Amo#q|`7BKdYOqZWg9N0A@`fwhS_h$L*OYp|s@>z-JHyCknb z0_(8!X+#S65rrTIMT9NsJG6VmqgCI7{PD7^KqsB?YpNquS6*wC&r|)h>MYfLR9{gY zrJ7G)G*^5P_CMm`-})fk&MS9~T86#9%&_xftYNo;UtK2K0bzo7kW|;h-)~^5wHt!< z1#P(M9;#zS^Hxo^d29NmIh4+QZlabx9S0u#EI50L)#u+Vm%Ux0-4N!*&YK}g@HFxT zuforp=!q~vIFbZkB3}>>KOau*s&yFX!)4gK4#~pZ>rfy(u@24ak-xKC_&3W*zRAe1 z$JRCB_b3s7Fu^NG67)d6;3N1wMhrukU;>f^vye~NmaIqf#~E(zdJGh%tw*wO+j;CuIm?0)eE z3~b17Yd0WSxMKqfghw}^c_T89<-%JmC*|f(Bet#qzs7_Q!URo`B;d^-L09-SA=s;c zy$VJmUoZ)NO^I0uBWw#dBDpDpuiS_N;iipf-i+M25d(!kvs{?Ra^Ve@`C zktC>(d_hb2H7D95Oz1Ro+_FcN-G5EBt50Fnq>@+K5K!KmMFLh}~nkxdvVytWC+ zBwzRPTd+2V+LCCFFhOf130_9N;4S#IB0>=+7=$Fjc;pLa!_S|+tlEr${*1b9Gm?de zH={uK+h#NmApc}J$%#!0U@K4L3m%1EYoZCl1kWHz@B;D$yqDC5=#DT!ZzKsKkS`bu zzbA<}gb}u-X-IyOeQZrbf$(q|nmX`(5@1OZ4Av_rmt zTj?2M0Kx=cAW6WjB$y7rXJs|hG4NSNU6YPv;f{0^2!BjR^S0!1mJ83bTzHG+B(DVh z0vUxb;ew};BFl$1^7s{UG;F)4%OpT*Ht}N zwXfv_PE>tN^(xgDRi{!*|HdtKq-%wWnbrui zRM%9!Pjx-j*{U0<&Qbl8>O9pitG=Q-Sasn}H?x1Ew>s`a(Wi{tHmYEv?X2b(QV92UL5h?xebf>R{DDs(Yz^OLeH~Fx3N8 zPZAx)GhKu_7HEZ$s*_bmtKOqJM)e`pajNrF&r^Lvb)sq`%No!s)itQ2cLc zUG+1nvs8Cgy-)Q=sW->AseV^=uUpZG|6mO;QFSxbt5ioltBzE4 zbX1+Ly1VKu)uF2QsUD&_TlHksIjU!=&Qtx3>MNFh%Scg2p;p+Y`i|-&s*SzY9=M^} zuG+TK8lgk=BS`4LcUi6Jc7DgxlUm;K{8Z*$mg8InL;g!ZQ3qakt=Nfn9eF*qX(vVr z_wK|N;V(OJSNI3ZUm=TGPVy2n;}u>-HQ2=@_~txOFJd~VUaq>oXl`_0P4WxXjZ{xp z9iV!F>LArAszX($m*^kONqNiIUE(;bM~doxs?Vw(p!#>!;i_+|j!^A_j8{2}HFrNa zi_cKYEM}LPMWbd#a~31v^%}1&XCQ>IE!&OxuW_={cjJ`sr`_=GW@`K^FXjM@Xaf&uXAOhh3>Fc%4gEol!(0^(GOD5J3bI-t_Pf{A!=Ie^%*!nJb$6Wuz|03f0l7Q&q=c z$EzMqTYpd4&s+fO&#%-ns-tB_mDk!DRegkXW9O}qAZUwR!5i=jCO$-nU#@mBAwExk{AysqeESfVMXU<@ocPO26h@_SrPL#2h6F(fas>n7)r%O55WzGg5VnN}ajF;N ze0LDuA>`JB=pEwGD&+7%YZ$)mtmFJw(HusiZj9emuTuTD>QvPgf3oVQtM*WxWo@L# zD4nO_1!|dwlVzqMbhoe5SYfhP7BfhbE9f6EKoT|wvB5d)8(C&W>y6O-{2{R92i}2?| zxGTKG^7qMqSpL38tH7FvttkxBDXcG=Q@Bs3q=o8i)z7NtZsoDo<|Rt!DGH;OWKWez zHg&a??8?Jv_W`@#c^IRFrw(I_@aAFMCHd{cz)%jR5h4X`ks;s*_=3+7*q0-W$;PO@ zY_dEXTZG?dTjDf;aKOAH_gnKFh;ATD?@^m^HPbx_9cS z9-z9Z>S)!^i{{iD+1BCO5ncm%=esA}&QlgiEmL-;%#;OPu%>M5F^n3>G!7rbmVq9v zyv}Oa01bOvbr9+g!N-g1kEfd~x*$O`pA)j(Ch9QBljX#c4pR%(#$Kf4L zetR6fh3UsJUwDA!!m}*@jQo@3ByT+>e8woXkt=8nuR+992odlVT<{ih1^wYQm>7u= z!Zzgu<_~6^g(q-Im~sN%5&SeM;{>{pt@oXHa5OilWi)wZM^mwq`Rd2JiV=*?4J7yg zexI|G=#v=uIfH+563N0XCs80gc@oWskbknApxhNRUbI^)h?u*KN>!;sf z*de+W(|^v|Cr4HLsxB1GeH3ghu>I77Q_`4PrsTIWQxg1~H6`yO=?f+?2>FC9>J*xf zV8Sy`VW2SS6q1Emr%)g~!Sa#h6_yL{v7F>xnBa9J3Eo5g7!Uu> zpPsQMELtaQtm-(`(?oLuqjkdKRVS)W7R?EauqH5r()j@Vjanw~LYWB+3b!V(J~F;! zGVM?#=#0RzM1MpQwy0mQWh@6Z_ZQq1uKxw?qR8xDFiLoZ739_>W3v1 zI>Acl8TgH7XI&5`;07f;!}F|PcCw3|S#$-}4#JT;`}A(?#X2iAA) z^a}OEI?bMFb?SFcKh{$H47?_?_fHTa7>)$OHt`%zO=M>a&cS;UnR*Vrg}csS{v^JI zIKm*#ofc6`r!X?u80X7o-75%fTU;A7-Y_UP7T#BUGAT15S@SP@gKSb4vp zcMNm6{u}0#e4~*Y!)SHj6-zWhh~QZy#4`44=O2tch+1M_E|X{BR4exS^YEU+*gMao zxA5qB%omBrR)4M zUB}I`x;}OR$y3?Il?x~k{(AwPasL~D)I%r;5VJiH0UA*PG{W-7m+Mn zco7BDJzBYMxoGXnRBK=EqjX-a8`P4@?`2X6SZ<~AEFx#HlOD(*Y@c7k-5Cr%{Sw;6 zkt;4?lyKK2Y!O~$ImvYhoXJ)V5h>uW8U?-hQ%S}cc^U0yv2NUDj1nea#+F&!N82wy znAvq|$?R&G%p9w&%=j(U*^JtgKdY3?uJC7-j5hlU?h4mlLAyER!7CUgEMPgwQ*6;3 zwra+oRuUcg(@KJ$e-pNe`M5imb(iI%T|AkYk5R(Y`Pd>XVmZm{s6eolAAdGU@Y@=K z_fbUHCKaIFJl0)TfKkE&1=u1iD8Su$yi_rM=W_5C%l10fcUv5ydD=*~&SQ^LIxo*l z)G`Uz%S=LWx-|*Wzhiy^!_WL3r-aLYhxdGP$M5JZJjin4NtO!>SiXR~#d1=9IkAAr zKf)h65{>vnN1_FP=t#6dg5YK3F61qpu2-$Z2YOkF_fb7Yb-3t?eCO4{DjzMH1IyBD zvPr7&?PJJd3Bg=JJ zS-#YxRaEsqteL)}6H`aEVf`${cwDtzbyL+3TB<`-*H!(A>Ux&;HioLh zS1U|X-N?G1F^AH5Wzwl-(r%WSG~IhlRS>ty(1y3Va&k|8r~dK) z0GInZw~W42M&B-@D}Vf8d*3qJ{2#JA#edZ-k1FlZd>W@yg^$Yw7*a-$E2F2E(M!tc zjb-#!(G}Psvj6os{L=k_+Xk3VLa16YG45sb6J>Na)yVtLUueLt63Wy)8V(OIey&2C=0pInVkAMB=C8QsCurTgY>)yQ-4^snz; zGQZo)RNGrpEx_iv-J^0zwRz!YZQQMozH(;=`*8jt0tH*-m}aD<2HDj4~!dKu5KEi z6_;7&i8xZ3?n?5QxKCWrE~f0m*Q7%EXT^!Peyrz;@_q1Gab6GUgHMNBSFSS3KNyaI z(=JZ+Ec;+M>972Q;iNJj4EIU-{?hnNIKT34@Of}m@xm<6KIL;M|4=vy&xgW&|ByI* z3Y&AzknRa8=Xd6FglWQpTsi zRmBKDZi>gZ`@B;wB=|hIx3PVJ=j8H5d??&9K7!k`O}U~pJ{fN8LptL_;XKnmZDzN- zplhP%t#a)!bctt~C&S6i@yT#$4~ceandgM^A^1GF>S>FYdzO9T-v1SL=5bM#?f*Xv zGJysnuFQb42rh|Ysab|%NvSF7Q(7(<_Nb+a!DCvQ3Z{~pxFvqvATTjpz}*oQ#MGxG z%_Ynw7u>Z3+%Pxn_qk^7d2wL;KEFTo{XX|O_jNDl%wf)%IoHU9{<_WeEeu-a735g$ zbBk+j-W=dOY!kb-%B##_BMXzo_g*R>AToiP6kllQWLBb&TF)Az^1W3JIN+WCCHYb}(WGFM7tXYt?aHKX#zENOwj zGv*umps^8d>#(88o~C62|COU`I%Z}h2}Aa1i)6SQ#i z>5LOs9J|#7XWV?=w#?|@Rg;;uuT@F^Db0at;hMva7r%Hl1nVgNns)=mtplNeYxF|b}@VEx3v2HOI?dmIRgj<2{5 ziKWXm$n~G6_HtrVlK3mUHh;t#aW}nN@%g=U!7n%}I0vU<;yPLj9%D$ccc8aR0kY zvr@4X?zg;K8UC4qj<>v9@**sTi~JFy6hRvt67)d1;6sGmCgKn!n1Uq1BIF7(P%OxU z?;YYedI~OK5@C4w6|(Pm2efvb%4y@h5WjIot**F{p2oE5;+$GPPHii3PHozHqt*dV zcR851S!AEuk#rf%pSsBiZ_XdeMz_1x=En<;@JT%4GENbOzo(-5Jr0eZG~Q!rAfL!1 z+G2^|EgTT=32VV{G%F*nhqsNvWGo#3T zw&Vu4zgg;oSN`_y5Y%#dMgP0gtM)%FQqyK($=}?4i;+tNr|N3ts2YFiMqJdJ&&f=O z@d4X%LE8sx%M-&Mcn7xjOSDaK+83Nk7u^D1g<;`r-y9l99j$h#1NwTLvAb&N<8$>OWH6d+QS~%qCRd58pHn)5sE&7 zj+i2N8yf}h;eucUYCR@CN9V`v%ha!JM?*M|hPmSGYU2$?Eme6_dKPBNra3IKcl#7w zx_whOPx&!SP>G`wya}A15N**~5P>0re__60F!l&O#cjbP_?LSJR-Zk?){T$XAhp!n z6s*tlv6JhnPEq(YK5#YzbIQ3-Y9hCskpfUGcnQ8wxo^9nGZFOO%!)pbrC0598u#}$ z%zVm<2aqE;%V!IDa23yl=^yWwhH|F$AbB{C|A%WEW3_;fz6yFIyP5b~56Q3a|1rrU z`2VcrCH#L$@&W#znf#Fd??N*tQ(&Kivupz##d$s@&Up^!+}=>$h5kr+G~M`(ZJWnGt4)h_yHDez`85z` zV4r;vBM3!`pfe5${)KYEzY*e0j6sxOI+6rSkt@hXv0yKJs}aAWXEjq`*!9`Ak;ii6 zPsKU%1dinSB%ALmHEJg1MfAqXZ{9O%ZIHzfL2t0gKFVmij8fnAv<#lYP$rG8N01AV zhrWWNm`)gOCSjY4sioncBwQu=VySE7+9rrFngY9Znq%uo2^)-5ev2NZ{0@DD@_Y2L z%J0(?l|P^_z($4(PGyn3vpeWjJG)_>rahd4M@Dv}I+{Jljx<1jK`>@M#~synZbg81 z=v4#wt=F`Lxbd7Rkk5a*yK;WE=xQ8RHA-~5Hgtog)kI%cQ!97hdFm9xq8BiqMf{{= zkKkS07JLYQIjCdNM-Y!Gf;reINWlfcI@GF8Y)5Coe#8lmBb}&mUd0dJtfAG5rT~x4 z{DBr#mL_E_Shj^v0jM&+EgHVtWD2OpGA9hF!AS0yFYv}5K@;2-w1fZiL{)H)m zC~Opbf(wFp)N&{0ptHNFLvZT+ido!Ams!-$$&u}v#ylM>+_@W!I4U*k!^wjPKx@H^ z7~)|HtlmX3Wf=KlO|zbvTKCc=$%s)2GD>xG-TNm^%VxQpr^R>RlteoWx0*Z>|5$)m zYw}3Ewtx>tl6MwhsqpCn6p;K|_OK@RYi;;?a=$j>OVWNQh0$dU`nGQUqG^*c%#-ow zB3Y1%{emo%3GxtBi#UwFgyHwkfc0n`HKuZ(Ba&Y2+>CU(g3ApGY4q&eKcR2S)8H za_`lf*D4;R^vxLdX( zF34GzprfHm&T&iEJ&ivV5`~!hj2Md)!DJi~e2en>d?lpo>gTEY`r#d6mZpDz!40g( zUs40stc_fOFNy_C;OkAaK~F(vOcF#QOAv*#f=}UYBBmnDWD0bjx7aoUE#0W4AcjRj z>sVx;;{$Y=<2$-R9O=Rz&A?U(QU_NA4N=!jG)08qMT`}6LWZCRjtlz3#fKPlnc5c#Ge?1D8X4*elF+z}tB?6|D7OcZVK`tMKWgEYxVn7h5 z^inEj3Gb$22g&DiZ*VogVdWi61fZLs4aN()@Yz_Nl-~W0gXT#ofhV6~%BRuel+U0~ zQ9hf#KzSNHU3orzgE&uI@AIUz8~#l=Nk6m5K1rA9GD-Ro=g%@|jrlMxJJSwJ1k4*C zV8&L#Xf$ie7yrbxiZDy)66T?P;uadT(`lI1lmow+h8-lc9NcKi2sPo|jPOA>K~szu zFi(TvZJZJegj;ihsj>ude1Ml=rb@va91x`9pOUX1!nvFkDMV zHW^f&UeQhS3de5xWg2*nD`NIdJYdVdujomwm9_yr*7YR1z@YWPl~#;29Cbs9FAyR48e;{^kRiy#ae)Oc zt=U+?O0;XuMv7KqxUh637771ZiT{#3RLi&-&sjk)5*^T2&>PbQA7QKDOI#7mM%|Z) z<%kfh$5_JfQwCPO#BgUa@Vl@$1I9KIJ_GGY9uULYaO;Lh7Bt0vL1&Z+dLyVU@d5f0 z?w_x+{i)wjY|v(6ep|jR{((hue%O*>)HaFpWmCjMe~)sFcXy7j!s)g=8ZNNRz8fFY z<)GD1UcRd{^CtSYV}rfWNAPb<5lp~F!5my@$J6V|A1cE9NUs`3b9dINq4UeE;fuJJ zO@Z<4GTAYn07I7;LG<%^fu{)%1VvVE4c)wbb1(H&x;OtI4$^9W zd>j{Kz$J{~^VgzX7{i}hi{ZlCYq5yr71e&O<{h;%L2CqcB;G(@K|f3vjKEd_UkQRF z)a^v9L zJeWoHJu{sy2VS{u&m?qp)(Wz)gAom9vhZg(PZ+m!b?Rl?>O9reNn;)6obAlMeuD7= z=AslVz$pP!0lm%v?8?TguQTj#*%&FjnvJExzq3(5$~UyQ8P9sn-XKEJU%($@c!O6R zeUU{359jrzz4zbHrT6-tXg!^^!|QSX4TinA9>HBC{Ce~wc~YI;g#rDsRq!&d2)d(g z1QCUZ2(}W75k#x0ya2VgvW8x@m3h6LwNjQ_uNZneSg(*Kp`9 z{%z^8siNXIx>PjqOE$csvEJbJ`_Ng--Gr81IUT=l!eHUaO_(Emvb=cwGn>bo!V_CC?rr&Ny#-6j zAZ=?!GtKBS6)w7FdNZ-hr?~JoBc`HO4_^DN<5sdKV`n*|=2qSU;1+vSSpv&ixtRQG z&ST;4s*rBo<+5S1DobP8r)_u`u&f%KdNO=nv=%hM5J3mb7er!@AR4y?aqy2M;?ak2 zpS#W0k%YO<+IL8jH74W=TA^6b5x%{MUg#-^#w0-uvIG-wRxktZy-lq=mRM||{8F8@ zA1vtJn={4y9210+pM&JRj8nZ$fdLJ9vmw}^X}|U1n`3eA=V|`zU6g0;q!5hdD^v78N zuh!lnc(o>2h#10!EBnc)VSMUvr3B%Go zXgHL?Gxs1;n6n3yg$MT_TlmKwoD<&I1CL>3*&cKx`P4OtWKO_(UxrAZMK9r1N)SvdD zVGQ}(K12$O_F=NHbRV*X5BA|4$;)u}(X7qmNf3${K}VzrcsvREp+iAit z)2Mx3PcErJq#(KD}6+m;dv4`LFSwvG_u|m(Am~ z#a!@HE0)vcL2}tBjsCjwmGlA1GwGw0ucId_-#}lYd<#8O`F8qt<-6zw%Jb<(KgHV` z+sB2QYQ@j=$I1`VYy526<_Nu+@=R&$# zxJ9=+zP{XdEetJI2E z`ex;y(esplK`&4~k$y^f0{y!3Y4iumXV9PHCm1rjv+3T-=g~uyFQkXXtA)i}=%IW$ zy}$A_`UvGK=@XS_(&sB*N6%Egfxb=o7Wx6@+v#VO@1mC~kI(0V@u01z`{;qnf2Oxr zevtl_@+0(rD=(yfqWmO%lJYb3Im(OZDatR?*D1eF|M8%tt>F~ilF%IiFe=M4?D(10suD)*r$EBB+P zDsN2BRNj=nTX_rmugXK|7nHZ5-&5Y6?)j^2Ft5=A#pOYQa4vLKE4tA8D(_1FP4nNarpI4U3!}JDqCA#fuKY84&BL}{e?f1o zd?NiN$F z>VCmLTP+YFcnxC(k;o7X#c@F#T*ebq(UveQIfCKiO#$(%kFfWyeD}(~Mg_`;(r=1$ z`qS8(a^)-Ob@?HmlxNZdly9KFq&%PA$?i}2vbDS6Ijz6)ee~frZ>s&wh5x7(2kDcQ zAED1sUTAm@-<5iM2Q6iReJXP4G8G>BsTfs_Uyz8Iz;W`en1FA^1pItN@Ge5WG<66b zd8{JLEV_iLsSA@9TTLrChB;sI{lOo{kS8oXh7ywRg?uM6k`H$rDenaXc27exhq^2Lr1ur3FGSL-Lf`Ld9j6tqo z7K#Z&Y9SiNvv(T{5h>hTh{?j^g~%3OE5teB--Ylg<&X_?27n!tv(9>=f3-N*4%Sa=*Qr;s;}V=&2! z)TAlwek0@x+M-y{4ZdFy1JP6P2_^|9AWJY8X9>f~-{CQpw+}3QEMJb-Q5?XY-_em} zLBFuf-oFyM^slzAf1cZ_X{|ARDx-yCt6%`G2u7psG$H{Jgkix6jGM-;t~!BL(@X*N zx1X>z70agfi*v3n+mFO!EU>p(Mwd40=-Le3T}^8b-{}nhCVC3`VUpluWC?gjfiNVU zghwLVTz(QAg=T5o9FEv=?K zI)z0utbN%(gROg`Owa^DGl|#GSMWBb3kGAW;4@qiOhesSd|}Mjr5D(wQVZ1AwV`P) z+TGI_H;ZjJBV!h8df~XBFjt}7wrReQjhYRbOSB&bJ3W;WG*|x zELeg#xXt4TXPx7N$sEbba~LVybq-5~znw#Y@EV`{7yfe&&F6EZwfW<(tQ~@xf)0F8 zndpZbf-&%3z>u@gqx%9@S#_SzE0ep$@24fmE^7;@hxk=fF*)( z91t)mw_q5WEi?tb7+++YwP^11#ma}$zgM0>&k^TrhH`fDi!ga1_y19r*{7w9F8klC zo0bg`F4`;DzmP4xjWV`Wci;tElyF8Fqr8iCj)N1pXb<*1U4r@OgLQS$u3o_CWRC6D z1*8i9xqx3ue#lUs%titbvWRGdD8ZXZ61<8Me_e$sm3(p)-AUfw8=uO)F_X7|Uq=wU!{3V~{*6}z$`A!r5fbfOcw33~B|UWuVtO&BI# z$LVy|TzDPTSCH%Yq`q+fb&M3AxQ?YO_~ox_*KJdBgj4cJc_H2HhHZNMR`W_ic{n{7 z#Va^HZCPZWp22jPoID1jVmS2X`51gC`7TG6fG+kN_(zWb)-bLGV6WxDc$p7BN1mWqMSVMYT z=l0gy$K0m;Ca$uKr_Z{XoRVgU$mGki4S!aaXSa^U6^#s~S8XJ%$VJOwxdap6RE)e# zHgu^NCBoaqXt$t|P` z*WALd!X3BpG>hNAJ8;XkXP>uy7d_}4m+kFVzik^yQ(e3BN?f$w7?I7EhVsW<+0umD zD9C2SdAIRM_`_{9Ur+vc8v}%ew=qlj=WXmD-UVVG8iRa?02$};>e%rAp+D|w*|?MNP`!?tqkMo1R4 z$9})-8`-*C~sv$N8EGkz;Y4wdbA8PV< z@oc~w8Hn4?hC+}oXpf_UH{g^*^h0X_e}SE-5%WO3`b|bO3NiT`L(N8Q>I3|kV`^Dr zo?7YWZ$z&WZ~vOT{rSd571D8-Z`D0mma59;u`HgQFvd1EYS|C))eciY)ON0vj~x@f zGipDHbIcR@zU7$m1o}ng)981V&!CqppG`MDwAGzQudRHcb?#dEa?w6_UFb4*t@Lvj zWYlJ`+&XtbMtsnP{bpIJD$8ftr(yhJa5Vo|Z&ZcR!5F-mlgy%@>~(`#wE>nkA4IWkWu_Imj*jm@edE9gg%cYNW?B;Ve z9xR)$$~H*I?zXZOs_Y2MWT)2*Z_4jBsX{sqhjBxe{iwkG5dziRnPNT zcu^J7(Mv-5y29*>`Th!X@OUBE+3&>c>@`KiT#$F@DSn0x9& z<;&@xC{Lr0QNEHsRe2^oMfo~hUUqu`-17OV9{mKb=JQoMZQNt5b*%5!JKeV|u{tTV3h#62(d9SX* zb)6eVS9H$D=I+v=_B!va^N}{MZfWtH`3L9t>ay+ZvDO$?U##;Cop00m0iB=M`5m3R zjH`%QN9RF0Z#^!uVx!Kw6+Lwxt@ANDpQ!UW%8^#XyxBIU`=3i_%{mw5I&btvMfn># z|JddpG9Qz5<;gnFwz`vbo2@$EXLIZP{qaTfiZNZ%t+=IgZMrc+8PMGWA!YXs+Bq1#Q zpGiWv-kKz&KL%!+{VP3`Y+bcJ)BL4FsbmWAbi&-GW;32oW}bwX61_fl*y?{K4zUJz zNE~7&A|WL#)M)i9@V0 zo}DGOh&9eyi@8eT5bMUzP8?!g#l#^V7`Vec-*KWH5{Foua7-Lxjq`sb4zaHL zABjV(>z|!C#JcL)i9=-7GZKebigXSvfLacRd=|T>hzj4?*mVJlK?vCTM{I4t` z){v4##KJ5hZ7OF}u+6JqTf^MrJ%)RKk8bt;vBB~8#{pKCoFK54$_&|5q+Gl)idU#G~X*4t*@A0cIbj6583RBgaWUjmd6ENgIwY9w|S?-X0WFbnS^GSUF-d@ z?t%FkU2sSxVx1d@R3cI;sYJefMhHnDVqpT2PS0M)uk!t4KI+&#rVaUQYqF2uGip6M zb%?bO4yi*dx1D`zRh~bVGe|I; zZ-}CT3ijUp>w7-y6T8n|qwnF%|NG|5-E7eO;NE-AoH;Z1+?g|TXU@0x$;W%Y_;~M& zh73qoN+sccZ~RYI){#$coluf7<}mz?8CmZ04fpX6$E_#5R_a!P5r>Wxmgf6LjMAbb zM;`9;jTt@)OeF8Bw^}XhBKzH>$*CVh>o%q84s7e?vkUIZ?W5H3Yf+R>sZ|%)tCGj3 zUJ43-t9C%*(xWUb0bbe+^6c**@t#tyE0k*cnL3v3q(tL7WXV@*{e|S+Av~0mQUcy> zrAEo^5V8$<5SC#V}Vi|=f{R0YZb=cT4LoxQO7wf9PDfD^pyNq{?S(9 zu19-SW?1LjF7F9_>zbRIHXJ%F(zd3(xy5euo@RY*f9YLiEs6bawKd3vjBnVd=VeFN zB-b~!k2tKlT_rC9^X^`*6qJo3t%qP(YjkhrhOkwh+*W^b1X8X~K~2`Yzo#-G$?d9Z z?pWRsQOO-pH5M|x%AjexCbi~X!$3dmNl#gVCw4?yb#-HXlS)~L+-F9U0*Z{9^(qDB zTW2N(T$*lCDT{@6gKpo@5@}N@M=^g=ppUMTdMCMhVMkM>s;RwogVMT_J?@m_Aag0Q zG_}?=tz@QSc&}27!#b8SC`q}axVfaoqG%yAD6L?HCo|$3h6+&8jy`>sr9{yjBKq!D*4L_(THIgscF`GW zs%@^TZ(6BR>L`>H;9a+^jI_7n4pqtuFfUFDl#$ueVVEnyd^jmE6wLajwKWa(b=4xh zN(?s~31rZCDrGgKpG*pj2D7oIrJ;FUq*bM?$piO|Eq-@ zx|gWlcskYd1?=NwU~6HtZU`RLm=G^*5z%+HqJ*j%SlCowl$Ku1%(NKaO(S1#LqCbgwb zfxr?fE=l&l+!>!`;U?QW>m8jdYtX+u8$d=;hQ-vcJts?QlGah;IR*Ldf(~_IrUy?W zbDZd46J@-l+kdy(U7(#vVqn1oBOv39n(+fw-rUD?HdNk|rJ%0O zb50MP=l0OK$3w*EGN!H#jQAIyV}P#yU3%$x26|)^jtou4k>sxjeTimF<%fZtqdT9Zm_WYTA|O zPNx7<=N&>PYdehd+zX9wQDeHxvl|*)MB|k*40s-r;+0n=8jsP=WzXoR zc>zfeK+KwMd0xi#e?;sRQwXK3>7G}S@-IqNr+Z#kDrde(z2Q_v_ejs*o!ZpZwAYMK zo_`?2t!$vAM=H;oLPw>`R(t*lO}$Wnddc%HE+g5zv{>ik+#XC5axRu)-gk;=Y+I>3 z|6+n3r{JY>j%EJiJRjh4O%5&tnVyf7%8lgWy3O-3b9!rP+w0e&k$pn9;9V1qpf7#O z?(J=CZm(~KTlkDUlUde#KF4Fs^R7laMKk>ZM5A}LG_Zezc-gyJw}mfZ5FZjc+S{4` zE08VT)(GbV%JVg-9p1?LmgY84-++3omXA0`KWO2ZTSvi6}V(@ z1^3bX=H;tvtM%BTkWgPo*?$yjE)J1e%v$=B_gh+hTaD@)!sWg2ahUN`%~gE|DdlzP ziGbH5s@ftA$kg1btmLWl=R;%&a&JvOV$rOo_Q*=yPrqGYyaC2han8Nqd|i0NqWPx4 z^h&5*UBm*@r)J@&C^Zme>qbj%kztQi15pFA`y~5t(Krz0V?Zw+l^168N3&j9Ic!&y`dTIDYqU5ZJ`wxG-F&=ZttOx`T@?{JDhoFy$#BXQJB}-a3bg( z3D&dBxQMOS?JdV#d{o-H`Z^feJJ!j&DpJ34RlD*Yo}d63q7mgChYS{PBY%{Bifmlz z-pQcXr!}|Muf)LXoq}vXunxM5cq=Fj*Px#t<-KSR`7?00N1#its5cMZm4|1Se{&CW zpg*Y0d_1OtKH%3o54EGU!Pvc^6lI-?drT^-UXE743Gq7T4essNv@>oscb>|30+|qkMX8d>8jY1#^k1)CYQ^`cn^7rg{i{o>Lt?~ zYF4%>S1}rTafQFNxxJ=6Qa8P|xp68gqKfhK)Yta)V}jnVU6uuN_-oKwVG_2N;u$*i zgE7U{*V_)uodc0niZn$cb#2q?+gciGHmKs+6mnS@_?2JJZ)YrGA*y(eB&11}bq;&3 zR$6-nHW3iJS#7y_z0bF$6dXGIqs>*(t?GX_;Hg3(LXJCLawi(z>FiHnOOFLqlYQDn6PbE-QzLt&w)j!77_O z&^n8k>b$>~<6iB;v3Y|aR16`!C>R?Sx8aGM7Psk07L-iUz=}Xq^1Eg*)`LfYdhLhF(yQ;RuR)1BTXGg*R-*F z6=QZpzOD({;*$EvI<>%uzV9!=(=MojJp9LsR=)idZ)5{cD${LhIqs?siZLAoFOZ97 z*4Ba7hPBjCdm2qu!k(bp@c3d(Bq=ooQY^ZnV|{%?eGOg(i#MUD0NyO8F-e+f z@p){eNr9Ph)<{*18Da5)q`+LX=OY#!E%iLB5JN@K^9K|7Z;;#7y{Z|{zNuZC%zvX) zBbT*OZ~HO%Vyz02?6z^)QM42vO2lhV``pNi_L&$M{kJGJ1pOgs_zUT4bi%EYP=+$Jh%%oX*KhPtY{dJazh+l5by!pK!?QKfk`cs2Fkftp~dG&(8hnE!~5 zM&-W~!$Mfh+7MZbX|*5IIxGVW9iN~3UoqtJ=GMAMtK8U5s<*4h=jUt}yS1^QO9}TN z<92)Nc(1kHzI}YY7ZP(=?T*&A=GKL9a&5|gpB^{yrYD!R%_ehq~>51Wve3r}_;X60hNO5n#(G!osU0SW8m>HB|$X?rIHTEMD{tf=W|XrHR5GnElcr~SW) zA=e|-er;yfaOMAxJc?7nsd3uXA{e~}3k3fELjPgOfsK}UPk)KsZ({Co>1ac<8Yxgv z%qDcb_LbNz;#IAYnz{w8^=s)81B+4QWA-BxgA<4Pt5?<6)nV8VtbkF`#})g2 z^}?z}RSTC?O&g&CD}}GUawNrfB_v`eqn>St=@Cuy1ClS7bM zGPxYb3ntTF?wDLOAM*XR+M1S@X&X3v1lCGjv=gtctFObnt0mGjzZK?y#|^BLBK z)8G*snrl^Hy)GqxN>M&^X6RJ7(m9b0;wu9u>-5D_{Pgl!lCDiTziDnwM^o)86*yH? z>mi`J8HLi9!OsRx(|PZhl8;(HJB6dj_fvfHpeG-CO3)V?1Mrx594@+WdYp=umIi0^ zpBsQX8}wCz+d*GyMUOT%JVvR(f45Jl$esx2(g)20@8HH`1&)*E%SO|PQO98~6LzLJ zroi#KJKtTAUACI;smL@E8KVN#s2W^`PYeGTIFYWx{{-is7>ZQjOsOM1JtVbr2wJ`M8QGU6dUYVJX z85uhoR#-6SinL0tf*2~$=qFd^Y0;QyCcgct;9E)^ezlB#@UuL0MfdOegvaTBoC$X0v?8?J^QRSOqvfVBdvjA{(W+()Lr-ae z$EIaL;LT}19DmhEZ&hI~g!N>suDO<@6CL{VTKtGA>T9fGuh>+j`@ZhWdZseHp`&e; z^1rMlAE_#Y%zIk?Ko$Fb!Sr1E3Ox&Jk2JQxQ_!pVU)S>Urqk`Ln$B6<=INBbeR=_o z&rUDJ@w@4I-pRh_uZy&_uhL_O^5ZGsE{Dw+44I`f3PR8iFX-~OHllGyI$9P)n)EWP z|2+!2XhD}h_P;AEZ;Bu9=E%Ee256OIYn$uq+A8?wE$?vt{aVsL(_aJ` zxI~v9K5Ai)LFywda^g%H=G2)19JkM;gM5DGpgd&4s0YQEFxQ#Mu>W(Nq3Non4p-AxtN+ zs*XlmP^Dib&ai!RywMW0-^P0Ba;^}Z;i!jjuttUg)MEyyddy2P;i=)=CKQweJwln$ zEEE!+Zqzjmm>xB8wAN;S`=$Er0Ed(WKyXrjq(wubIuFoc&PJkWp5 z$)&}yzN-8UoMA-j^aLn0L?;iJ>tkQYWAbv0B5USUsn9T;G-EC&<_&Z6IWd}Sl$$Pa78*Fz&LaNy0hZCc&d?tY~e;t7AAPBga zVLae5cO?ZD(K>pH79J|fa+7r%9#g<}Ynp8sW-7nf-_*=Smq?QymBKJncl&LkpH*R4 z3a#qXBj}h?=NAvf6KC7h4W3Ig%%B@)^SY);-P8>Wnp=))QDGPf*%r^Icj=fE5er!8;sqf#NKTG)y9*E2h4$xk zNa0`ZOIS(L!zL%pDp-!kQ|{>#yb3q?C0dxZF36WdOb1jN77%LJ$Q&Vv*Cknj#bltZ zt)mrLZD?yjdsN7dH=nT+_1=IAF1bbwsj!EE5f`(DHWj>9crMCRvev=v(1;x@H`e7U zq~oaIb*K$Gn};g#elm8W)Cg})cvY$B%7_N>p2YVUR~pwAbz2JFCWEW42i_#c?oF$U zG_=<&RYAPP$byh&9HWAF3&SN6$EqOSWhkNZK8C!%#`8XOaNfOOM7g9C&y07Cc;*){ z>@QD47m}&R6R0s}K`ITqknONm6?{{j3O*_Kmz3r##Hk=gR^D>5*&zr%&3k1jc&o03 zKjTY9@EK$3C=K%lXBgc@aRk+mi}Q~WD)@?HA<`pN@KvGRD%gjUlW`eX4TkZQe&ly} z@jMhCU-_3_^iG*qXxmTpw$-*aH#8i*DuUO=AT7J`1TWW%XUIL_orBi)HrBV*##yk# z*k3hE>549w0l|;Xq&<%5P$i?4ny}iBJ+TJenM%gsE->aS^0JL<&yVHClR6@1!dZfL ziu9I6{;^2c?tXbkeM9@KCRK7clT5eLQ;WsTRqI=7n(9=^I7z}tjpd;9Td?3$GF~hC z_ab(+w8fV_k@3{o;#YOt6Yw=T{c0x=BK zSlPnD1K(mxrb=Ob$*ikyZLcS@Qs;VgaW-Z%NqY9vhWRC4rP&8cs&s0XPL;V%ecNKp zb{godOJ?ZQLypSl6idH!IL&5+Dw(AdYmV|QUd_RF)I)`frp?t($W_`8#=Rl#L-l&> zUbh9`G~orTHY=+T&1nN$=c;es5<9wN zK-6t?E>UWd8#yj9IzellyTWa&nmZcmDp$d%$|4)ySiM$;!%Y0&UW$nWI*Lv`21@#& zltEY~Ro1a6^BjnLOLC;LjuYBSQo0rs&P!3MKjR%H6~j$hqm#ST5WDL(zdiZrUc*?( zqu`?9bK7vzH>REkq@Gr#sV8W!%RcF7Z!IihwTD;KV^C&`v5=B?DtOxlaR!SaQ(3=* zLOU3mW7JAP>Upw8iv|s#ZElZ%CxhW zX3S|mL>>np8f}*}>kxS!WYBm?%MNL3MpLrLnA{9T^P!vy;GNa7e9-%bHbnl}!($u5 z)_D7_r72O=I4K6(qj#HphDkxe% z&w6P5rlJ++)88?}icxKm_Kp_ukW!O7sAK;ac~=$Iovd5}M^8E}46YN-k}BWDOEu1F zS!i;{Fqs)gwwb&K&m(y!2-s@s#G&vjR+G{6 z4>bWM#sq?C?q!y>0ncd4ULJO$6AO0|sAqY21BzV8;JOHkHckfTV|tA#xab7;xa~OH zV7-IH_bX6(*m@_0dQm2kop@INledp7g=P*%li9@bI|B`&e| zAD1x!_Hr#@&PQ<3&Wpd}f?hJ%wDzA)(q}p;-99ps zQK0j_sRcINYXqicYXLU}^7)!EEky*Lbp)zJdByPs-Z4_{1Se^oPD)kNVz14yG7EI} zl~RG99GP3SOcpC&G?Mx+7bVLafp@e(A4iFnc|l~H7@w-XS|*!HY~KmJyuV9&yU|fK zxo1W2QlzR56`6EL<|HlCTU&yKRMlvK4R1IC+qHnUguU~GUO5*@`nyj0D>~i7N)%uQ zqN*N|63#aQ(=9E~PnVztz84LjI|9SCKwk>jQ>uIA_$2*TC%syy>jz!HInDI>Qo?19 zz*a4gsjF}p1x^=%J&wQ=T0qw^pFMQ?E)jUu5%^gP*xy$dOEYGPz;}+o`C4EAH00RZPwbU*s!m6Mo;2hckLYw4(+l_rX51wL znU25@TA)7#^7#;Fd?*41Mqp-03)ude!kjEg8tNo1)k(dzavE>uOc9vk2yE5@eRb`w zt?89>ilonU(jV68Zmoc}o4G>-mO298Yk@RfI}SiI_lrQC5ttR!0=92?VNRwbwKz#f z>m=QR3rDge&YB?-7dsN?X^BE;&n_Ivt~Bdpk+{Q=*w?MYesy_D_MMXcqLcoe6n|u0 zPT@#eZ`KDQ@Uan?9nb>2LlnUlIy*xozH%g%XbIW~613v%=_28@(b=1{L|7!)24`>3 z5*yr(j=fq!--!K6ZA#7^l0Mu?|5m5xiU!(o_P<18fsvR~q9yuKqF^MO;+%mZ(cnlN zr6uem>k4zKB0F(}r<7edigui{UL?+PBqTmnOV}^hrR3Z$=@&Wa-)IdfqJf5- z^S(%2WhCbMwS+cP!6+JX?f{Xv!I4-j6P5aFKn`m%)!QA~?z@r@v%`^8k5eOO$^U}4z0PSdeD|%(kQzF1;z#(|v_$oC$ zRx#7^V^p0t+^$|xkp6GWnxVHARA4^m-@7)ixIUv218K#6J-Q<&{!)rml3dM0l6t2a zt2|BZqedcl7oB`^H5Rg4F@w;%Zo*q*pLB9&^vrk)14||43gpybzR39)H@1ZRu@emp z_K&#p@dKIAzP!1n zwayXE9QUW(s#x`tRu&#k<~{MNeX$SrXSS8&Dv3!)%a)3^>)Rn znbylZ4tmQ7%&alHM2NWZ{RwYK>?FUHfm&p@#IH`VA3HU}+QDP=0p`K$GD5hV!n5D_ z6W+hbI}*WNajE|t%*p9R&QVyGab$Al|ABKXIg2*59X*dhZkSHytci2t*{=8_>qfF1 zf!s(BY6By&MsYOCJtrPV2I3!yQDC5dW5^e#@_9P23m4%dqVcdUkmU(6T_9)01G+%8 z#KX2g+~fpf;rc#wxPv0GFgFilj~1Irs25@*YA}aZc@v!YDO}HSf~PQ@#zg*zMbj|r z$MPv77{E9~f~0VDMUSv3FdlH?pm6@ubk(+ZO%8FGoAy}=iqHdpZm#qHeQWL&%VW+JIoocGUP{R_m_)V@0#XRb5nY34jY&NJRO=iAMBy*Xo%i}_|`=yOy}-!F{m zc=Ke!^wZ24uV|VskaN}7=KPR3pKs2`oAVGkPy5ZBpE2i4%(>Q_F@vDqX&CkLrl7@F zzAlW)>&zJ@4?>`FzB!LJXTO}MeuiNT=~F*4XRO(3`Z06fWX^vzXXw-EYs`6>IWNUI zN=4HR1J6VYhRwM|&J{nJ^S5%Iyw{xfn6uBEVJYUH1k3633^`AH#hhO-=X1>YOr?q_ zI5E{QddXRtJ5Yb!wegB02K*V4YS;eT=UD-bn;Jc8L;`Ng=ktviKK!uJqkX>7BZnV8 z(mwLe;|3gls?vWOJ#sFy_uV<)y2b9hW4^WCK7PmK0Vko({ChN0&bQci?kFF4_fbNn zV8r6zh!bPO3#?rGk>p*Rc{J@2mafuEUFlc-kKCFV{gPRr}a zoR3@Q-%6w5BKvD-XsZ@3Uo`mlV|}-VIWGUe|E&;yzMRxwPD)JgW8bwiYoK?fBp#h2 z=gSjh#wVx7(wCqbE%XccLrc(q-=SCW?-qO5-Q@%CH>vNS$@1^8_1(olh3)H=J8)}@ zq%ANq15W9d`RH!H_w!aspCTu<3f(Lj*N@tT_mt2@sWVOL2PXAdlX{~4`>t|3^Zt?cihGOn`F?%&*+1Po9JJ4#b|23p?VIi^$|{2^ z%b8)s{7D+XD|;XWI`wa2KX`YaVQNABKlFbMu(__Jn%6ykma7ZT2QbYEcI1gc)++nLCk`RrQUR%%5#^$D0$B42 z@Ka`i_Y(g1p3Z}EyUFN=Y90y7?fwkMRGr|wlJzRP2e}ggny-TP%>2_n}Hc-ea1JF!E8bF{+uaPpk0h+u;DW}z7 zHjkwY_hjAfWw;_dFWMB5m&BCgny4r<<@o(Z5qDZrP9WvfRs%Fy1J*@b>3gJVEBzTj z^L`}uIk!*B@xZM=)Yf6DZn}RWT2rWz&U$El#Nf|oYchqdxSm!&UqYU*mA(&)+wZwH41q>CkvINGM}OB zDZ7v@;}l#1)j28KQ4uvNvi8AXo{c>;oNhF9qdIwSh@Qu8Fco>u{DnH-#3f*z_s4af z(?jREJ#=nzbQ0AmH!G-4xsIbc2_vFq460K|pgP~QFy?!<%tB!qAygT#&Y~RWX14Yy zc$-u3INq9V3KrvBER>)+6RL5EsfNm=a?hoYv7BdNPM|tZl5$x76+H^N(iB8kCsCcI zq&TWmDi5Pkk>{F0(34S%OQ1UcFJAY*^-y`eqtc){9hE?JMuGCY(WrD_okFIlOse(V zd@4(rg&P2>GnngG=k^{Y+~JfUs7|K<2h}MwP@Pocx%WM4{2340<%#ZYkE`6%L*)ZT zWtKMhgGQwo{Gqr)YVqtn6go08b<262m_upMPZ)g~)hWJTP@QrORA;7s{!d4l{d`mn zuuee5P4?$ac9qE_&kOq~H35YH)%m};)GKi*CV5`{h*D1=L$2rbMP5hO8%|XWs?(`W zT~r6sc>X~@$rdVsG@dtwPFI;!<@skSG-U=^z`OOh%;u$)aT?OnJ?~u>FXnxx7(sP1 z0ZQTLPGEkDdp>B!WzK85f*;lAq5b9R-v2SPcEdX97IeIh=Tmm?Zd4~bX0CoDpR=pP zQJrkhaa1Q8qJ!#WlSx2z@^N>gI`5(ByJ4L)z60x|i5*lY4H-vuUIRj9@(w&d+=}ZY zmurQF>m{4DxwPXry-9?5UYSQ{e;tl-nCA`t6H zO}M$q3>a4#eT4KS^Ok$8OJ=4GM-z)fJF|LWE*NFSO!P*&yWhTZ6RV?2nqa4N_u$^w z_F%i+4WQj_3Nw2I&`5W-`^g?cNJs#Arn_^hK4$vuIKW^)dFsVYbU&axS+By%8G_wR z_x3F)gp~pE?8huLFF>CC4WU(jrwNY$;Ak_=s*-K;hZ^4XE1B= zs^+$K9Y9i$%clX5P;#*jJu2`D?MwDQfX7vkCk>zsp{?!*rR8yXH@&RT^O-Iz-q^a~ zrA4LJ7Bo<)JE=I1FD)vgJPHTT!Iu^dGOaC1x3;3ernRxNoDS&}I@Vut5l~5%ftu=R z`M_eVukq!ji}iZap1eOVWg>XE_v-!Ll(qUYcK5kf&Prc@c01N35q|2g99N=Ls0OIS z_Qi<4){n)%jGjg!twRY|%=v30t@H3xGydZxouS!@>B@gXmwjM=fz@SuKP<$t{KFC) zkNuFGbsv`Dxc$SDG|4=WnTa4x_D8zxFFy<$KI3jfvH9m&S$+L0MU+8*A&o^%_OI%) zkNe0!LJ}A#7($enL9qH)3!6cOp+v;1e@&Nt=SSW=NhW$Kw5|p%!O7RyWq(%O!lAOWncYqut4YR z$2jFsecKYjmFV{Bzo5&0PZ#s^$Hh@8fWev}G))Iw>ff4BFnYX>r%%7EB+VDZqvi8O z2Dmjrm-;upfW|Kk%79D#rweO1+E_QZ)PIJwfCZYnd~JPX=sLgw&lK)ba3$(V`OhLS zIw^1>SO#qB|Lbe^BcJ4yifjuK5}>92bA-J<$v*;Z(SPo1_V1tM4L%G?k^|>j5H>JU z|9Na}$$^Wyc_Wp7+bp}{)7)H^`G=be-0*^Z(x*95DPVY#KOX~R;3gr*Li39H);1u7 zoQ;&g%}d6x>Qj)E2pbLD!hj}%o`fHVjRtO&1R5m~HX681%Ai?R)UWQwjRtO)1R4kS z(i>_T)fu=$ra!AB0Z=DyT?FnNtUUuwCa}@K4v||A4q-?uTZsr37*pV`@%Bld8I2c9KgH^N0V zYa`l?2KHWS-}N~L4Lk+>KoJED@+$D_4Ew#$i*RcPJ})=T7*L1boi3LY-n2>IFYvo}vB z#|IG&4^0lvdDDLQi@d&{RFFTM)tFEkv$k59$)Ux6w-0;~OrJ6YUE4u~hE{ah!~dO= zE!|VQKL`IAf@3=V-?{mcM2uoc0GbB>8Cu>n>)^^$cuZkctd)q*f%BCY4(C|3Zt32F6{l%MG$bRLbXpoPW+;S)(q7NZ#g7k zR|(D!o$(o(Xi}ig)K15dhK!@7e}JS$YlhB}`qDeF84Fr71ZVrzH{Q8S(?Ds=U^QGB z3uue5IMobTd+3}z)KI%ub`EJG>DzrC8Zn`BXfQ?ioOkUbzs=0QCEg>jw32}13~%bP zH-4Lw;}{R+#c`bB%`@yB-{wZejnRhka8!7Uj1tCt;S2scnfFW&%hx>>e(R-4WYDul z92{r(ZE;B$75vA-IfdU98Y6DXW%Je>dp(Gd;}2WIu&>t-RpZFvekU=D;5deZ}kkNG6C}+ zcn%Y!@3SGf`}?BtBB`fI>zZ5Fv;jpzv=Txg0xwD$5lJC~xtkiPZElP(Y$xzim!19t zyK~tOoP$0!;AxGvc8e1OHZ=Psv3u>BxTnW6_^TI-`B_g{z&KL|H)@&gG5b+>#~vKxNl4W0LsAICd>Vy@?YqNDlb zrvQ$rKMyjwfO$o(*JdKuXK>3u=N=w6rYnSBQ32RwI_C}2YXV=y&FRA9*W*lOP3vXb&rJaRyr8ej}fP%U?+jG15epl**YV;f( zm!o;3y~pvPr6mUrL)-@(l`0LuxShFKqEI(^0|qS(b=lu^W}Eq^9Y35hp;++WZ{(?9t&AQgE{>^J$Yj5~11USdFzxj>lD}#(+ zKuf*i3x|Uv7|_x@PDwDrP{v?DOY=qd6!0_#w6s8GC^Nyp^uzqpRcWC(-38zpOlWD5 zu$F=aOlSo`p{2!Kroqso#a60PpVVO$=x$JGsb6xofa^4f(vhdx8~>9TWo;71g>F!2 zS@yw3D9e$W;{CX~8x&fWE6VYPEJdm^uW)=UPDZ}6AwOt~(pq|6RyI_0O&-oSR6YbY zR)b+H%X@PioO2IQXqlOT5at^KK9iV=vVtyq;eYuq+3{b;^Rm(ER$gX&D#7ZZ9-z=N zA9~(@>3R46m-8U&fa6y9D?=fB-~629vLHO z^8_rb9*!0p-YWBw9`ModHemwQ2%wIJkB04b-6q^w$Ka(Xe2FZ@q-UK->QbR{vnoi% zKDDd=mmQU{q9F7(QIhfu4`2NgNP(t?uaU=@h)fM% zD?E1`nHt{C4N=U!6OgIl>xyRUY1qItJsXfF5WZe+D>I9$Ea4ki5*A^k7Osh=7B1G} z=A%H0fo}QKp48<`Nw72I09nJgarS_6McW40pF# z(Q+`V;d>mrYD?ZLR?CGAqp0wGLgtAP@0S7#Sipn)AyO&ep&kY7J-C2MG&cN<(~NXO zcuvaiLzBP68Jv{&vePC7BO88YaK0|zS=$f4Dh|n*{{I})4;~x7uwydTxdk#CzUuYy zATW_v;hWgXx*@aS9emzBAhY2;d}uuov*E}1;50n;5C<|Fet~8Z$ZYrx+Q_Sa2d`Z( zB2Lqj(SLNrHd2gqY5T%4#WJ>w;B?7P@VuVj7>KPiNb48E6*WL^)-5h@(8Ix* zl8Ip8GCG~$EZju0Fz=O`bwwGOlk4uPxk$(YJ*9%1QUc*A~SBy{yn!B1V(9KDzEuLDFu9=IbF$l1N(8 zZ-J&EzOPVf_*F^Je!wb1dZj~ylOBI-U+7gozW2( zsx_u|qTHI>eLU`P>`L6C^^9d%J8@fw;}H;BOaIDiVrv=9G0tFXDKoAcTRWpNs?_*# z0&~xYr@O7J zeAYlJa~ChwWD5ah%Br)hPh)qx(eNLcfhQ|Qsnspz^Yg?q7yi9*-t^FCJ#N8Ov5H*mexp3 z9v(~gSh>A9)~6$>S=MZg3{au@^nsRDC_e!V z^if%VRWutOm;1JI$!UguVUXQphv`nM)vw9@m6>*>t<~c$a*cxmOky0RtZ)*woUJPeo!wU#rYI zYxgC6t>XtA%GhsqF|K{GMW{t7j^|_&L%$M0X-CHV#Q@$j1Tv05TgSjOJQYTT#hC_{ z#!xQ}2SYjs1}>=Mk}kxFfn@v_uQe=P0ShNj7-28L&6wahIu37!8m6?a2O-MaOuF(71l>^q;8X`Q4`ix@*h zWx$?I#cw3aauTCN{=j5xkYUF0W(*-Yn0IKb$!}#_?fNu`VI-80eOXb@K%j$p`(lp) zqGtV5pQ4P_p+q;@gH#S;F;;~v5y12*nm}@j zX2MrE-HAiX7z`qjDO}u51evj)AvA@n9SlOD8`D@bzFl-jpYY8&0cyrbk9gcklz}0{ zY3c8ga30`XbKl+x7~znK>w|D-j2k&9zJnvSgF9n@Mm(^C<6RHf85il08b#p7lln3t zQiHE}4(^Qc6;8AT!yBAy1Ww>udq2iGm`lb(nBWLTQkYAwUt0wI-q~+eRv` z!kdk2ZiOUZ(zv0fN1phsbq3b$;|uoO26PrW)oEDU>|WaB+d={+jSEfjr6eva8BE$j z?gKcOw0FnxTDMKT=)xTZXSamAfjuy36HrrUpOG_iG;6*5)F=~YtGZmImev)oAb-?{gi*&oVS_tdFH%nnxvmD=VMc{4Wpkq*HntYG3K0V&Xzgv znJVc!&G`s(o^H-Dj4-Ugg}Xl)XRULM7<(#5A?(e&FizsmoS8?tp`EDi;j-l5Y`U69+H}oflKHbm<41JBEGccC*OUGv;+N8XNqzj@-?J)u? zjKF0^;9@PH)N>~Nc0+$|=*JEHqoLn2bm}@O;5$R-7`k_gSmY2x7m<#lM$ei8`4bT| z+2KZDF=?dda(<4#Rzsg?=<|(yg^|DBq~BuFKQZZZP5N&p{aKSfxHo(i3p~yURDeNx zy`lMA7NoZry4lc|8TxEPUuEd44SlPj`GYXbf4`w$GW4^C{-ig?Dhj-07{42V_Y9ro z76soMdYGZR3|(bt_j<9=@rKScbcdnG8hVSN=NtM)H=aK$&}bO@jKEoj{=1>iGxXPn zwhi4YRq|hF=t4t3Yv?hC{?yR(4BchuNYpU;ZIC-S&Cq#nEae@3h(`o+PZ7o*_V(?Pu2;5exnBtGYQnHag?c3>hOw#EK6e}mO$;vAn%49wl#~| z3zk6bkd^S*Fji%&AS7RQ_tqcM^BlK|RmB@Zn+5>x&NNfV;gff5oRS`UGb@99;5`xO57p2P!wN{ozdkQR|yZr8tX zOw|d_3rerD+mJsIr1dOl0H}^U0(VEykOpaOK}Npbf{yC1=n116q$PABNQ?R9D|(-> zgoGELlqJbX!&mf{UMgjDgS2>)QckM_(xQys~hdY@}Ab&4*EzQhtfZOBhPTtQG|o(63A5>*FpdMyLpnb zm#`}P^Md|)LLdAEyosje$OtjEUG0ZJQ` z_$=P=g<$mKqHRAmyM83m_{ea(DBRbgW<5FC!u_FsY`7vzCZx!4yRHP0!e>V-=n{a> zVgW4Q&~6u>=Rx?aF0$lBxp(cy$k2_?x`C8=UG5$E(NgIL0kqEERsRe=u{RPfM8mQc zX;{`Jc(Zn3Svxb(G!kH0U8oJ4o4~Tph9uW%8u8|xI%yGP*+RNuS$R;bzp}R!H7n!79y&KUItj^=8x=^FT*o0< zeY6eYkSrkq$$EmV!Ly|Tg=Gvtl>y1h&T(#LYmb7rIR%G#YqlxaK(d4qNLE5ME-}?m znN;q%^Z}Mbe+Niby_Cc9ujot%u6%9hC-> z<*0NZSw^J;$r3US$!cc_!*BzDWEJE(*15e$33oUp2qeoXz=3254M-N%c<%i>HSWiQ zCM2sNu5wQgl@Az|S=!(a8kGi;6<0_tp1q~e;Xtx(i|c#B=+lra@$>@8lIw0r);eZi zj;aBY^=dr(^Cr8>WRmBF`zU1~S--@kUWrQyB zi@l2dmOGgI(w@)&Q&N@ZpB6M3NLCFl4J2z3((s|Zi{iz+?-V1DEGEcMwuJd9?)hLP zE^}_iB|fxQqaj(k_kYZ+-HGf2l27aLfrG(SH{smd2@XO;O~6sQYe3~nXfUuWqZ^^muIE^b_`;bx-E%#} z5@A`RKyx^V!?H$63_!xS_0sz`LI|Z9Se9#G@0Y;vRY_J$CmpotmY$i>cQW3B;zEdo z(%;?7NR`IvLNF0_(#&`FGCZaUlN)>RuU1-yX~PayizL3dmle%SD}z5yz-G}UqH+#2 z3*X(_m{_nX;U;yuYf$f44>rEh4BG9YFtZbyh41g}?IDDOgayBJS58&*T?$-}1FYs? zvotiT!I)Z5PWS*{7FOo;2l$wUHs%NT*C4PYKN~&pgKETJyunt`ISKbN=!(*^j2}Wz`>TMrnrs9ixTyFGL5p|Ux zol}(f1S3sr>sy%7u{B)vVu=2e^rziVw z#B<5dljoet&kNim%}iskG7CJrd+FjYJ=e-QUNX6ox-nOUWxJ&?@Epul;ULp$1ann5 zSV;X%zat@?@;=(iv$#mWT)AC)0kO(SbrqEzK#H#lD68yLcX9d{yyL5^HFw75Y{o`bXRKwj zRWMAXU=s91XSLYZMvEa5Fb<;fZGN!?@gW*Sh3@HfbG`D-EFo%LE``XHP){|js7!H=fN%{UNQlr62{3xIAY~eG0J^?x9 zJ4e_P1a{*)SIF3yEmmgP`&#)l`ZLzX*S(QKBW62Fy z#;)CB)s7|lv<60(4m?1`T$x%r*geq@L~jfHZ4qv;^HRLQN9K+`0`rAlrS zm9$RcSN2M77d}k{tLcS!jg~68gZ+yiv~tWzv{cERC3>J3OZ@_uD%l}|6TmqbE>&{Z zqp@o*u(Io=5Sj`E3BDL`?`^T73$2{h;wt7sq`eit1}LbFlKX{Cyh9vpRkFJpD@FWPp93UOC41zC zmdZ0PdEhnOFqi298Qck<8L6XVD|v8t?Ai;h?EE_2Q0pMk6Kz$pHx_&KLMu0O|7aG{ z00D!0DEalp*ntb-LY|A|T?EJQbZo*!*!e#IIp@=R>=dCt16;YDM^nORW&l?OzW%(2 zgwa`Vw+BXc`&m6u1V)*Gg4NVJ{DIkzPGr5(<<{Cz^qgg}w=c5t`h=%2L4T3&<4d<% zIj+-C1irsl91TW39}Gv}K(2x-q;E4EIGFGezTisXGpar4fUttAgh?O=G|0!9u&Sbh z^^(AtykHMpR&ceXFfb1(k=O%Ut)g<_@uNlLAqd;~uvM@@k{G2IbnsaM-3m5##`>8&^BvOu?X^`6TxcjR~I+yooIfTBG}RyJ87HtUz@gBA!NC08v>v@W1nq9OjT#B zw`~>WiULBmaDxtHE4a2ZHW8`DYxgttaK6zOTratZj15-f`+EG*ooV%eJ2chfV`0G! zlB@@V9`LT<$(^w~Z9Rm%V(Ss;E8EH~)Z$5u;SZwswb!ni&o5lk%?JO|8S`JP$D`R7 zTfTv!m=Lenq2%1fOaJonb2^h~j9FSc@XZS7XvY^dE3ui&xI#a;mfEF#^Q z&4qCd((P1mnXog(c?FLbG8a+;3eYgI;0c`6^3!|{+kAGXT6&vLKwiNUOJcJw!I-)$ z)^Lec7`P#QT&La*Z_}Ayk^;}^J*byS6rr~4MD|P!Y!v#IsAD~~sbFPg|zSPPZ zN@FH;OAYl3ol`T8c5oqQ{1+8M=Vrw=UTS%xd`QwCkJi6pfPfo(sxNe&V_}pQ2Y!V% zb5hPu>O3rX=;in_N$7lW(!O|t3T=^*FleB37d)stKD{{KGgauVX=Ft4N!tW4Sm znEIoBY$a|N--O(*2+RrxWT0Lyf7+vocM5?ULAza?F<=hiK)p&Heh2O?=s>+n9+AeY zJ%m8Ldf}5Wk9NkcidkMWE7A@j@k4$kk9WpiiCIPHgx|!h;-S*4b$54QUL{WnlMtC; z9OhN>bZ6}F%Pb!<9xJC)F0%?vCuW##u>0$NCC_)pc3!3ndF3)IA6dSHteM5=4xjLW zzmk{H(Jt4s!O55FJSSYPoy1=*$FCqtRTz~UWOye~p!~>R$?Nbamup}2{N;KE`L*Qf zdxh@XgRjt2$Awo|L8E~k7dI3C)L+Tlov{nAKp0hL>_Oxyl5${6SMcDE{gu4e8T;u9 z?Zxu0)CL%TW!(S4hq{7)_{3ky{?6E$S6cpYaZ9>_2Y=(Q#)jf#o+&;ii6Sv!tur70EBU-L)_j$=;FhZ_uQ)Y+;L8<6 z$Wg*)s8z|Aov|mb((~zmUuBJg-lD6mvcsh!mx@OO)=%u3tM#*Z;A-pzb;drq+8SmW27zF~ZXj66&z-Ts*XZ((yaw(`l(Rdd zxpM;RcJXyGn3 z)=V+AkAEvL92UNG8o`T&OEpj9#e#`=v2dAA(0H+6H(o3}NV7FwESQKF3lA3MdaN;c zF*m{BDmVMe|}D|U4^qH zsgE7~tuQ&9Gb(o3cFP|Xx0wlfhC<`Bb6(*PQ6)gKaGp#T3n*iNWZ`@%*$18ml7$OI zdk~CnAX&IjoH&tJ21phz64p?#Fo($@kStuxg(ZGnkYX!U*jEype_i~QhX^(YITjw7 zG=`%1xFFXyXod8GVh?MRFzR#z$x5>iHc@F#w~4xeWTm-MExhI%AX%yRxmCJWM4TCL zSm}^;+Tb*oo^X~96=nMCf_y{?K(f-jWf=AF$QjUOzAjjrFOOK7ya35c3-E6GH|-Fc z{$>@MNekPv?j@zgov~~G1|Uag?18^&PxdyXK>bIk{Oh&LnS8yt;p??aIrVy-;nM51 z+6S(;LdIVZ2&NlbsWfc?f|c^-djP>gLJ|!5s zE*sU7PYH%@9y-CP(Jk)-e3cyy-71YY;X8t%+hjb~mAGpaatMfOsS53M)~3vN1VeY5 zr6~ty6}m?lI`4xwB<6kS;Jkamh@xik?+AwWC1id)6;qA)$NfT2Jfv^!Ae>a_Nx8YC zEUqkto)XHzNrj${8@L-M6?!JY#4klTq3JH=W#=(*x-&wBUU7^g%j}_7g?6j5KA{Ua zIWl;t&{a$Etn~VK=q5h(Zah?I2Onb(JXB~8AA`n2Epfn4p~q_%_7}n5)n>;(F3NS*TfM{fia!2jW=6f({c2WfbG5RZwLm;J7f3WZ265R*5iPK za0(obSS^2>sb{t#cV=eGd^lc5>%#)0ekk^^fBR7gkW z7soLg$+rRnQ-w*86Q&NW`dfj4N?{V@6s(PdoC4D{TZ5c}2_UCHmF8=Z6V~Clz&t)u zH&O+riyA$vO8A^$V21GZQklUzIZ&s-%+A;aw<2`6Gj`*x@b$E;+r{y>8{p(B>o*VV zxbutyoZ7(^fK!L=#YzB9Lc{@1%sXfUnybalXY8%;fIsV>Q}8?d0?3)g>!htJI@tNF zU_NOVk`3ZX``)eYA^L>_fTtRkxOEvS%lGaW1svQ}2a^)KNy^c(d{ zxEBHS2LYh6xi7F3SussV*h%8o1sjn+dFu!34iQk)nJ9e&WJnSeMLNbzsL#kLScT;_ z{9lmgP)2{?SFVP)VgU;%DR$UbA@%^+_v37pPK{Ucz{(1g-(AZCrj~>M0GASLxf9V+ z^o<`v;UV2lVTNpNlLXRD|J57t=h_X zIpsPP_l|OwG~&aOz^BPGD(?nIabsr>GLB9FN9i$PYx>xp*eEvmq>ja76W~#Jb-4rc z1xZ;pvKtJ=T8!-pgknKS9WzIwa~T{Ii^2UIh11~^aSs{?wFf!J3FJq6US1Oi#h8f^ z1_wo%5#2bbD9t&3gy5jqf2fsPO@~+EQsbbApc{c#@Hh^N(~}ARq`}S@iX0;x92DzB z!6O)C1EdA3IPoXS4b#@NtWi{Da8UZXChCYEYVPQ8h)m-45jTkrkK>@uVoq7>&@(9O zPSzrUBLI&btdP|0E?%l`SQJN=jmh|-bB|ICbFwbQ9hOJMT(!E9@TZ~6#b&h@jW!gF zDbFEO4v6j9EJ@Cr}9EvRbGk1w5iDSUT*}@B4W>a zcL<6cwu%x9z^`0B4dZX+dR#*CVTkW>iL~|3UnzMRC0_);>OCChp)ysU{!EHn6hQZ&c6%qTKi&q?y?F7e1&506Y)CiTm|Ppm$&=UzSb^l_holm7kCbx zJ6$P0rZ|?SGzCSnK*gj_a8AI|%n~dOW7XoY83#+l2%b2TQB45NFf0denHncUx52ei zuo=7KgsS~$uC)wf!4g8s7~-T!2@GRM5XnR=4ew5i%q0jhqPV{64% ze8AFF2#98foE{J?O}4?(_ytQ-FIXA|e^6NuEDg8!|G@lvH#3f<;oiRyjPptbOVc1& z8irm_Vxiu}(i;(q5gZ5e?h`D{tAeFrkOd{Wu{4Yp=*eNo1UcPU8b%THka4y;% zGQgLQgm?k&)W?GbqTJ1ohXl}@J6Ia-zdF18bi24dXj`AFhX-M4==B{e4R_SzJMr|H zJ+L%fcG^!7|(y7O)H_(|-iZaDj#jogX9Q9;dU#skn9LY=62-x)Vk!E@K+3 z4A+wruri-VF(uPpD-M=<5mT!8k|(!toTVVem-XuS%R6VD31At%OCwR%t@-k7Ug)`y z>MXQ!;W!a1gB97)4nuJ#rw3T(W4tjtdqkY6q1|e*%)BWvf5^&6YL|2DgvYU!nN%g? z0|!+-u-1Y>=Z};AZ*hd#6ZCWJ`9|DO175%Q#`wodT$A319H$T4F|id?SI!$-K(b?aGg6{HGp(XbK2!7%@d zMzUz}m^jgg8f2T4mm7x?CMO+%)~kf5`)@?%$o|GYORvcK1=5is#OWPK(IrIvWk$Va zeA3mR@K=AIDOgCX=jzQo9A*?qD(f*Su&?|D~LZzvx6A`n8ShFP>WZbul(rCI; zh(r%U?&gp;tc6Jr3L!5L;=Gq*!mb|KNu!}-o)GJ2o9v#(89m%d7gDCczS&4k%zkKl zkEQ)Bmx_eQjt1#4@|@F>&kn9!Ijp0;p?O8S(c(N;ejT~>Oc}BwjRg_gN;x2m$ZuO} zYU+Y*s~ehY+B%yhB?KBQ4b2@zV?bJ}A+@uIH4$9oLq3kikRy5u8|fKsX>T~2 zB3VBNHBs^2Nuq!Ro3*Z`b6I0ZSURDq1TsAeq3ISyD$PB@L%?{-o|?D_&0LjSQ`6MY zEE4A<`i2CrAUe24BqDvHt%`0Hi3^yvf$mt_8fq7b3n_YnH$~-19JJKTM@hKwl0>wFwN@2x zMMJGftVIFuVV$Ao+Lk)BpGd4DnFKGDx_w2cgW5_YE(h}}qckV&)Ta`>gAvrwyein( zP^X$wB-V3H4MzaUQ*DXFGZE)Nf_IckueGsdb*N1wqRFjqTf7gG`leuOXKO2Q8;NV| z%yG&aB4;(pj5#Rm4HoZHjyS2B(3%dBh)zx+&r-;$U|U0w8a{C~(!a~%eKnq2(-=Y< zuR$%nZ4AkE%C{rmH_3FWfg=|0`wp|(tnI4W@qaJ5% zhmd$1506s#2D&^Rm3)*XA6Jssp;g2|NWQJq|E`jQ`fBSD%^9vRf@(@0y=6bLLJ#U6_t72p4}bQHDSj+$njD}oqY_O&3xNJCQSxAwC+ zG(qX`*w-Q6{m>zTiOSzQR(e3yL-5-X#Gf3?|RY118CmaQ1}afN~TCrTA&jor`*bLGIqQCG@NPS|s!&B{Vb9emxRe$q8XPh)d^2olbIaO+&a{*l*G)C1bpHhJ^iQ&OF!J zO#3a+!9Zt7eXY(#b3VXEZXxl?P@weuGyDbr!7wciD;t0>pw ztoFYOk&(wK+}kaM`^*&TgB`+tznOr}^A4shsvgGKABM*FNMowiz8e~wS>t2fG(HY0 z+W*$rpU^5v^jrIr@d{JzPeI85QYcdF2k?9!D||*POkOSQ&ms^u+?rf3?9cJDO=U;e zpGSKFX8!Zj{UOP{z@!te+5CiAtt9w`|EiAg~i^`iI9|>ZhsRYACgo}s{I`y zGH0{YyJl9@h_wIB%uQXeBUmKte@BG7sDlzcLfGG9I?O}1#{NDuS&)Eu&3*`vwHfp% zDbJ_b>>q-26({qNnM_mr3Ss}40?bJ&b1}s~&3+inhD}QYg${{L4616ZRc5?4d_DOVxCNH7=?mvq%?~XXDX1OCHDsP0 zH)hq;C_XamxI5b?znj~#?9AF4Ttc;2qx2#9pOYKfgQAxoj}OA8 zVSQ6xC3+1I!igmduC~aIjnV-dC9bf{sjh792(3V7dp`um+h8n=avlcf>)bijbG7!= zGQ_UWBkieEwe|!x`8Zz5t(jBJ>j+z4JH+ltZp7T8>b`F>=+R{LF*B~{s26=xzzBn5 z6-bX`_3Z^-GZHK9>}Y|t3kBOl^IBROMOr_EWcl(DJOespUQI{KO3bkRlDMx~EqOI) zmQdTOP~Aw;4{56&8OI$V`XL9zO|iJ}(9{p
    >!9+?$>-$K(3)+{2e2a5X?a!}pT zMhg;a?>$JkE}F2QZac)9j%hUO>=>7-G^>)Lh0p*QHc;2aLcyQi*+Gj16`Wa);N1w$ zT2EyWmT=jO>5VP0J&p!cXfxH~ycW#7!sZ+XsbjFr&fye?s&B1uVxFaERdFon90Atz z6tSARrp;N5)p$|z>V`Vhw6nyFTOVpzQQsk)W8)McLO3LxM}pwhHa3KsJK9AKdbDcP1l6cH z1DQvQMfklqA42&hS<@ht4qkYyz zYj6ara5J`-{oKu1JkJWPU4&YIiPP#XQ|itw@#TDN?cJMFYiM88(B6PiGM_qA{^d$w zPe~@_JeLFv`B{JC`;s1EF!G4e6l(4~IoM94DjzEzY7~_vbU{i?%yVJPyIpAHoHEG6 zY%Fi1{Y?IP>et+pmZ5ZYXdJBYh~+@%YVX9pfZ9ytpN|2Fo>8c{W;+hLfVqRg#g4MB z1%exe@S$OcgSA4p>V+g_+%h(^02)dVP}de*Jv#`)vPR@z%qk|Remg$@5+!?RtTXIR z@J@s5D(;2(mr^H8@K!`wBSbz{bNO=;yjAF~bE;3~3~bDW+4s?syn9jIcf^WX+X6G+ z+@Y$*eJ5wYK^YMLaAV;_1rW5h0N|rZ-8tcmI8eqbO`(9PBZ^ta zCEwWDUOx@<6M9meaMO%-i*f(>Y$w8JA-uM;t-Ym<`dGVgKSK7x_+)%W31)_Q2*uvK zp%N7(+*sWCZcFek0JF0hQ#o`!M%hd7F6KsaW0jZVG=@#ca$w9Zg&f(%s)nWp(u`GJ z_GBYC!8rtGtR8`Fp%v5Gf-4rN&Ac1a%80B4ZzBR$b5py25n@mef}Lv`8XJObYpYSYLG0Jv|AU@U7Vmn=7SHW6QYSjXz0ol$n@Auh zpZdjZ%Fgi+P&;}LO&Hp~Dr@c;iTsi^M=Hye0rbqosu^Y=6`ZzEYrF8k4i#UO;7tRg zfs~h;xe=Z!AtszdqlXQxufT%2XhD5jC|EbItzi{eIqw2wWS{Z$MBk!;?wb0Bx;jkY z-sPxL3|nPhYvz|%m(O2RKCMW2S1@1M*c!dE^VTy{8Q7ZoVEfcis2PVK!i#wm26X%+ zC)o-snTE*ztujB+yHW*gn3M&hb!e&4;wYP3Q-?`;MMVSlu->ycLb6Kg=BuPL(c7jXES_A9q^_JyR&v+mJY3(HOm_S8 z$$3sF>Z=o<7Q$wxrB-;?s93pENOHmym4A#r1-F?b5-z;DcOkq@|416q<~HZAs%J3TULdlBf-0#gsn0g0v>exCNE4L7}gvx$dZ({ zwl@D|&s)ly7#2K&&^{_)xHcuDc8srs2&!uAjXfe-FHg-m4M$`Z%1U#!O~}KNXW%<= zgHat;`7jw2M|iOlT`>F50JPeo0g0m#tfxY4oGafZWc6#Kv@DYrEi@WC8k$1w9l@qn z;oFQ@KBJ|~5r$hqY_}bMSXP@Px`{WUlnV@G_?w{P*6i$Q@RhR;Ff7LQZApCKNwv(k%U^BL)G;y zn4z9iN_l+Og_eiVUtzPKSJ4hmb0OM))fG!r2O=j^z! zo=ao44+%DhLUrxaX=)Mf*Olbc<+NP-SjqoZPUAgqx`X7^`0WTawZc@8jdQ=F9HAm@yz9;yp+_xT>Y0uDz6Y$h;qOf1>2Q z74C76flai!>l*6jcblU=B@wGcuR&m_F}OBVH`lD}qbmA&6<#ECd&K};U#%EG3&#|d z99G434ehOnBivsq(LR+_T|+9Jxe!8?THV;;gxZz|YeUsEj|=zLO0KptU`5yHZ#-R@ zX{7!;Ez$k0;_t029E+H+fmXHdt6=j_Yd`n*B%#)yXqg(C-BK6Ck^S*ISAJaXAYrW0OM!n#yz#A1#6NnCI0fv07QP6nM+GeEGhY@Jf}?UBGzY{ ztFG7tC@Exw3thgcfk&y;4e&(rJ z&KGP%B{kFh=?^fUM@BPxR)_Ex5YKpEmIGz6sOc*RFAnI0@CM z^^|`Q>vMAVUei&DK3myd8cT363#b`o84T0PS>?h%L@BMT@}Yv7tFozr)Z)CkWqznN z6zrH)-Y)#utx|)~A{`YVj{31>B?hWeO*ONzaHr(N6hGD-qqCwG1hx)A!jI#g(Xi^Y zukUE+K=1J5jEEL2HgGW4l;fZUd!$ga4V8c+ldQ9i)Y*PH+88t2JrkBM4Pvl}RBcY4 zDjeXbRg3Uv!H8jHmqRk0%Q(SoPS6EjXG24s@aHI{x6Mwc8LklQj$j+!NCIV~ zbqSV=eq`VAGv*T|wLjKT$RNB^taTai}{uDD+5kS#tl1il%xmO0z=%erF`cVtP z02-NeIV{R}kIteltb1?(6;*tdySb&*hw&V0R&!hcHAPLyeYtryowo;2S?Gpe&LP{D zJU71|!l|38&L2Qg5IAA36M>87l4V*wm&{*8JwG;=Ovs_RG(P_~H#Zwmm1VANn%CHg zV+Rc5kO*);A32W_STxU1y^c1ys&fSfsvPy9wUxj>$16BcQWGw%wS^C7AqZP18URyLf)mGbC7$3t!~7VV@G+ntj0I7fF=;>Ns_ z)Vys?rlUjEYkYs@DOhCz`;U?*l3|KFf{TR@`yoCOQjAlC?*V35S>jaTdyp9_?$e0- z?`Yg7PmKGN8MjbrLuBkwNWF^u3Kj=TlQCF$z48n)yVK}1KO>BiBqWNK3d@saR>btb+h$*I-RkaJPNs5H;4IW4+kvdxTy~(sq_)=)W zGA`T~XS=8?p&IwEPSm`hhARHbiDAc!4OPqIo$a-4Esc#Q*N3pr^if5g=cL2m8CW=} zrl$IN!r9c&UK?eh)FuB`Ea9V!E>%M$Cm%yZS(53E+3KXoGYY$(dNjOHm}31#b-bv871R5lCG zSZ1pIjarW^XhF1KbDi*v;~>oS!j1YUpI1G%d48zf_#TOHVzH^G;o~VMz9AQ8 zL|0V}?F+E3Y9zbvnV~|5FH}>I+8UYtut<0+mC7V+U$L#lR#a_#l~*$uwM})3b|!!>ML4GMHpOwEvxx--YUwTHEU2zc zIIBc;xWa*c!*#D`s3avcvp$UfD}wEefWQnSVI1e$H(#io59VY z)!?kcK|gY5eH1Ua?P3V!e4yc6+;3LXP;Mb=I?7~1q9DKjkdjz;SkBrehX(aYxZsq{aeV!_Y2vj_tt&fgwr6YLxA_}hdSbupkNzSkELzOcOUck;otsrhIq7U=v(1U#M=CxZ z&AV!5-B0;2_MMs@KA&^5lX4@*$tGGGNm)nL!5sptRbgoqqAYbN)fED3b>I!eppFU# zbyUk^Xdufj5U7%=;|Igu$Yw43cY#)#awUh^mPol4Z8YVHi3p#v1EZay*p^HJ^*mkP zh9)awSP^6Dd6U68LZ)R39=gEYhW~fS4-j^!6bXo_C}1km{)!&l2<%A@SSDJt=mB+O zErTU5tu&rKt$(;4DU_mAC=(vAUh0XsJsnc%DxnDXBElki*n@`-dcc0zdND;21uIHb zH5B0a?H(2(&Kadxs0b>@ql#5huwpt6xkGJL!OrH|dLaj(lQ>k+1fzP1Go7D@la+yu zD%;Q#4g7KM-GEKD%NJ5{(b@r=wI6+gr|_?H=e zmkLie+;y4R6hFf8mzd!PRd@;&!8mq$kIa`i-1I0aPgda>NIxSRdn+;Re=N|U6_igj zGmw)xgo9GepcWO>Qxy(76H#8H1lGQ53f!UuROyxS^2=G^kSXvQD}TBsGiMYj*uyDY zW`_T+!h2H+*-GGhR`8`3m_C#hYzU=gqb?+XRo`ZLZ}0&xH1?9bSv1gs>GO)W6veileG1&%2J zh=0vXi* z)d;LCXMw9tflHJ?E(sXhmi5S7!{PUt;ZMdXpen4qmjzxm1-?@PJ=6%J5mNaP3mnw~ zGu=wSaM$K$_T`{&%%BA-sF%teRpHEOEMWG}nHMX8fXdyiwLLOdtMIipQ^6A|T;)E8 zYH;RXSzx#+@U0SXsN7Kv&is%C=4pXhE+t^N>T)wvIjGSLs#ZZgP`MeoBgwwaDr1Rr zOo@w>1ho$&$o|Y)#S$A$33hx{62_Z#iJA9s_?2e(H%dbyYoO|zb%-Ty(h^nqN`iV3 z(x8r5)rTeSFeTma0q>9&%=|2|qiU=$H+5;4i8N`J9C;4kukDOM8Lk~RnFQ?rT zTsQH!0FQJyM-Gx8Z|_dtZv@x%m!GNYG2_;C>9Ry!%OY>>k?E-Kv|Z7sC$BokAsx6Z z^pcX9Eo)1$SLc@~aL-!#XUtWaITdf#qLQ!v8S_13!#VwB9$mu&OabNMWyZ^B{&V(P zVq;&8MvRKy_b0sF#KYbko?%hBxBrCqVVIaF!D%ci_REQ!Obc-q;y}oh$(;QM&SK(J zuWdhhHaX9cmt2$)jdk50S=&|mri7!GB%;)6asnGkCe(3Z)ISZxyYb#;pnoRUGFp;N zojX@O_+k!aV2_UTCIgAFq+Q8CG>5S_H+!b@j=1NC{^$gT1vxY?z`HKw3l17M-3M!& z>AHpI%BbHKE#Bu;Ps2hV2ef!!PLk`{Jqu6QMIExjblL*WZqo$|&(9-I>{bQhSlsjP z2vD0ZdQ~2KET=M%%L>@5Vvie7@Pk6=ou~>pGQn*ie@^v`wqR@hNe#8_W#pCt_i}RG zpy=(bE$UbR^tz}!61jnxjyB}}VFpn1xcX^-7kW8oEDfiH->Qkd#1x`%VE321>iM^u1EwvHhS3<=FVE`{VkKUB9AF(|2sAh@SSdzCWk$ zhQ0^&op#71C+Lm|sO&9fl-;WDsB#|!%4X|3`lh1u`9AeCOjHP;`iZ_jqwo9l{bGH; zK;NNH$v5cxsrtSM_b@3!R+Ipq)!nD>F20xkpzq)Eeex6f{;0m^={stQ;!i@&se3u! zC%&fdFX{V*`o2MkJQ7q}DY{!YKA3Mo-)#7lPGMDvWDV*=Bze|j7cNX_OtA?q~J^B7aNN$;le$11j@pN-y7vFUjwQn~5bs?9?L z1#Vt=UDc-VDz;3daE`w@_wPz&ulI1P+R|f+(RWW;{xdBk-Qx}l+El&^s;V~qtRhrx zo_JBK@yVX7@Q9d>UW+*LWR>iJicKF?ZTdp%?=^zMycD)2eS#8+g;UW-_k;*6sl&`u zukVmPGIIsGJmM6d5NC7euBuJOhkNqU(h*{&b3MoL7=88@*p@NT-FuWA7l# z=7}!jlYN6_nbCW{!|H)4FpBo&JT!g(=MuVx9BAkU8Qp$hqdXqD=}bA<_|4hVXnw{c zmm6E387hw&`=7}OpNl>ehZ21n?U*oCaC~(pVp&r z7h=aDLx;Q$+U`g^X#q?Sp$&0foH+j)M5K32po43|K!!3Sh74so9vMpU35{v9VY1g4 z%yNwkO+pyJr;BgmG-AlmqY&kE+B8`7RFa`rzBb#bcp`XUxH-h@^Tg8{Nl{wj=^txF z^nxbw45G~3Dr6|-Kp{h^?B63))zY6KLmx(9$|Wg@%T`*s_(2ASJ{hfmP_rGFBXSu_ ztXmm*t5K#6yAiT*$UyD1w{~iP=!)kRlMtXMKtr!Fwmp|N_*E4=LDgs!3wj7lpgd2& zf*vvsKj#eHj+|M%`!xbop+^}3+QA`j{s}geLk`EIK!FWihq73_$Ktsf8+z0@<9TQJ zD7BaOR|=<7fLa305^ndrZ&dcyJGr;51EuN_P*F+ke+?MDKgL6E>TSJ=M5__QW+UNV z@+dg_Ns7dKQ+H)i;z5WQHe2{MP>IxJR2?b>phYPLrLSq5jhgWUuqd5+N5P{1M1&Yv zl-`lVz@q;F6@y6=Z1l2zK+j>VKdWZp?ys8Vyk7PatRjFQEt01gZ@l}=vKt}Le=#xz z@aUuc(Kq72qdg!>{f)t+q>B6t;DiD2=qZpTcZ(Q!)TN|>L?dlUQ|ckm$7&z-!0!5U zLOx+qp%A`ymiMaN&nMx38FOclI2N114wJtEE6EaK{VXY#4 z4{FT5zMF;(T0;y&N@WX^cUc-KvS08o()k`90U~`ks`KJ*Ixp#_bCao)Fr-{q#*p%J z6hqoi)k73R$|NwP?@6o=>|16avHpH!86eV}OtUasyCr;;neaF&nxPZs%DI{;#*oHk z;~Jd}kw(hx*Y2ZqUPN^QL)yaWQ2IA?OXxpZqyQOfS znF3=-%>+ygDbv7^k{bKNACSf_G_=(o-rW{e`B*oVk873bs=}YpD!Ia+j4C88_NRtG zNB=a{a}E%~kvsG=TA#v@9z|JbsMG^P%Fn=%rm6OS{#=TF8L|ct>EEN#U)Iq@8U@*3 zd6J|iAQ50le~n7L5tX7K`z$Y)XYs?Sb6%`|4t)-#x8sM z*xzG1Riu$B`};kiDa}U-99n_L40@FP&qY|O{ljac$$Vrc!xΝQ4F`#V2w5;U+w0 zzNIqw>544$KZhFqM=5FyL`r5s`4ibcr{NvLkkY_(s3!T6hDsDeO8q&CA*GIJVo0gW z#9>IOxnmg8U6YB7f=H?IO%N$nv56t2ii~1NZvr9Gs08*O?~3%@h#wX>?KoKRDAMb( zr?uH`#Wji|y$?hjiqys^(gVa*Cwgk`5i-XH_s93a?S?9~^%4IAPoqj7#UqR`Y`#L3 zCMIGxXS1b5?%gP}!?#gZVn=|zca@;6z=&Z=A6O1fUi2U^)z-JH2^#VVRN8l{Rt}$Y z+Z&V(I$l#hPLY~wzXxJ5P-$xNSkN>Zzz>8#rKu@nvkSS&k)V#%s~ti}jolr0GJLlU>-qS9uPRtV!l;XlehXb;j_I(gV65TJoa+(-ES7GIJdka%>m!gACnP-0sD)J9z@9gEW7}+Jg0|U6n4;r=GS!x0 zJJ3xC0dbJhR9j~GksS17*FBIzeE?Ky9%womC|kK@Gx$g|)!8d67j+0oY40N}Opww( z{0uCoDd_C`1A-Axop`1?(@&*n8c~{IMl}(onP7y~P=f*$!|5D=2#BwaMqSR_>nMJU zhLYw{Ce$=e&MeM+QcjCT#8&c7cRe_0L(X+pI?01nsVB=UjG5#HOt69oSnE9Cq8(bayTQrT@~JD$%o%XXA|6_04B|(aPpVUuWxDZP~Ias z4r(3pkIh#eNjXlYT^9G_Xug~*?g@o(pS3;4{fv%yQwwwLpQ*&6-6{rd%`3P$2WQtX zObPi>bZcHA$s=*_Omu7B0Nu|LR6olb$fS#gMi|nGWJUjt2d_ww8tAGvC#m^3a-+@3 z@070tM(HP6iQ~aT*@K@r6Fc~E{U^>$8ex=?c;u_Qti;&$Nt!%vJoia{)^Vi4uH623 zJgEDOFPQB zX@*XK{0IH`BXUBkQOSIhcGjXBx|(2GG0A<8^mC)eoFJ8P^INt9x@Y1pI%7V|8D4+_?3qFGnfr zO|F^#?l@NW<;RVWk7gphpO5A{IX!X-^`p<3;8pk5fhL?=i&(bGw@^AQB6K15C2ttNf0h*<1tk{mB@)6Koa(-`#6!F*W4sZ@!RK_S*(%j0ac^kQ7H7N_r9aXurJbQ z6soaGwZU*y?+#w2tO19hODoz4E6mU*@6NGEN&zns7(=OgcfDb3{vyYrcKTd1F_^0N z!Cl6_FS6t=;~!t-WU+`rl^2gm^**xBNc}SNWE$%h?=}jKf>OP^A5pDvH*qy8)%zIb z(&F7ExxKuP)9AN&A0rt6H!&_?-9mL_mb_1VW}NqBX3jI{Q5NruB%wN4b#PTknLF=O zHyaOp31g31#t#*dfW~lnetK43lO6nK1w9S@h%=*f?#D(m^ z1}k@4ky_&JL-~!HTa^v&bDv40-yS3ZkkLS7ncFv^|StF?Efmu z_h~7yhf|89IrsB181EjvFms`yq49*TuNL_H{n4-+rApms2Dx z1oGe7I&Cf4IR7eUlSei3-hfx3bAcM2+XgHyp@vp-Frn@#GbR|-zvj4c>Nk11;L0Eq z$`&vBr?=F?<<);S$0Pr5zXGU^^{-==GS9lU=Qe9cJ^wizs7!P`Zq z7lKm)J8=sCY0RaLMeZ9WdkM1(+1mI|f5Z6U+l)e5l@jnXUl)y$BK{h-3sVx@=Tlaf z78=98^W^j7Ot$BbKve&-en#te=?zaqo-MHnJoVQxZyDmD0U3JZKmRjy?gVe0&ZTlR z^=s2!&yos<>fgxuCZk1Ti*cxanD_6#b7HL8zRwLil%ay*rjf~gE_IvBo&t8<$W+LV zz{URNaG8Qv?5C3yFfcPlc@v9AX-? zk-LuQ51GDBnJ4NmHXChgY?Zbr*-Eh`PqlfH$(Bd!f{Ynxn~f%YECWmst9LKWJ${-A zXpnjL9XGB#mX^&OmoRXc`RVnw?o!^Tj~n}rInce|KbD8<&&Tq|u&lBVCT!LF95a<= zh{9IA&oh?*41VMAw6tE{7nnmx2frc9(@MNAGDjH;wQ?$p`)LF3OB_mQRDTTS>V5gR z@%RsU)g0K50#~=Rt!xJ{hM-pPsqntaVFai0Yrx>tP;E<7h&+D0uW_idIB}p@@9W2n zfj`nhu;NE5?TR1Gm7}sF+|X>Dyl)>jw*8nHU`5JuET^BpL8Z z*|+{DT8v%y)4)8IA$X_1@dP-n_t0_U@K3asJ^qtFnFR?d>NlRAfwuUVIhX;g{>a=L zWv<10__)#hFDn0K|Dr|ij(<_)SN=st?u&nUaZT5Dh=>fM{P}uIZvqvZgCn zcO_K36TL&Y_Q*0Iy2wm{pq;z-M@!;m=D~M70X>fo)s$A+r?}E zmLUGt%q)xd-I%1&Mf&q%%OZB9B{D?^-{g4UXUKb2x<*Gl$<75j4aR92(xbPQ;izz}{`Atx4 z!4PJu<-akn%28P`lsN?8@^c{+_&Nj#ZNV@OBlwp;9yVJroC9ckP`H-rsOWekf1Au4 zyuM)Ml9D(R1w%{_h=R0#f(vtv(+P&j7Np;71pnidHyi8z0rPJ{Z9kb*2)reUHZ8I6c7$Y$MBz*C6Wf*fA8Re*tIrFP;f$YoPM4_u9qEy!cm zVz7Xa4HHDRAfHZ;F!L#~6{5h!d8h{+gUA-R^=t;N*=GtytV1Wl529FT`ce~NYKhBE znTuL%$~6#%s!j?sPNv@M2IDx8%l~?F$QK&~K&q4d%A^Zu)8t%vWp>K-RNYJs9$#{$K4y4S}V2)z|? z-yshNO9EFmO~8TjSPYH8R$ha3gYX8fVrCqKH(<1>j%Q0h1-r<=HGFWDn!c2%YngJS zml72@Y6O4F2=j8xm#)?n*E1DJS1XDeD0#emT{Z8er|%;I`{loQOM1fJ-Lr5z{mWVZyK zIx&GgW&)}f_EEfOrZYjPwn!BA!oY!xNTGaNyY-RkI0P=I59)k;;MR zqdg~vR1Umg_8rywFL8<~RL`%`f|OHu-Ry|8R4o#LH_YnhHyMF96&?2K%6{9d?13eL zE84Nn)d=RmO>d0{ft`v7{Drz!48a`OL5R5G}T3i2JWkR#tTGr4{M6BhY_b74gx-0o)TP3Y35RxO*muJ{&O6&F&s@=Zs6@3+WI zoef?O2Z4aCi^98o6`Tewhzn^v`6?A72?GGD1e}4W#bONKoGNWLY7d)@)?0a|Uu~*w zKyUlhxQSEr-;7oQ!ntUw@X?DEA#>L$dnp*=%mm)GlAO%9M^;#+YvwlSP^eQtm+6^Y zng?reGrbCeI}e3xa5EY9tH2qeOd7z=D=3An^N_nqk++~Px4bN>ZxKBcTvzK`lo;vV zLuSaFh`)#Qhkwt*B(Zh>>R}99-ULnCAxtE}mWe(Hno9mX%0HYOTI8>I%_GE{#Kzx4 zDjX9F1zDy=Q~s4wJ`GHr@~>2q^N5ZCm2K+xKIE_4B5(DO{VU0&KMRRrF>o?@V0=L= zyjCD^vi$8WaB?lo0XCWZE~-HmMX||3?vD&fl%8-SG6TdZVaD?%<>qgY8_D&WFDW~} z5Q7oP`I5x5twM}45y>v)^Dzl56#u6^jOLrD8*P*H~_WE zj?*(?kIB_#oW>rL%s9dxhZQRKC92=?;~0F5-j6?ts^c{5IIM`M_%J1IvkimD zBzhxA@BK<R_ zF*L{eTLIM47haT6H$iN9eU&@+vilL!cz`yIp3?>P>ojUcgmAbwc*^(l2<@u3&Q)IR}ij}g8eiFO3 z20t9pv9?Cnjyy+Bni*;7h2O6DzEUPzL7yK<>Lq=+4eg~g;O0!?VMT$>y<}m+`4zjr z-zguGyJz*0_w)&q*FBBQC;+e;eGh#Ie-!jJ?r{J>^3aRo`sjrR+L_!+qdXG;NPc%w zrUn3#Go1q7Areg`6hDk-a=9}dOaG&v6#$StHx-_b9YDz~QIYHoL7seyi~#_tM=F*E z0FoaJ0|3bnN&^7NkxK&rFY5<~IC9^^Qk6XJXmtViJMyi=qX_^c-?ljNfk<$V>@UAk zw}gMCN4D*eX>vm3R$%|+jL7SIq(eTeZVCG`B66?HlsVV#m5znv-bH%4VF1b3<_}DA z)6&cs29O+a{=oboQshQvJdq81aT^k8bz_Cmrfy+!g`x<+VWFngZd8y*)rmZEh9X`( z%8$HvPUMk06!BspKl1D8&LQU};sE3q)+j%6_|YuQA-5&sD3l-PiyVPYVBMuzEI=zQ z5@3oJa~jh}3#BNgj~s5;8R&g-hf;$E7lO3WID|V89o~?u4;eOv@}oUX%*BWH>2dx& zJA46U)rq2tUOu|uO02WZ%mxbI-^dq^YXdjj9VvqEK#Pn66 zSDD&Th2Crvq7M~G%dr!DQ^+p`kr?Dw*}S|(z^5Y&7QLyZEtbXz#z6$>gq0MU5J7TO zF#Qw+y^J?~80a0m88AZ7iwq4Br1wg3;6Qpys-`0ImtVu89Pd7&FFnX3A^H-Z4&rdy zrGMa%b{28yKsqOj9);1tm_DqdS1Bes@E_yoS#?Hr!b2}*%vVzMz871{*>oVudrEr0 zYraaR#XLH)LI=_g<`3vVTEhK-d48nIFI|IdGh(X;T9&D$*#2FYE$!vV}m*l#2z==-OLLiDTpemU;2yond-`%HbGs_*Ig-b>$K#f(An&+7Y? z`hJPNUp$S&!+bwAF-AmQUl9?-(VojTiAlgz;cwyw4$#PiOgy-xaHiplTRjlSgO^?&`qnaMC z=_fQjRnvPlU7_g%nx3iY7c{*{)2}ie7B!mjmKF$U`tO>?f=&H>py_5!AJ%lMra#m4 zT223|>1#FJACq41R3S_-*LhOCteOS{6H2t-v4{BPj z=J>}n-AB_s6S;;1n$9CSj2!LP3DQq@P!kksfdxb(Je5}e_-oVjVohJB<;QCI?K*s$ z4*yJtPt)Q5(c$}b_`sf6z*BM@d)30fIzozj6Jz=HbIn6k(1^%Y#bZl`bfv+?@MAJWOx?Iy@4cE}=noiMlr>2K% zdW)uKX!=eY+Mf~#X~rHcaE_+`rs?xF{jH`qYr01g$G=|FxtiXu>Cu}0NYk@5{j;V+ zVa-Tf%OyBh)BQAkji&Q7eZQs$Yx+4&kJR*snjWj^E}}89m?*m6HGTMOPH*f`I}4<) zV@9>6D>S`Y)9W>Tho*N$y2@mJ-wNG#*CxQ_w-2mN#6L~umwu_GZ-#}+@4X%?UDoc> z^szRkk7?S3XZ9yGkWbxx;WT+lF9zKfj~x~FHN?mdC&~ZMrxS}y#>NTn{%XD)gdJKW zeSw^8fBq!=e62-@kCrHKXym(UX;+_5O#16WWF1*L5V>uE9B+RaB>f#>sBPr81=5p5 z%q0ss9KJCEArOKGIzJDKLBDL)4{=RW0p>=fN8#OwACG{09yHKtCsm;=gwIk4xXp-2n^n+Z^=(9E#1L>y z$0Oh-T?_ie;lg@6kiko^M!j^@%o{Wv05)d?R*d{#-H@NvX2;p*@kZ*f4la}PznX~LJPj;h?z zrxU41wS!W%N_aRb;ubJ^6LhLK^}XIiq6ZSgW+mZXl2Uk#q)5CsbzT-F9)yTtvtAD( zk=l=ntr7qnjv_3f^fkj~rA9pg4|kkcylw7Tdjv6Jc(~h%(wpa=p&vkX$HQ&h{c*Fz zM-+#{QYaMMNeTsL#G&AJ^hf`QL%|(KZm5GW3T|UJ6x>OWg-<{n3eEw=>Jy5KQL>~d zOCdlgxO)f%_md2Nl8$#-JCH5=8dI-Ez%gke;Ftmej=HCP-93obe+3?afE$%zst9Wp z=>{sqzP_7=4O&AC0Y~Ku(|AiGMfMB6A)V9|K)~G>)p>C@otJdexyjT?2skb%BjETs zih#4LI*20Rm;?gu8AiZOMq>T@BFjL)rDd9h+1f4PtIUK0R5U{;tPyZbF#;|w8`tP; zh%{1ezjimJ^CFr72)GrT4%QR)8@eTQqfW>~!0D8t2sqAs6akkHJthL~#c1Ad@1}CQ zsZt~0OqC`APOCH#a7;!KaBY;r5EK9ixGaZRJNI@=;XX43M!=Z~mQ2?2LzROMscR6ed%rmG5nLaWpWxTr$XVt>jH9VPH z;5sS#GGq-1xYwi6U)Iq@8U@*3d5EMm0`6Z?sW+lhjDR~xQr9B_zM@#^G;8Z!Gbe3WI#iQ`qky*}2E4_6MKQJ4N(dn}4S2Km>-h>8t}+6= z^O|mKn{^pzo0WtqI>F!YMa3tSP-MwPGAsNKdcF-8R75wV+nKud7&L~jC-%n?oBDbp zMWJe=uP5?zx34FDh2Z$FCoZ6P=GPO=xF*)^l(BIds_A`+bDReeY*vaE|MkS{NllCS z^+d`H<$=zXg|n1|G2E%6Fyw7&ePqtXGBc4*4P9lxt2vS!+1ZtJE>i}`T3R?e<3?2s zG!kCYY0z4BCP^qCz$j=f+d*|opSonwTDFtvREzsgRC;z6H((ll^I;eF6$M&L%dtPA zl8g3^7-%iG;B;1EO^AWkatlcwiGyc?)^Z2v?!ln7+<{E0PcqJhbmAd&jOXzX2U@dP zp8!TJGs&7)_+OO)z|=C5Z274pu@6P**ME{ZG`|lG4%o78ST$GK&u;ib1c8j|Sb$HE zsLFLM>AH3k-l2CzT$}J-p(`>LpFA8uV~{^==xc8c)iwkhOV#h+lf$rUDTk7qh|jp9 zIK$-%GKc&}eRu&A_o53FyDg(I9y;Qn!JBz97 zKsi_${T{v#FaGtH9bIR3Mc%qpI!19Q;VKXcA3l7vOMN@X)yN^_6yl3Vzqy*aBDtGY z5hrfOyOOTR!p(Sx)fG8=bF`$WD-1~UMA+3%bqTMXD5}l1`Q^yI%`ywI{=t!d2j%4y z$#K;O@W%rDa`%FUR^hsW`Q)_fqYp8LT~{)Pyj6YVda1v}=-SGBl{`kU`q)hBJa_Uz zWXDC#iwIG4n`=D{67E47-R9cBECO!CKE>!dpPRo>ahI)%yndPN8D`#K@c13MaBVyg zAbrEZ(qK2&g)B7+EQNN`-(YlI#C!rG#KGTO7c+YT!>L@CFgXQM1hI=b*|;_x3ahlH zQ4pV5yDp{fn1HW-nXD1QbycE=c-W$%I!=b;GCmlYx-qX0<@65~;<+PMA@O)P&z+nP zM}oU2<~`3}h>X0mMP@ELIEvJ}kYqe0&U5#(I9{hOelb7##YWFP96&W0kCOBJl~bVF zjQ@tC=iV10RhLW002;XT5l6GK=~wwY_q&v_ph{%aoM*?O$d=1xwqvhKp6V?QALrTi zLS#Qei|8PL>nVnh^E}AhO3FdE&p3J>x;v6`h0J!cz$^&FW9B@MJP?_3h0G{nTSGXJ zC}z&H`}6`zY5|xUGUs`Wi?W!T*z@=sk;|`;Sq?U4OCd;Rq>8`f=y`HkWd9Y?xq!`I zJwm&E%F(muV^#l+2+&Xw&o3{lvbTZ-NJkL9D^u0)iH>mVKW4Dim}JCSN96&!eVt9(-^$bpV*vmQYX{s_PG zEm(();46>$i+!Qb2f{R)7(Cx{whQD4?Tf?U`BpHW+yQ+i2G3W|OoG)wL+n$Jz6Kmp zZIwNHQde352E=RyCTQ8$}BBGZq7avlgF<^ea&5wkypWkp(}Da zKKbZmRm$GSed^J7R#(KhO8O!7_*L+w>Wchum9o2i4VedOxPf=aU6C1}v<8CJQBo$X z&bOv3avlrcY^a>?Hq`uZ(2zMXG^{!S%}bQ)3m$2@LlvmWbm~zCw#NYUqw8^ZbH7D>NjpkDukW? z;uY-^$CM$UCZHXt@E@G27*y-3*z`q6|3A2)N@%k}y~}3B z#tBY3)>_mt43fswS>4HG{-dRbz;@6!>&uu5u?R6Sb)LO6dHI%UOr2+6S7d8Mre$+K zSEIihsLu0rS7d)gt?3R%)cE@)BJ;u-<)^H>b# z-0C|KKIb{q75U@_nS+x2c7yaMvnT=Rd<3Agcs}lml;5aKZwt_K5ZiL2GKo8HRFPi2 zQCYq(Z$M9|GO{)3V0zRj^2?6GO-2ii*e|AM4xJl`F?Is!MsnSnKjtspS zzch)DN?JVMVzGX+va2WEtmK;bw&`Y>r)!jOb5I+PoAdn0B_Z6LPvPb~KXpaEzgZ6P zZ~y`4xJeao&eO$g0?wf>0i5&vyDM_qEiyNa129(U+mf^@wpnkBTy~4hn)Mk*1fhz| z4@m|*;W2=Hzz&FjUY)BsG#)e;@UcEMiE7YXz>m4=7MYRGLF7%3jf_Ig1q!+%Ik!p& zZ%Y(L&KJYT1qO6Qst~Gsp6Vs>h`7KYOlY@Cmx~n>6wYTt;Q~XLNmG=Mpm3JJ(5}eA zTV?hj4p1A2c+^{9I0w)^BCwVUS=2?Sx2&>HisLK@EF(eQ0%Ac9X zfrAMv`en!t5y-eEa?Un*jq{-i!M_LsGpl??s5yiWZ~~adlTyIJ)-eqdjFAgCnM2?( zwF(k}EM7+Dkc`I21+qCaF49b2jSS>)UVLE0FmmBQE?a9tk!g@zAdgvt!NRJAFmi!> zI&Y%SNRreF5pZ!HMuCoD`=cA2jiJJfGg=P$_TjzS0!UpFvZf$oWF z8E9hN;=ynQ>btI1sb&aMAPx*ypog!XEEo(I$=EJ?BQO5#$_iC(XOp}=YIoEW&<*-l zfN`~LyDGsm+ogXjXPAD5LG|o{fr`O^w*sojZh$v`F?G~FR)1&_0p31Mxn?{LkH=z2 z__rR4q}~Y>6EB|P@NIsB4!!6c$)4iB`3po~44VHIZi9FXn*Ubj#lBGK-}XGTBX%4H z&3{{(TDj2|D*bm2oM2|*ZloRAPKYw@mT@1c^#7Gt1u7Femm`Y#p-KNP^Yl!?#7+_Z z2lU~Yi5v4j$P5+tiQD7jK6zr?rxc?QKVqk}ohtl$;vygDiSeMwm;J zkWMFG{^yu7VPF2|Q7DwZ+XpKBFT_>pYqSW8DSe&gQ9cFs^1or$1s~e`-(=b*3RC=7 z(1OYt<_}c*Z(4-5QOD{2zfilz;9dS5)NI}0UH-?Y-n+rO{7+N8c7u2MU!m&a4^;Z! zrP5=({S8w|JT_})yRdpk^_hY(7X@c|M{~zi(+K4}ip}!srIeaSx?!`t#a)rTcd1GG z@Le)ZZ>!W;?2g9rj_Zn~-mQ+qO74~}44_k(+Hg0}Se&q0Y;{Ltc_%|ZgKdCL`Fp|5=AIrj+R zozAM%0bJZSCcQJdBIn$LqYMsK>nJl;k?>Y_MRwjJ-C?R+o0TT%7}CmG*n1Y(u?4V+ zv}yyFfmZEm;0gv>F%bn?QQQG*(PL#LE_ho*7yQY;Pr>IF7$a0k&k0*ac%X(}(MySh ztyTnU6bo zLeUyXXGjyiB3dkULd7v`7QHNb3=v1gVY9A@Y`qUZ5J^2ap>sh=92|>Ti%a6a6gf^Z zcgcttIE!*o(jAyZ2_*nB!2BwIVE)r6q!ZS>$t3 zq=8u^R22ItBvt45BF1IWSRt+S`U+oWf>y$15oWIld-frdBZz?xs#sbfLVt?t+&8+(k{ful&Pyx#9~!lfL~E)GAfc73Xer~ zHW-X4FCk7Qh!2p35ekPzvZ8baD$;=m!eMQ|^VCjUh71R%Y)crAW!K{}Z3<$2*i(r4 z@amI?1|Z2H^&~O}{IaEVS%nJ(pMo@{Ny74j3rO%f5_}o_@(*yCjm(sPj)x#U{Dg-s zc$iMjL-9&_Al^koj!~TSabT9YaiPBtbRIGCu=J1?geg)vQ^ByLv2g z+D^QqNQGa3dNzbQ$TLW6)ws%F+1cO6lIc!6a>lP z$HeTAMWOg%@X0O6bcOptKP$`*`I^PKtdaASBH8im3zLjtcBqU>LYJD}+_Uo$d2VRT z4!NFax1)`5m>u#DB42u7cE}Tm@FCbYktY#(rt+u@|MyBsnY4gsLz*v^0%*DbQ9U z&P9P70;2v2w4smU-S3Rg>f|rdJm6~YI?;^uR8Q2p?0W1gv6oOYxp=4rY@#O?FhbBtsD3+2 z=hHQ@18Z8GDeGl|as<6jiXNKMd(`NAMB4a=V~0hw2#o{f(8e5ry!EEz6n#2CXR+p4 zZOu4(R=rJua_Cgo1m)1Xp>DtPKremFw@$Q-Lr0w*bi!$u7Oa23-?T**9FT=x!q(6% zLNl+LeS=`o6oDJ#ZU*eW^?>}=vis8KWpiry2k`ya1iYp1kLvq&eLoX-sIo5C_YwL& zRNs^Iy@$TP2&+%>&+7Zt`hKOp-!PTKujTtp>j=#ls_&PTvcM(!{v`@a3XkghCVjt9 e-?s`5-x7KHJ(-(b) ? (a):(b)) + +/* kiss_fft.h + defines kiss_fft_scalar as either short or a float type + and defines + typedef struct { kiss_fft_scalar r; kiss_fft_scalar i; }kiss_fft_cpx; */ +#include "kiss_fft.h" + +/* + Explanation of macros dealing with complex math: + + C_MUL(m,a,b) : m = a*b + C_FIXDIV( c , div ) : if a fixed point impl., c /= div. noop otherwise + C_SUB( res, a,b) : res = a - b + C_SUBFROM( res , a) : res -= a + C_ADDTO( res , a) : res += a + * */ +#ifdef FIXED_POINT +#include "arch.h" + + +#define SAMP_MAX 2147483647 +#define TWID_MAX 32767 +#define TRIG_UPSCALE 1 + +#define SAMP_MIN -SAMP_MAX + + +# define S_MUL(a,b) MULT16_32_Q15(b, a) + +# define C_MUL(m,a,b) \ + do{ (m).r = SUB32(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)); \ + (m).i = ADD32(S_MUL((a).r,(b).i) , S_MUL((a).i,(b).r)); }while(0) + +# define C_MULC(m,a,b) \ + do{ (m).r = ADD32(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)); \ + (m).i = SUB32(S_MUL((a).i,(b).r) , S_MUL((a).r,(b).i)); }while(0) + +# define C_MUL4(m,a,b) \ + do{ (m).r = SHR32(SUB32(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)),2); \ + (m).i = SHR32(ADD32(S_MUL((a).r,(b).i) , S_MUL((a).i,(b).r)),2); }while(0) + +# define C_MULBYSCALAR( c, s ) \ + do{ (c).r = S_MUL( (c).r , s ) ;\ + (c).i = S_MUL( (c).i , s ) ; }while(0) + +# define DIVSCALAR(x,k) \ + (x) = S_MUL( x, (TWID_MAX-((k)>>1))/(k)+1 ) + +# define C_FIXDIV(c,div) \ + do { DIVSCALAR( (c).r , div); \ + DIVSCALAR( (c).i , div); }while (0) + +#define C_ADD( res, a,b)\ + do {(res).r=ADD32((a).r,(b).r); (res).i=ADD32((a).i,(b).i); \ + }while(0) +#define C_SUB( res, a,b)\ + do {(res).r=SUB32((a).r,(b).r); (res).i=SUB32((a).i,(b).i); \ + }while(0) +#define C_ADDTO( res , a)\ + do {(res).r = ADD32((res).r, (a).r); (res).i = ADD32((res).i,(a).i);\ + }while(0) + +#define C_SUBFROM( res , a)\ + do {(res).r = ADD32((res).r,(a).r); (res).i = SUB32((res).i,(a).i); \ + }while(0) + +#else /* not FIXED_POINT*/ + +# define S_MUL(a,b) ( (a)*(b) ) +#define C_MUL(m,a,b) \ + do{ (m).r = (a).r*(b).r - (a).i*(b).i;\ + (m).i = (a).r*(b).i + (a).i*(b).r; }while(0) +#define C_MULC(m,a,b) \ + do{ (m).r = (a).r*(b).r + (a).i*(b).i;\ + (m).i = (a).i*(b).r - (a).r*(b).i; }while(0) + +#define C_MUL4(m,a,b) C_MUL(m,a,b) + +# define C_FIXDIV(c,div) /* NOOP */ +# define C_MULBYSCALAR( c, s ) \ + do{ (c).r *= (s);\ + (c).i *= (s); }while(0) +#endif + +#ifndef CHECK_OVERFLOW_OP +# define CHECK_OVERFLOW_OP(a,op,b) /* noop */ +#endif + +#ifndef C_ADD +#define C_ADD( res, a,b)\ + do { \ + CHECK_OVERFLOW_OP((a).r,+,(b).r)\ + CHECK_OVERFLOW_OP((a).i,+,(b).i)\ + (res).r=(a).r+(b).r; (res).i=(a).i+(b).i; \ + }while(0) +#define C_SUB( res, a,b)\ + do { \ + CHECK_OVERFLOW_OP((a).r,-,(b).r)\ + CHECK_OVERFLOW_OP((a).i,-,(b).i)\ + (res).r=(a).r-(b).r; (res).i=(a).i-(b).i; \ + }while(0) +#define C_ADDTO( res , a)\ + do { \ + CHECK_OVERFLOW_OP((res).r,+,(a).r)\ + CHECK_OVERFLOW_OP((res).i,+,(a).i)\ + (res).r += (a).r; (res).i += (a).i;\ + }while(0) + +#define C_SUBFROM( res , a)\ + do {\ + CHECK_OVERFLOW_OP((res).r,-,(a).r)\ + CHECK_OVERFLOW_OP((res).i,-,(a).i)\ + (res).r -= (a).r; (res).i -= (a).i; \ + }while(0) +#endif /* C_ADD defined */ + +#ifdef FIXED_POINT +/*# define KISS_FFT_COS(phase) TRIG_UPSCALE*floor(MIN(32767,MAX(-32767,.5+32768 * cos (phase)))) +# define KISS_FFT_SIN(phase) TRIG_UPSCALE*floor(MIN(32767,MAX(-32767,.5+32768 * sin (phase))))*/ +# define KISS_FFT_COS(phase) floor(.5+TWID_MAX*cos (phase)) +# define KISS_FFT_SIN(phase) floor(.5+TWID_MAX*sin (phase)) +# define HALF_OF(x) ((x)>>1) +#elif defined(USE_SIMD) +# define KISS_FFT_COS(phase) _mm_set1_ps( cos(phase) ) +# define KISS_FFT_SIN(phase) _mm_set1_ps( sin(phase) ) +# define HALF_OF(x) ((x)*_mm_set1_ps(.5f)) +#else +# define KISS_FFT_COS(phase) (kiss_fft_scalar) cos(phase) +# define KISS_FFT_SIN(phase) (kiss_fft_scalar) sin(phase) +# define HALF_OF(x) ((x)*.5f) +#endif + +#define kf_cexp(x,phase) \ + do{ \ + (x)->r = KISS_FFT_COS(phase);\ + (x)->i = KISS_FFT_SIN(phase);\ + }while(0) + +#define kf_cexp2(x,phase) \ + do{ \ + (x)->r = TRIG_UPSCALE*celt_cos_norm((phase));\ + (x)->i = TRIG_UPSCALE*celt_cos_norm((phase)-32768);\ +}while(0) + +#endif /* KISS_FFT_GUTS_H */ diff --git a/code/opus-1.0.2/celt/arch.h b/code/opus-1.0.2/celt/arch.h new file mode 100644 index 00000000..03cda40f --- /dev/null +++ b/code/opus-1.0.2/celt/arch.h @@ -0,0 +1,209 @@ +/* Copyright (c) 2003-2008 Jean-Marc Valin + Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/** + @file arch.h + @brief Various architecture definitions for CELT +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (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 ARCH_H +#define ARCH_H + +#include "opus_types.h" + +# if !defined(__GNUC_PREREQ) +# if defined(__GNUC__)&&defined(__GNUC_MINOR__) +# define __GNUC_PREREQ(_maj,_min) \ + ((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min)) +# else +# define __GNUC_PREREQ(_maj,_min) 0 +# endif +# endif + +#define CELT_SIG_SCALE 32768.f + +#define celt_fatal(str) _celt_fatal(str, __FILE__, __LINE__); +#ifdef ENABLE_ASSERTIONS +#include +#include +#ifdef __GNUC__ +__attribute__((noreturn)) +#endif +static inline void _celt_fatal(const char *str, const char *file, int line) +{ + fprintf (stderr, "Fatal (internal) error in %s, line %d: %s\n", file, line, str); + abort(); +} +#define celt_assert(cond) {if (!(cond)) {celt_fatal("assertion failed: " #cond);}} +#define celt_assert2(cond, message) {if (!(cond)) {celt_fatal("assertion failed: " #cond "\n" message);}} +#else +#define celt_assert(cond) +#define celt_assert2(cond, message) +#endif + +#define IMUL32(a,b) ((a)*(b)) + +#define ABS(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute integer value. */ +#define ABS16(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 16-bit value. */ +#define MIN16(a,b) ((a) < (b) ? (a) : (b)) /**< Minimum 16-bit value. */ +#define MAX16(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 16-bit value. */ +#define ABS32(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 32-bit value. */ +#define MIN32(a,b) ((a) < (b) ? (a) : (b)) /**< Minimum 32-bit value. */ +#define MAX32(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 32-bit value. */ +#define IMIN(a,b) ((a) < (b) ? (a) : (b)) /**< Minimum int value. */ +#define IMAX(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum int value. */ +#define UADD32(a,b) ((a)+(b)) +#define USUB32(a,b) ((a)-(b)) + +#define PRINT_MIPS(file) + +#ifdef FIXED_POINT + +typedef opus_int16 opus_val16; +typedef opus_int32 opus_val32; + +typedef opus_val32 celt_sig; +typedef opus_val16 celt_norm; +typedef opus_val32 celt_ener; + +#define Q15ONE 32767 + +#define SIG_SHIFT 12 + +#define NORM_SCALING 16384 + +#define DB_SHIFT 10 + +#define EPSILON 1 +#define VERY_LARGE16 ((opus_val16)32767) +#define Q15_ONE ((opus_val16)32767) + +#define SCALEIN(a) (a) +#define SCALEOUT(a) (a) + +#ifdef FIXED_DEBUG +#include "fixed_debug.h" +#else + +#include "fixed_generic.h" + +#ifdef ARM5E_ASM +#include "fixed_arm5e.h" +#elif defined (ARM4_ASM) +#include "fixed_arm4.h" +#elif defined (BFIN_ASM) +#include "fixed_bfin.h" +#elif defined (TI_C5X_ASM) +#include "fixed_c5x.h" +#elif defined (TI_C6X_ASM) +#include "fixed_c6x.h" +#endif + +#endif + +#else /* FIXED_POINT */ + +typedef float opus_val16; +typedef float opus_val32; + +typedef float celt_sig; +typedef float celt_norm; +typedef float celt_ener; + +#define Q15ONE 1.0f + +#define NORM_SCALING 1.f + +#define EPSILON 1e-15f +#define VERY_LARGE16 1e15f +#define Q15_ONE ((opus_val16)1.f) + +#define QCONST16(x,bits) (x) +#define QCONST32(x,bits) (x) + +#define NEG16(x) (-(x)) +#define NEG32(x) (-(x)) +#define EXTRACT16(x) (x) +#define EXTEND32(x) (x) +#define SHR16(a,shift) (a) +#define SHL16(a,shift) (a) +#define SHR32(a,shift) (a) +#define SHL32(a,shift) (a) +#define PSHR32(a,shift) (a) +#define VSHR32(a,shift) (a) + +#define PSHR(a,shift) (a) +#define SHR(a,shift) (a) +#define SHL(a,shift) (a) +#define SATURATE(x,a) (x) + +#define ROUND16(a,shift) (a) +#define HALF16(x) (.5f*(x)) +#define HALF32(x) (.5f*(x)) + +#define ADD16(a,b) ((a)+(b)) +#define SUB16(a,b) ((a)-(b)) +#define ADD32(a,b) ((a)+(b)) +#define SUB32(a,b) ((a)-(b)) +#define MULT16_16_16(a,b) ((a)*(b)) +#define MULT16_16(a,b) ((opus_val32)(a)*(opus_val32)(b)) +#define MAC16_16(c,a,b) ((c)+(opus_val32)(a)*(opus_val32)(b)) + +#define MULT16_32_Q15(a,b) ((a)*(b)) +#define MULT16_32_Q16(a,b) ((a)*(b)) + +#define MULT32_32_Q31(a,b) ((a)*(b)) + +#define MAC16_32_Q15(c,a,b) ((c)+(a)*(b)) + +#define MULT16_16_Q11_32(a,b) ((a)*(b)) +#define MULT16_16_Q13(a,b) ((a)*(b)) +#define MULT16_16_Q14(a,b) ((a)*(b)) +#define MULT16_16_Q15(a,b) ((a)*(b)) +#define MULT16_16_P15(a,b) ((a)*(b)) +#define MULT16_16_P13(a,b) ((a)*(b)) +#define MULT16_16_P14(a,b) ((a)*(b)) +#define MULT16_32_P16(a,b) ((a)*(b)) + +#define DIV32_16(a,b) (((opus_val32)(a))/(opus_val16)(b)) +#define DIV32(a,b) (((opus_val32)(a))/(opus_val32)(b)) + +#define SCALEIN(a) ((a)*CELT_SIG_SCALE) +#define SCALEOUT(a) ((a)*(1/CELT_SIG_SCALE)) + +#endif /* !FIXED_POINT */ + +#ifndef GLOBAL_STACK_SIZE +#ifdef FIXED_POINT +#define GLOBAL_STACK_SIZE 100000 +#else +#define GLOBAL_STACK_SIZE 100000 +#endif +#endif + +#endif /* ARCH_H */ diff --git a/code/opus-1.0.2/celt/bands.c b/code/opus-1.0.2/celt/bands.c new file mode 100644 index 00000000..3be543c3 --- /dev/null +++ b/code/opus-1.0.2/celt/bands.c @@ -0,0 +1,1302 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2008-2009 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "bands.h" +#include "modes.h" +#include "vq.h" +#include "cwrs.h" +#include "stack_alloc.h" +#include "os_support.h" +#include "mathops.h" +#include "rate.h" + +opus_uint32 celt_lcg_rand(opus_uint32 seed) +{ + return 1664525 * seed + 1013904223; +} + +/* This is a cos() approximation designed to be bit-exact on any platform. Bit exactness + with this approximation is important because it has an impact on the bit allocation */ +static opus_int16 bitexact_cos(opus_int16 x) +{ + opus_int32 tmp; + opus_int16 x2; + tmp = (4096+((opus_int32)(x)*(x)))>>13; + celt_assert(tmp<=32767); + x2 = tmp; + x2 = (32767-x2) + FRAC_MUL16(x2, (-7651 + FRAC_MUL16(x2, (8277 + FRAC_MUL16(-626, x2))))); + celt_assert(x2<=32766); + return 1+x2; +} + +static int bitexact_log2tan(int isin,int icos) +{ + int lc; + int ls; + lc=EC_ILOG(icos); + ls=EC_ILOG(isin); + icos<<=15-lc; + isin<<=15-ls; + return (ls-lc)*(1<<11) + +FRAC_MUL16(isin, FRAC_MUL16(isin, -2597) + 7932) + -FRAC_MUL16(icos, FRAC_MUL16(icos, -2597) + 7932); +} + +#ifdef FIXED_POINT +/* Compute the amplitude (sqrt energy) in each of the bands */ +void compute_band_energies(const CELTMode *m, const celt_sig *X, celt_ener *bandE, int end, int C, int M) +{ + int i, c, N; + const opus_int16 *eBands = m->eBands; + N = M*m->shortMdctSize; + c=0; do { + for (i=0;i 0) + { + int shift = celt_ilog2(maxval)-10; + j=M*eBands[i]; do { + sum = MAC16_16(sum, EXTRACT16(VSHR32(X[j+c*N],shift)), + EXTRACT16(VSHR32(X[j+c*N],shift))); + } while (++jnbEBands] = EPSILON+VSHR32(EXTEND32(celt_sqrt(sum)),-shift); + } else { + bandE[i+c*m->nbEBands] = EPSILON; + } + /*printf ("%f ", bandE[i+c*m->nbEBands]);*/ + } + } while (++ceBands; + N = M*m->shortMdctSize; + c=0; do { + i=0; do { + opus_val16 g; + int j,shift; + opus_val16 E; + shift = celt_zlog2(bandE[i+c*m->nbEBands])-13; + E = VSHR32(bandE[i+c*m->nbEBands], shift); + g = EXTRACT16(celt_rcp(SHL32(E,3))); + j=M*eBands[i]; do { + X[j+c*N] = MULT16_16_Q15(VSHR32(freq[j+c*N],shift-1),g); + } while (++jeBands; + N = M*m->shortMdctSize; + c=0; do { + for (i=0;inbEBands] = celt_sqrt(sum); + /*printf ("%f ", bandE[i+c*m->nbEBands]);*/ + } + } while (++ceBands; + N = M*m->shortMdctSize; + c=0; do { + for (i=0;inbEBands]); + for (j=M*eBands[i];jeBands; + N = M*m->shortMdctSize; + celt_assert2(C<=2, "denormalise_bands() not implemented for >2 channels"); + c=0; do { + celt_sig * OPUS_RESTRICT f; + const celt_norm * OPUS_RESTRICT x; + f = freq+c*N; + x = X+c*N; + for (i=0;inbEBands],1); + j=M*eBands[i]; + band_end = M*eBands[i+1]; + do { + *f++ = SHL32(MULT16_32_Q15(*x, g),2); + x++; + } while (++jeBands[i+1]-m->eBands[i]; + /* depth in 1/8 bits */ + depth = (1+pulses[i])/((m->eBands[i+1]-m->eBands[i])<>1; + t = SHL32(t, (7-shift)<<1); + sqrt_1 = celt_rsqrt_norm(t); + } +#else + thresh = .5f*celt_exp2(-.125f*depth); + sqrt_1 = celt_rsqrt(N0<nbEBands+i]; + prev2 = prev2logE[c*m->nbEBands+i]; + if (C==1) + { + prev1 = MAX16(prev1,prev1logE[m->nbEBands+i]); + prev2 = MAX16(prev2,prev2logE[m->nbEBands+i]); + } + Ediff = EXTEND32(logE[c*m->nbEBands+i])-EXTEND32(MIN16(prev1,prev2)); + Ediff = MAX32(0, Ediff); + +#ifdef FIXED_POINT + if (Ediff < 16384) + { + opus_val32 r32 = SHR32(celt_exp2(-EXTRACT16(Ediff)),1); + r = 2*MIN16(16383,r32); + } else { + r = 0; + } + if (LM==3) + r = MULT16_16_Q14(23170, MIN32(23169, r)); + r = SHR16(MIN16(thresh, r),1); + r = SHR32(MULT16_16_Q15(sqrt_1, r),shift); +#else + /* r needs to be multiplied by 2 or 2*sqrt(2) depending on LM because + short blocks don't have the same energy as long */ + r = 2.f*celt_exp2(-Ediff); + if (LM==3) + r *= 1.41421356f; + r = MIN16(thresh, r); + r = r*sqrt_1; +#endif + X = X_+c*size+(m->eBands[i]<nbEBands]))-13; +#endif + left = VSHR32(bandE[i],shift); + right = VSHR32(bandE[i+m->nbEBands],shift); + norm = EPSILON + celt_sqrt(EPSILON+MULT16_16(left,left)+MULT16_16(right,right)); + a1 = DIV32_16(SHL32(EXTEND32(left),14),norm); + a2 = DIV32_16(SHL32(EXTEND32(right),14),norm); + for (j=0;j>1; + kr = celt_ilog2(Er)>>1; +#endif + t = VSHR32(El, (kl-7)<<1); + lgain = celt_rsqrt_norm(t); + t = VSHR32(Er, (kr-7)<<1); + rgain = celt_rsqrt_norm(t); + +#ifdef FIXED_POINT + if (kl < 7) + kl = 7; + if (kr < 7) + kr = 7; +#endif + + for (j=0;jeBands; + int decision; + int hf_sum=0; + + celt_assert(end>0); + + N0 = M*m->shortMdctSize; + + if (M*(eBands[end]-eBands[end-1]) <= 8) + return SPREAD_NONE; + c=0; do { + for (i=0;im->nbEBands-4) + hf_sum += 32*(tcount[1]+tcount[0])/N; + tmp = (2*tcount[2] >= N) + (2*tcount[1] >= N) + (2*tcount[0] >= N); + sum += tmp*256; + nbBands++; + } + } while (++cnbEBands+end); + *hf_average = (*hf_average+hf_sum)>>1; + hf_sum = *hf_average; + if (*tapset_decision==2) + hf_sum += 4; + else if (*tapset_decision==0) + hf_sum -= 4; + if (hf_sum > 22) + *tapset_decision=2; + else if (hf_sum > 18) + *tapset_decision=1; + else + *tapset_decision=0; + } + /*printf("%d %d %d\n", hf_sum, *hf_average, *tapset_decision);*/ + celt_assert(nbBands>0); /*M*(eBands[end]-eBands[end-1]) <= 8 assures this*/ + sum /= nbBands; + /* Recursive averaging */ + sum = (sum+*average)>>1; + *average = sum; + /* Hysteresis */ + sum = (3*sum + (((3-last_decision)<<7) + 64) + 2)>>2; + if (sum < 80) + { + decision = SPREAD_AGGRESSIVE; + } else if (sum < 256) + { + decision = SPREAD_NORMAL; + } else if (sum < 384) + { + decision = SPREAD_LIGHT; + } else { + decision = SPREAD_NONE; + } +#ifdef FUZZING + decision = rand()&0x3; + *tapset_decision=rand()%3; +#endif + return decision; +} + +#ifdef MEASURE_NORM_MSE + +float MSE[30] = {0}; +int nbMSEBands = 0; +int MSECount[30] = {0}; + +void dump_norm_mse(void) +{ + int i; + for (i=0;inbEBands;i++) + { + int j; + int c; + float g; + if (bandE0[i]<10 || (C==2 && bandE0[i+m->nbEBands]<1)) + continue; + c=0; do { + g = bandE[i+c*m->nbEBands]/(1e-15+bandE0[i+c*m->nbEBands]); + for (j=M*m->eBands[i];jeBands[i+1];j++) + MSE[i] += (g*X[j+c*N]-X0[j+c*N])*(g*X[j+c*N]-X0[j+c*N]); + } while (++cnbEBands; +} + +#endif + +/* Indexing table for converting from natural Hadamard to ordery Hadamard + This is essentially a bit-reversed Gray, on top of which we've added + an inversion of the order because we want the DC at the end rather than + the beginning. The lines are for N=2, 4, 8, 16 */ +static const int ordery_table[] = { + 1, 0, + 3, 0, 2, 1, + 7, 0, 4, 3, 6, 1, 5, 2, + 15, 0, 8, 7, 12, 3, 11, 4, 14, 1, 9, 6, 13, 2, 10, 5, +}; + +static void deinterleave_hadamard(celt_norm *X, int N0, int stride, int hadamard) +{ + int i,j; + VARDECL(celt_norm, tmp); + int N; + SAVE_STACK; + N = N0*stride; + ALLOC(tmp, N, celt_norm); + celt_assert(stride>0); + if (hadamard) + { + const int *ordery = ordery_table+stride-2; + for (i=0;i>= 1; + for (i=0;i>1)) { + qn = 1; + } else { + qn = exp2_table8[qb&0x7]>>(14-(qb>>BITRES)); + qn = (qn+1)>>1<<1; + } + celt_assert(qn <= 256); + return qn; +} + +/* This function is responsible for encoding and decoding a band for both + the mono and stereo case. Even in the mono case, it can split the band + in two and transmit the energy difference with the two half-bands. It + can be called recursively so bands can end up being split in 8 parts. */ +static unsigned quant_band(int encode, const CELTMode *m, int i, celt_norm *X, celt_norm *Y, + int N, int b, int spread, int B, int intensity, int tf_change, celt_norm *lowband, ec_ctx *ec, + opus_int32 *remaining_bits, int LM, celt_norm *lowband_out, const celt_ener *bandE, int level, + opus_uint32 *seed, opus_val16 gain, celt_norm *lowband_scratch, int fill) +{ + const unsigned char *cache; + int q; + int curr_bits; + int stereo, split; + int imid=0, iside=0; + int N0=N; + int N_B=N; + int N_B0; + int B0=B; + int time_divide=0; + int recombine=0; + int inv = 0; + opus_val16 mid=0, side=0; + int longBlocks; + unsigned cm=0; +#ifdef RESYNTH + int resynth = 1; +#else + int resynth = !encode; +#endif + + longBlocks = B0==1; + + N_B /= B; + N_B0 = N_B; + + split = stereo = Y != NULL; + + /* Special case for one sample */ + if (N==1) + { + int c; + celt_norm *x = X; + c=0; do { + int sign=0; + if (*remaining_bits>=1<0) + recombine = tf_change; + /* Band recombining to increase frequency resolution */ + + if (lowband && (recombine || ((N_B&1) == 0 && tf_change<0) || B0>1)) + { + int j; + for (j=0;j>k, 1<>k, 1<>4]<<2; + } + B>>=recombine; + N_B<<=recombine; + + /* Increasing the time resolution */ + while ((N_B&1) == 0 && tf_change<0) + { + if (encode) + haar1(X, N_B, B); + if (lowband) + haar1(lowband, N_B, B); + fill |= fill<>= 1; + time_divide++; + tf_change++; + } + B0=B; + N_B0 = N_B; + + /* Reorganize the samples in time order instead of frequency order */ + if (B0>1) + { + if (encode) + deinterleave_hadamard(X, N_B>>recombine, B0<>recombine, B0<cache.bits + m->cache.index[(LM+1)*m->nbEBands+i]; + if (!stereo && LM != -1 && b > cache[cache[0]]+12 && N>2) + { + N >>= 1; + Y = X+N; + split = 1; + LM -= 1; + if (B==1) + fill = (fill&1)|(fill<<1); + B = (B+1)>>1; + } + + if (split) + { + int qn; + int itheta=0; + int mbits, sbits, delta; + int qalloc; + int pulse_cap; + int offset; + int orig_fill; + opus_int32 tell; + + /* Decide on the resolution to give to the split parameter theta */ + pulse_cap = m->logN[i]+LM*(1<>1) - (stereo&&N==2 ? QTHETA_OFFSET_TWOPHASE : QTHETA_OFFSET); + qn = compute_qn(N, b, offset, pulse_cap, stereo); + if (stereo && i>=intensity) + qn = 1; + if (encode) + { + /* theta is the atan() of the ratio between the (normalized) + side and mid. With just that parameter, we can re-scale both + mid and side because we know that 1) they have unit norm and + 2) they are orthogonal. */ + itheta = stereo_itheta(X, Y, stereo, N); + } + tell = ec_tell_frac(ec); + if (qn!=1) + { + if (encode) + itheta = (itheta*qn+8192)>>14; + + /* Entropy coding of the angle. We use a uniform pdf for the + time split, a step for stereo, and a triangular one for the rest. */ + if (stereo && N>2) + { + int p0 = 3; + int x = itheta; + int x0 = qn/2; + int ft = p0*(x0+1) + x0; + /* Use a probability of p0 up to itheta=8192 and then use 1 after */ + if (encode) + { + ec_encode(ec,x<=x0?p0*x:(x-1-x0)+(x0+1)*p0,x<=x0?p0*(x+1):(x-x0)+(x0+1)*p0,ft); + } else { + int fs; + fs=ec_decode(ec,ft); + if (fs<(x0+1)*p0) + x=fs/p0; + else + x=x0+1+(fs-(x0+1)*p0); + ec_dec_update(ec,x<=x0?p0*x:(x-1-x0)+(x0+1)*p0,x<=x0?p0*(x+1):(x-x0)+(x0+1)*p0,ft); + itheta = x; + } + } else if (B0>1 || stereo) { + /* Uniform pdf */ + if (encode) + ec_enc_uint(ec, itheta, qn+1); + else + itheta = ec_dec_uint(ec, qn+1); + } else { + int fs=1, ft; + ft = ((qn>>1)+1)*((qn>>1)+1); + if (encode) + { + int fl; + + fs = itheta <= (qn>>1) ? itheta + 1 : qn + 1 - itheta; + fl = itheta <= (qn>>1) ? itheta*(itheta + 1)>>1 : + ft - ((qn + 1 - itheta)*(qn + 2 - itheta)>>1); + + ec_encode(ec, fl, fl+fs, ft); + } else { + /* Triangular pdf */ + int fl=0; + int fm; + fm = ec_decode(ec, ft); + + if (fm < ((qn>>1)*((qn>>1) + 1)>>1)) + { + itheta = (isqrt32(8*(opus_uint32)fm + 1) - 1)>>1; + fs = itheta + 1; + fl = itheta*(itheta + 1)>>1; + } + else + { + itheta = (2*(qn + 1) + - isqrt32(8*(opus_uint32)(ft - fm - 1) + 1))>>1; + fs = qn + 1 - itheta; + fl = ft - ((qn + 1 - itheta)*(qn + 2 - itheta)>>1); + } + + ec_dec_update(ec, fl, fl+fs, ft); + } + } + itheta = (opus_int32)itheta*16384/qn; + if (encode && stereo) + { + if (itheta==0) + intensity_stereo(m, X, Y, bandE, i, N); + else + stereo_split(X, Y, N); + } + /* NOTE: Renormalising X and Y *may* help fixed-point a bit at very high rate. + Let's do that at higher complexity */ + } else if (stereo) { + if (encode) + { + inv = itheta > 8192; + if (inv) + { + int j; + for (j=0;j2< 2< 8192; + *remaining_bits -= qalloc+sbits; + + x2 = c ? Y : X; + y2 = c ? X : Y; + if (sbits) + { + if (encode) + { + /* Here we only need to encode a sign for the side */ + sign = x2[0]*y2[1] - x2[1]*y2[0] < 0; + ec_enc_bits(ec, sign, 1); + } else { + sign = ec_dec_bits(ec, 1); + } + } + sign = 1-2*sign; + /* We use orig_fill here because we want to fold the side, but if + itheta==16384, we'll have cleared the low bits of fill. */ + cm = quant_band(encode, m, i, x2, NULL, N, mbits, spread, B, intensity, tf_change, lowband, ec, remaining_bits, LM, lowband_out, NULL, level, seed, gain, lowband_scratch, orig_fill); + /* We don't split N=2 bands, so cm is either 1 or 0 (for a fold-collapse), + and there's no need to worry about mixing with the other channel. */ + y2[0] = -sign*x2[1]; + y2[1] = sign*x2[0]; + if (resynth) + { + celt_norm tmp; + X[0] = MULT16_16_Q15(mid, X[0]); + X[1] = MULT16_16_Q15(mid, X[1]); + Y[0] = MULT16_16_Q15(side, Y[0]); + Y[1] = MULT16_16_Q15(side, Y[1]); + tmp = X[0]; + X[0] = SUB16(tmp,Y[0]); + Y[0] = ADD16(tmp,Y[0]); + tmp = X[1]; + X[1] = SUB16(tmp,Y[1]); + Y[1] = ADD16(tmp,Y[1]); + } + } else { + /* "Normal" split code */ + celt_norm *next_lowband2=NULL; + celt_norm *next_lowband_out1=NULL; + int next_level=0; + opus_int32 rebalance; + + /* Give more bits to low-energy MDCTs than they would otherwise deserve */ + if (B0>1 && !stereo && (itheta&0x3fff)) + { + if (itheta > 8192) + /* Rough approximation for pre-echo masking */ + delta -= delta>>(4-LM); + else + /* Corresponds to a forward-masking slope of 1.5 dB per 10 ms */ + delta = IMIN(0, delta + (N<>(5-LM))); + } + mbits = IMAX(0, IMIN(b, (b-delta)/2)); + sbits = b-mbits; + *remaining_bits -= qalloc; + + if (lowband && !stereo) + next_lowband2 = lowband+N; /* >32-bit split case */ + + /* Only stereo needs to pass on lowband_out. Otherwise, it's + handled at the end */ + if (stereo) + next_lowband_out1 = lowband_out; + else + next_level = level+1; + + rebalance = *remaining_bits; + if (mbits >= sbits) + { + /* In stereo mode, we do not apply a scaling to the mid because we need the normalized + mid for folding later */ + cm = quant_band(encode, m, i, X, NULL, N, mbits, spread, B, intensity, tf_change, + lowband, ec, remaining_bits, LM, next_lowband_out1, + NULL, next_level, seed, stereo ? Q15ONE : MULT16_16_P15(gain,mid), lowband_scratch, fill); + rebalance = mbits - (rebalance-*remaining_bits); + if (rebalance > 3<>B)<<((B0>>1)&(stereo-1)); + } else { + /* For a stereo split, the high bits of fill are always zero, so no + folding will be done to the side. */ + cm = quant_band(encode, m, i, Y, NULL, N, sbits, spread, B, intensity, tf_change, + next_lowband2, ec, remaining_bits, LM, NULL, + NULL, next_level, seed, MULT16_16_P15(gain,side), NULL, fill>>B)<<((B0>>1)&(stereo-1)); + rebalance = sbits - (rebalance-*remaining_bits); + if (rebalance > 3< 0) + { + *remaining_bits += curr_bits; + q--; + curr_bits = pulses2bits(m, i, LM, q); + *remaining_bits -= curr_bits; + } + + if (q!=0) + { + int K = get_pulses(q); + + /* Finally do the actual quantization */ + if (encode) + { + cm = alg_quant(X, N, K, spread, B, ec +#ifdef RESYNTH + , gain +#endif + ); + } else { + cm = alg_unquant(X, N, K, spread, B, ec, gain); + } + } else { + /* If there's no pulse, fill the band anyway */ + int j; + if (resynth) + { + unsigned cm_mask; + /*B can be as large as 16, so this shift might overflow an int on a + 16-bit platform; use a long to get defined behavior.*/ + cm_mask = (unsigned)(1UL<>20); + } + cm = cm_mask; + } else { + /* Folded spectrum */ + for (j=0;j1) + interleave_hadamard(X, N_B>>recombine, B0<>= 1; + N_B <<= 1; + cm |= cm>>B; + haar1(X, N_B, B); + } + + for (k=0;k>k, 1<eBands; + celt_norm * OPUS_RESTRICT norm, * OPUS_RESTRICT norm2; + VARDECL(celt_norm, _norm); + VARDECL(celt_norm, lowband_scratch); + int B; + int M; + int lowband_offset; + int update_lowband = 1; + int C = Y_ != NULL ? 2 : 1; +#ifdef RESYNTH + int resynth = 1; +#else + int resynth = !encode; +#endif + SAVE_STACK; + + M = 1<nbEBands], celt_norm); + ALLOC(lowband_scratch, M*(eBands[m->nbEBands]-eBands[m->nbEBands-1]), celt_norm); + norm = _norm; + norm2 = norm + M*eBands[m->nbEBands]; + + lowband_offset = 0; + for (i=start;i= M*eBands[start] && (update_lowband || lowband_offset==0)) + lowband_offset = i; + + tf_change = tf_res[i]; + if (i>=m->effEBands) + { + X=norm; + if (Y_!=NULL) + Y = norm; + } + + /* Get a conservative estimate of the collapse_mask's for the bands we're + going to be folding from. */ + if (lowband_offset != 0 && (spread!=SPREAD_AGGRESSIVE || B>1 || tf_change<0)) + { + int fold_start; + int fold_end; + int fold_i; + /* This ensures we never repeat spectral content within one band */ + effective_lowband = IMAX(M*eBands[start], M*eBands[lowband_offset]-N); + fold_start = lowband_offset; + while(M*eBands[--fold_start] > effective_lowband); + fold_end = lowband_offset-1; + while(M*eBands[++fold_end] < effective_lowband+N); + x_cm = y_cm = 0; + fold_i = fold_start; do { + x_cm |= collapse_masks[fold_i*C+0]; + y_cm |= collapse_masks[fold_i*C+C-1]; + } while (++fold_i(N< +#include "celt.h" +#include "pitch.h" +#include "bands.h" +#include "modes.h" +#include "entcode.h" +#include "quant_bands.h" +#include "rate.h" +#include "stack_alloc.h" +#include "mathops.h" +#include "float_cast.h" +#include +#include "celt_lpc.h" +#include "vq.h" + +#ifndef OPUS_VERSION +#define OPUS_VERSION "unknown" +#endif + +#ifdef CUSTOM_MODES +#define OPUS_CUSTOM_NOSTATIC +#else +#define OPUS_CUSTOM_NOSTATIC static inline +#endif + +static const unsigned char trim_icdf[11] = {126, 124, 119, 109, 87, 41, 19, 9, 4, 2, 0}; +/* Probs: NONE: 21.875%, LIGHT: 6.25%, NORMAL: 65.625%, AGGRESSIVE: 6.25% */ +static const unsigned char spread_icdf[4] = {25, 23, 2, 0}; + +static const unsigned char tapset_icdf[3]={2,1,0}; + +#ifdef CUSTOM_MODES +static const unsigned char toOpusTable[20] = { + 0xE0, 0xE8, 0xF0, 0xF8, + 0xC0, 0xC8, 0xD0, 0xD8, + 0xA0, 0xA8, 0xB0, 0xB8, + 0x00, 0x00, 0x00, 0x00, + 0x80, 0x88, 0x90, 0x98, +}; + +static const unsigned char fromOpusTable[16] = { + 0x80, 0x88, 0x90, 0x98, + 0x40, 0x48, 0x50, 0x58, + 0x20, 0x28, 0x30, 0x38, + 0x00, 0x08, 0x10, 0x18 +}; + +static inline int toOpus(unsigned char c) +{ + int ret=0; + if (c<0xA0) + ret = toOpusTable[c>>3]; + if (ret == 0) + return -1; + else + return ret|(c&0x7); +} + +static inline int fromOpus(unsigned char c) +{ + if (c<0x80) + return -1; + else + return fromOpusTable[(c>>3)-16] | (c&0x7); +} +#endif /* CUSTOM_MODES */ + +#define COMBFILTER_MAXPERIOD 1024 +#define COMBFILTER_MINPERIOD 15 + +static int resampling_factor(opus_int32 rate) +{ + int ret; + switch (rate) + { + case 48000: + ret = 1; + break; + case 24000: + ret = 2; + break; + case 16000: + ret = 3; + break; + case 12000: + ret = 4; + break; + case 8000: + ret = 6; + break; + default: +#ifndef CUSTOM_MODES + celt_assert(0); +#endif + ret = 0; + break; + } + return ret; +} + +/** Encoder state + @brief Encoder state + */ +struct OpusCustomEncoder { + const OpusCustomMode *mode; /**< Mode used by the encoder */ + int overlap; + int channels; + int stream_channels; + + int force_intra; + int clip; + int disable_pf; + int complexity; + int upsample; + int start, end; + + opus_int32 bitrate; + int vbr; + int signalling; + int constrained_vbr; /* If zero, VBR can do whatever it likes with the rate */ + int loss_rate; + int lsb_depth; + + /* Everything beyond this point gets cleared on a reset */ +#define ENCODER_RESET_START rng + + opus_uint32 rng; + int spread_decision; + opus_val32 delayedIntra; + int tonal_average; + int lastCodedBands; + int hf_average; + int tapset_decision; + + int prefilter_period; + opus_val16 prefilter_gain; + int prefilter_tapset; +#ifdef RESYNTH + int prefilter_period_old; + opus_val16 prefilter_gain_old; + int prefilter_tapset_old; +#endif + int consec_transient; + + opus_val32 preemph_memE[2]; + opus_val32 preemph_memD[2]; + + /* VBR-related parameters */ + opus_int32 vbr_reservoir; + opus_int32 vbr_drift; + opus_int32 vbr_offset; + opus_int32 vbr_count; + +#ifdef RESYNTH + celt_sig syn_mem[2][2*MAX_PERIOD]; +#endif + + celt_sig in_mem[1]; /* Size = channels*mode->overlap */ + /* celt_sig prefilter_mem[], Size = channels*COMBFILTER_MAXPERIOD */ + /* opus_val16 oldBandE[], Size = channels*mode->nbEBands */ + /* opus_val16 oldLogE[], Size = channels*mode->nbEBands */ + /* opus_val16 oldLogE2[], Size = channels*mode->nbEBands */ +#ifdef RESYNTH + /* opus_val16 overlap_mem[], Size = channels*overlap */ +#endif +}; + +int celt_encoder_get_size(int channels) +{ + CELTMode *mode = opus_custom_mode_create(48000, 960, NULL); + return opus_custom_encoder_get_size(mode, channels); +} + +OPUS_CUSTOM_NOSTATIC int opus_custom_encoder_get_size(const CELTMode *mode, int channels) +{ + int size = sizeof(struct CELTEncoder) + + (channels*mode->overlap-1)*sizeof(celt_sig) /* celt_sig in_mem[channels*mode->overlap]; */ + + channels*COMBFILTER_MAXPERIOD*sizeof(celt_sig) /* celt_sig prefilter_mem[channels*COMBFILTER_MAXPERIOD]; */ + + 3*channels*mode->nbEBands*sizeof(opus_val16); /* opus_val16 oldBandE[channels*mode->nbEBands]; */ + /* opus_val16 oldLogE[channels*mode->nbEBands]; */ + /* opus_val16 oldLogE2[channels*mode->nbEBands]; */ +#ifdef RESYNTH + size += channels*mode->overlap*sizeof(celt_sig); /* celt_sig overlap_mem[channels*mode->nbEBands]; */ +#endif + return size; +} + +#ifdef CUSTOM_MODES +CELTEncoder *opus_custom_encoder_create(const CELTMode *mode, int channels, int *error) +{ + int ret; + CELTEncoder *st = (CELTEncoder *)opus_alloc(opus_custom_encoder_get_size(mode, channels)); + /* init will handle the NULL case */ + ret = opus_custom_encoder_init(st, mode, channels); + if (ret != OPUS_OK) + { + opus_custom_encoder_destroy(st); + st = NULL; + } + if (error) + *error = ret; + return st; +} +#endif /* CUSTOM_MODES */ + +int celt_encoder_init(CELTEncoder *st, opus_int32 sampling_rate, int channels) +{ + int ret; + ret = opus_custom_encoder_init(st, opus_custom_mode_create(48000, 960, NULL), channels); + if (ret != OPUS_OK) + return ret; + st->upsample = resampling_factor(sampling_rate); + return OPUS_OK; +} + +OPUS_CUSTOM_NOSTATIC int opus_custom_encoder_init(CELTEncoder *st, const CELTMode *mode, int channels) +{ + if (channels < 0 || channels > 2) + return OPUS_BAD_ARG; + + if (st==NULL || mode==NULL) + return OPUS_ALLOC_FAIL; + + OPUS_CLEAR((char*)st, opus_custom_encoder_get_size(mode, channels)); + + st->mode = mode; + st->overlap = mode->overlap; + st->stream_channels = st->channels = channels; + + st->upsample = 1; + st->start = 0; + st->end = st->mode->effEBands; + st->signalling = 1; + + st->constrained_vbr = 1; + st->clip = 1; + + st->bitrate = OPUS_BITRATE_MAX; + st->vbr = 0; + st->force_intra = 0; + st->complexity = 5; + st->lsb_depth=24; + + opus_custom_encoder_ctl(st, OPUS_RESET_STATE); + + return OPUS_OK; +} + +#ifdef CUSTOM_MODES +void opus_custom_encoder_destroy(CELTEncoder *st) +{ + opus_free(st); +} +#endif /* CUSTOM_MODES */ + +static inline opus_val16 SIG2WORD16(celt_sig x) +{ +#ifdef FIXED_POINT + x = PSHR32(x, SIG_SHIFT); + x = MAX32(x, -32768); + x = MIN32(x, 32767); + return EXTRACT16(x); +#else + return (opus_val16)x; +#endif +} + +static int transient_analysis(const opus_val32 * OPUS_RESTRICT in, int len, int C, + int overlap) +{ + int i; + VARDECL(opus_val16, tmp); + opus_val32 mem0=0,mem1=0; + int is_transient = 0; + int block; + int N; + VARDECL(opus_val16, bins); + SAVE_STACK; + ALLOC(tmp, len, opus_val16); + + block = overlap/2; + N=len/block; + ALLOC(bins, N, opus_val16); + if (C==1) + { + for (i=0;i=3) + is_transient=1; + conseq = 0; + for (j=i+1;j=7) + is_transient=1; + } + RESTORE_STACK; +#ifdef FUZZING + is_transient = rand()&0x1; +#endif + return is_transient; +} + +/** Apply window and compute the MDCT for all sub-frames and + all channels in a frame */ +static void compute_mdcts(const CELTMode *mode, int shortBlocks, celt_sig * OPUS_RESTRICT in, celt_sig * OPUS_RESTRICT out, int C, int LM) +{ + if (C==1 && !shortBlocks) + { + const int overlap = OVERLAP(mode); + clt_mdct_forward(&mode->mdct, in, out, mode->window, overlap, mode->maxLM-LM, 1); + } else { + const int overlap = OVERLAP(mode); + int N = mode->shortMdctSize<shortMdctSize; + B = shortBlocks; + } + c=0; do { + for (b=0;bmdct, in+c*(B*N+overlap)+b*N, &out[b+c*N*B], mode->window, overlap, shortBlocks ? mode->maxLM : mode->maxLM-LM, B); + } + } while (++cshortMdctSize<shortMdctSize; + B = shortBlocks; + } + /* Prevents problems from the imdct doing the overlap-add */ + OPUS_CLEAR(x, overlap); + + for (b=0;bmdct, &X[b+c*N2*B], x+N2*b, mode->window, overlap, shortBlocks ? mode->maxLM : mode->maxLM-LM, B); + } + + for (j=0;j>LM;j++) + L2 = MAC16_16(L2, tmp[(j<eBands[len]-m->eBands[len-1])<eBands[i+1]-m->eBands[i])<eBands[i]<eBands[i]<>LM); + best_L1 = L1; + /*printf ("%f ", L1);*/ + for (k=0;k>(LM-k), 1<<(LM-k)); + else + haar1(tmp, N>>k, 1<>LM); + + if (L1 < best_L1) + { + best_L1 = L1; + best_level = k+1; + } + } + /*printf ("%d ", isTransient ? LM-best_level : best_level);*/ + if (isTransient) + metric[i] = best_level; + else + metric[i] = -best_level; + *tf_sum += metric[i]; + } + /*printf("\n");*/ + /* NOTE: Future optimized implementations could detect extreme transients and set + tf_select = 1 but so far we have not found a reliable way of making this useful */ + tf_select = 0; + + cost0 = 0; + cost1 = isTransient ? 0 : lambda; + /* Viterbi forward pass */ + for (i=1;i=0;i--) + { + if (tf_res[i+1] == 1) + tf_res[i] = path1[i+1]; + else + tf_res[i] = path0[i+1]; + } + RESTORE_STACK; +#ifdef FUZZING + tf_select = rand()&0x1; + tf_res[0] = rand()&0x1; + for (i=1;istorage*8; + tell = ec_tell(enc); + logp = isTransient ? 2 : 4; + /* Reserve space to code the tf_select decision. */ + tf_select_rsv = LM>0 && tell+logp+1 <= budget; + budget -= tf_select_rsv; + curr = tf_changed = 0; + for (i=start;istorage*8; + tell = ec_tell(dec); + logp = isTransient ? 2 : 4; + tf_select_rsv = LM>0 && tell+logp+1<=budget; + budget -= tf_select_rsv; + tf_changed = curr = 0; + for (i=start;inbEBands;i++) + { + int N; + N=(m->eBands[i+1]-m->eBands[i])<cache.caps[m->nbEBands*(2*LM+C-1)+i]+64)*C*N>>2; + } +} + +static int alloc_trim_analysis(const CELTMode *m, const celt_norm *X, + const opus_val16 *bandLogE, int end, int LM, int C, int N0) +{ + int i; + opus_val32 diff=0; + int c; + int trim_index = 5; + if (C==2) + { + opus_val16 sum = 0; /* Q10 */ + /* Compute inter-channel correlation for low frequencies */ + for (i=0;i<8;i++) + { + int j; + opus_val32 partial = 0; + for (j=m->eBands[i]<eBands[i+1]< QCONST16(.995f,10)) + trim_index-=4; + else if (sum > QCONST16(.92f,10)) + trim_index-=3; + else if (sum > QCONST16(.85f,10)) + trim_index-=2; + else if (sum > QCONST16(.8f,10)) + trim_index-=1; + } + + /* Estimate spectral tilt */ + c=0; do { + for (i=0;inbEBands]*(opus_int32)(2+2*i-m->nbEBands); + } + } while (++c QCONST16(2.f, DB_SHIFT)) + trim_index--; + if (diff > QCONST16(8.f, DB_SHIFT)) + trim_index--; + if (diff < -QCONST16(4.f, DB_SHIFT)) + trim_index++; + if (diff < -QCONST16(10.f, DB_SHIFT)) + trim_index++; + + if (trim_index<0) + trim_index = 0; + if (trim_index>10) + trim_index = 10; +#ifdef FUZZING + trim_index = rand()%11; +#endif + return trim_index; +} + +static int stereo_analysis(const CELTMode *m, const celt_norm *X, + int LM, int N0) +{ + int i; + int thetas; + opus_val32 sumLR = EPSILON, sumMS = EPSILON; + + /* Use the L1 norm to model the entropy of the L/R signal vs the M/S signal */ + for (i=0;i<13;i++) + { + int j; + for (j=m->eBands[i]<eBands[i+1]<eBands[13]<<(LM+1))+thetas, sumMS) + > MULT16_32_Q15(m->eBands[13]<<(LM+1), sumLR); +} + +int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc) +{ + int i, c, N; + opus_int32 bits; + ec_enc _enc; + VARDECL(celt_sig, in); + VARDECL(celt_sig, freq); + VARDECL(celt_norm, X); + VARDECL(celt_ener, bandE); + VARDECL(opus_val16, bandLogE); + VARDECL(int, fine_quant); + VARDECL(opus_val16, error); + VARDECL(int, pulses); + VARDECL(int, cap); + VARDECL(int, offsets); + VARDECL(int, fine_priority); + VARDECL(int, tf_res); + VARDECL(unsigned char, collapse_masks); + celt_sig *prefilter_mem; + opus_val16 *oldBandE, *oldLogE, *oldLogE2; + int shortBlocks=0; + int isTransient=0; + const int CC = st->channels; + const int C = st->stream_channels; + int LM, M; + int tf_select; + int nbFilledBytes, nbAvailableBytes; + int effEnd; + int codedBands; + int tf_sum; + int alloc_trim; + int pitch_index=COMBFILTER_MINPERIOD; + opus_val16 gain1 = 0; + int intensity=0; + int dual_stereo=0; + int effectiveBytes; + opus_val16 pf_threshold; + int dynalloc_logp; + opus_int32 vbr_rate; + opus_int32 total_bits; + opus_int32 total_boost; + opus_int32 balance; + opus_int32 tell; + int prefilter_tapset=0; + int pf_on; + int anti_collapse_rsv; + int anti_collapse_on=0; + int silence=0; + ALLOC_STACK; + + if (nbCompressedBytes<2 || pcm==NULL) + return OPUS_BAD_ARG; + + frame_size *= st->upsample; + for (LM=0;LM<=st->mode->maxLM;LM++) + if (st->mode->shortMdctSize<st->mode->maxLM) + return OPUS_BAD_ARG; + M=1<mode->shortMdctSize; + + prefilter_mem = st->in_mem+CC*(st->overlap); + oldBandE = (opus_val16*)(st->in_mem+CC*(st->overlap+COMBFILTER_MAXPERIOD)); + oldLogE = oldBandE + CC*st->mode->nbEBands; + oldLogE2 = oldLogE + CC*st->mode->nbEBands; + + if (enc==NULL) + { + tell=1; + nbFilledBytes=0; + } else { + tell=ec_tell(enc); + nbFilledBytes=(tell+4)>>3; + } + +#ifdef CUSTOM_MODES + if (st->signalling && enc==NULL) + { + int tmp = (st->mode->effEBands-st->end)>>1; + st->end = IMAX(1, st->mode->effEBands-tmp); + compressed[0] = tmp<<5; + compressed[0] |= LM<<3; + compressed[0] |= (C==2)<<2; + /* Convert "standard mode" to Opus header */ + if (st->mode->Fs==48000 && st->mode->shortMdctSize==120) + { + int c0 = toOpus(compressed[0]); + if (c0<0) + return OPUS_BAD_ARG; + compressed[0] = c0; + } + compressed++; + nbCompressedBytes--; + } +#else + celt_assert(st->signalling==0); +#endif + + /* Can't produce more than 1275 output bytes */ + nbCompressedBytes = IMIN(nbCompressedBytes,1275); + nbAvailableBytes = nbCompressedBytes - nbFilledBytes; + + if (st->vbr && st->bitrate!=OPUS_BITRATE_MAX) + { + opus_int32 den=st->mode->Fs>>BITRES; + vbr_rate=(st->bitrate*frame_size+(den>>1))/den; +#ifdef CUSTOM_MODES + if (st->signalling) + vbr_rate -= 8<>(3+BITRES); + } else { + opus_int32 tmp; + vbr_rate = 0; + tmp = st->bitrate*frame_size; + if (tell>1) + tmp += tell; + if (st->bitrate!=OPUS_BITRATE_MAX) + nbCompressedBytes = IMAX(2, IMIN(nbCompressedBytes, + (tmp+4*st->mode->Fs)/(8*st->mode->Fs)-!!st->signalling)); + effectiveBytes = nbCompressedBytes; + } + + if (enc==NULL) + { + ec_enc_init(&_enc, compressed, nbCompressedBytes); + enc = &_enc; + } + + if (vbr_rate>0) + { + /* Computes the max bit-rate allowed in VBR mode to avoid violating the + target rate and buffering. + We must do this up front so that bust-prevention logic triggers + correctly if we don't have enough bits. */ + if (st->constrained_vbr) + { + opus_int32 vbr_bound; + opus_int32 max_allowed; + /* We could use any multiple of vbr_rate as bound (depending on the + delay). + This is clamped to ensure we use at least two bytes if the encoder + was entirely empty, but to allow 0 in hybrid mode. */ + vbr_bound = vbr_rate; + max_allowed = IMIN(IMAX(tell==1?2:0, + (vbr_rate+vbr_bound-st->vbr_reservoir)>>(BITRES+3)), + nbAvailableBytes); + if(max_allowed < nbAvailableBytes) + { + nbCompressedBytes = nbFilledBytes+max_allowed; + nbAvailableBytes = max_allowed; + ec_enc_shrink(enc, nbCompressedBytes); + } + } + } + total_bits = nbCompressedBytes*8; + + effEnd = st->end; + if (effEnd > st->mode->effEBands) + effEnd = st->mode->effEBands; + + ALLOC(in, CC*(N+st->overlap), celt_sig); + + /* Find pitch period and gain */ + { + VARDECL(celt_sig, _pre); + celt_sig *pre[2]; + SAVE_STACK; + ALLOC(_pre, CC*(N+COMBFILTER_MAXPERIOD), celt_sig); + + pre[0] = _pre; + pre[1] = _pre + (N+COMBFILTER_MAXPERIOD); + + silence = 1; + c=0; do { + int count = 0; + const opus_val16 * OPUS_RESTRICT pcmp = pcm+c; + celt_sig * OPUS_RESTRICT inp = in+c*(N+st->overlap)+st->overlap; + + for (i=0;iclip) + x = MAX32(-65536.f, MIN32(65536.f,x)); +#endif + if (++count==st->upsample) + { + count=0; + pcmp+=CC; + } else { + x = 0; + } + /* Apply pre-emphasis */ + tmp = MULT16_16(st->mode->preemph[2], x); + *inp = tmp + st->preemph_memE[c]; + st->preemph_memE[c] = MULT16_32_Q15(st->mode->preemph[1], *inp) + - MULT16_32_Q15(st->mode->preemph[0], tmp); + silence = silence && *inp == 0; + inp++; + } + OPUS_COPY(pre[c], prefilter_mem+c*COMBFILTER_MAXPERIOD, COMBFILTER_MAXPERIOD); + OPUS_COPY(pre[c]+COMBFILTER_MAXPERIOD, in+c*(N+st->overlap)+st->overlap, N); + } while (++c0) + { + effectiveBytes=nbCompressedBytes=IMIN(nbCompressedBytes, nbFilledBytes+2); + total_bits=nbCompressedBytes*8; + nbAvailableBytes=2; + ec_enc_shrink(enc, nbCompressedBytes); + } + /* Pretend we've filled all the remaining bits with zeros + (that's what the initialiser did anyway) */ + tell = nbCompressedBytes*8; + enc->nbits_total+=tell-ec_tell(enc); + } + if (nbAvailableBytes>12*C && st->start==0 && !silence && !st->disable_pf && st->complexity >= 5) + { + VARDECL(opus_val16, pitch_buf); + ALLOC(pitch_buf, (COMBFILTER_MAXPERIOD+N)>>1, opus_val16); + + pitch_downsample(pre, pitch_buf, COMBFILTER_MAXPERIOD+N, CC); + pitch_search(pitch_buf+(COMBFILTER_MAXPERIOD>>1), pitch_buf, N, + COMBFILTER_MAXPERIOD-COMBFILTER_MINPERIOD, &pitch_index); + pitch_index = COMBFILTER_MAXPERIOD-pitch_index; + + gain1 = remove_doubling(pitch_buf, COMBFILTER_MAXPERIOD, COMBFILTER_MINPERIOD, + N, &pitch_index, st->prefilter_period, st->prefilter_gain); + if (pitch_index > COMBFILTER_MAXPERIOD-2) + pitch_index = COMBFILTER_MAXPERIOD-2; + gain1 = MULT16_16_Q15(QCONST16(.7f,15),gain1); + if (st->loss_rate>2) + gain1 = HALF32(gain1); + if (st->loss_rate>4) + gain1 = HALF32(gain1); + if (st->loss_rate>8) + gain1 = 0; + prefilter_tapset = st->tapset_decision; + } else { + gain1 = 0; + } + + /* Gain threshold for enabling the prefilter/postfilter */ + pf_threshold = QCONST16(.2f,15); + + /* Adjusting the threshold based on rate and continuity */ + if (abs(pitch_index-st->prefilter_period)*10>pitch_index) + pf_threshold += QCONST16(.2f,15); + if (nbAvailableBytes<25) + pf_threshold += QCONST16(.1f,15); + if (nbAvailableBytes<35) + pf_threshold += QCONST16(.1f,15); + if (st->prefilter_gain > QCONST16(.4f,15)) + pf_threshold -= QCONST16(.1f,15); + if (st->prefilter_gain > QCONST16(.55f,15)) + pf_threshold -= QCONST16(.1f,15); + + /* Hard threshold at 0.2 */ + pf_threshold = MAX16(pf_threshold, QCONST16(.2f,15)); + if (gain1start==0 && tell+16<=total_bits) + ec_enc_bit_logp(enc, 0, 1); + gain1 = 0; + pf_on = 0; + } else { + /*This block is not gated by a total bits check only because + of the nbAvailableBytes check above.*/ + int qg; + int octave; + + if (ABS16(gain1-st->prefilter_gain)prefilter_gain; + +#ifdef FIXED_POINT + qg = ((gain1+1536)>>10)/3-1; +#else + qg = (int)floor(.5f+gain1*32/3)-1; +#endif + qg = IMAX(0, IMIN(7, qg)); + ec_enc_bit_logp(enc, 1, 1); + pitch_index += 1; + octave = EC_ILOG(pitch_index)-5; + ec_enc_uint(enc, octave, 6); + ec_enc_bits(enc, pitch_index-(16<mode->shortMdctSize-st->mode->overlap; + st->prefilter_period=IMAX(st->prefilter_period, COMBFILTER_MINPERIOD); + OPUS_COPY(in+c*(N+st->overlap), st->in_mem+c*(st->overlap), st->overlap); + if (offset) + comb_filter(in+c*(N+st->overlap)+st->overlap, pre[c]+COMBFILTER_MAXPERIOD, + st->prefilter_period, st->prefilter_period, offset, -st->prefilter_gain, -st->prefilter_gain, + st->prefilter_tapset, st->prefilter_tapset, NULL, 0); + + comb_filter(in+c*(N+st->overlap)+st->overlap+offset, pre[c]+COMBFILTER_MAXPERIOD+offset, + st->prefilter_period, pitch_index, N-offset, -st->prefilter_gain, -gain1, + st->prefilter_tapset, prefilter_tapset, st->mode->window, st->mode->overlap); + OPUS_COPY(st->in_mem+c*(st->overlap), in+c*(N+st->overlap)+N, st->overlap); + + if (N>COMBFILTER_MAXPERIOD) + { + OPUS_MOVE(prefilter_mem+c*COMBFILTER_MAXPERIOD, pre[c]+N, COMBFILTER_MAXPERIOD); + } else { + OPUS_MOVE(prefilter_mem+c*COMBFILTER_MAXPERIOD, prefilter_mem+c*COMBFILTER_MAXPERIOD+N, COMBFILTER_MAXPERIOD-N); + OPUS_MOVE(prefilter_mem+c*COMBFILTER_MAXPERIOD+COMBFILTER_MAXPERIOD-N, pre[c]+COMBFILTER_MAXPERIOD, N); + } + } while (++c0 && ec_tell(enc)+3<=total_bits) + { + if (st->complexity > 1) + { + isTransient = transient_analysis(in, N+st->overlap, CC, + st->overlap); + if (isTransient) + shortBlocks = M; + } + ec_enc_bit_logp(enc, isTransient, 3); + } + + ALLOC(freq, CC*N, celt_sig); /**< Interleaved signal MDCTs */ + ALLOC(bandE,st->mode->nbEBands*CC, celt_ener); + ALLOC(bandLogE,st->mode->nbEBands*CC, opus_val16); + /* Compute MDCTs */ + compute_mdcts(st->mode, shortBlocks, in, freq, CC, LM); + + if (CC==2&&C==1) + { + for (i=0;iupsample != 1) + { + c=0; do + { + int bound = N/st->upsample; + for (i=0;iupsample; + for (;imode, freq, bandE, effEnd, C, M); + + amp2Log2(st->mode, effEnd, st->end, bandE, bandLogE, C); + + /* Band normalisation */ + normalise_bands(st->mode, freq, X, bandE, effEnd, C, M); + + ALLOC(tf_res, st->mode->nbEBands, int); + tf_select = tf_analysis(st->mode, effEnd, C, isTransient, tf_res, effectiveBytes, X, N, LM, st->start, &tf_sum); + for (i=effEnd;iend;i++) + tf_res[i] = tf_res[effEnd-1]; + + ALLOC(error, C*st->mode->nbEBands, opus_val16); + quant_coarse_energy(st->mode, st->start, st->end, effEnd, bandLogE, + oldBandE, total_bits, error, enc, + C, LM, nbAvailableBytes, st->force_intra, + &st->delayedIntra, st->complexity >= 4, st->loss_rate); + + tf_encode(st->start, st->end, isTransient, tf_res, LM, tf_select, enc); + + if (ec_tell(enc)+4<=total_bits) + { + if (shortBlocks || st->complexity < 3 + || nbAvailableBytes < 10*C || st->start!=0) + { + if (st->complexity == 0) + st->spread_decision = SPREAD_NONE; + else + st->spread_decision = SPREAD_NORMAL; + } else { + st->spread_decision = spreading_decision(st->mode, X, + &st->tonal_average, st->spread_decision, &st->hf_average, + &st->tapset_decision, pf_on&&!shortBlocks, effEnd, C, M); + } + ec_enc_icdf(enc, st->spread_decision, spread_icdf, 5); + } + + ALLOC(cap, st->mode->nbEBands, int); + ALLOC(offsets, st->mode->nbEBands, int); + + init_caps(st->mode,cap,LM,C); + for (i=0;imode->nbEBands;i++) + offsets[i] = 0; + /* Dynamic allocation code */ + /* Make sure that dynamic allocation can't make us bust the budget */ + if (effectiveBytes > 50 && LM>=1) + { + int t1, t2; + if (LM <= 1) + { + t1 = 3; + t2 = 5; + } else { + t1 = 2; + t2 = 4; + } + for (i=st->start+1;iend-1;i++) + { + opus_val32 d2; + d2 = 2*bandLogE[i]-bandLogE[i-1]-bandLogE[i+1]; + if (C==2) + d2 = HALF32(d2 + 2*bandLogE[i+st->mode->nbEBands]- + bandLogE[i-1+st->mode->nbEBands]-bandLogE[i+1+st->mode->nbEBands]); +#ifdef FUZZING + if((rand()&0xF)==0) + { + offsets[i] += 1; + if((rand()&0x3)==0) + offsets[i] += 1+(rand()&0x3); + } +#else + if (d2 > SHL16(t1,DB_SHIFT)) + offsets[i] += 1; + if (d2 > SHL16(t2,DB_SHIFT)) + offsets[i] += 1; +#endif + } + } + dynalloc_logp = 6; + total_bits<<=BITRES; + total_boost = 0; + tell = ec_tell_frac(enc); + for (i=st->start;iend;i++) + { + int width, quanta; + int dynalloc_loop_logp; + int boost; + int j; + width = C*(st->mode->eBands[i+1]-st->mode->eBands[i])<mode, X, bandLogE, + st->end, LM, C, N); + ec_enc_icdf(enc, alloc_trim, trim_icdf, 7); + tell = ec_tell_frac(enc); + } + + /* Variable bitrate */ + if (vbr_rate>0) + { + opus_val16 alpha; + opus_int32 delta; + /* The target rate in 8th bits per frame */ + opus_int32 target; + opus_int32 min_allowed; + int lm_diff = st->mode->maxLM - LM; + + /* Don't attempt to use more than 510 kb/s, even for frames smaller than 20 ms. + The CELT allocator will just not be able to use more than that anyway. */ + nbCompressedBytes = IMIN(nbCompressedBytes,1275>>(3-LM)); + target = vbr_rate + (st->vbr_offset>>lm_diff) - ((40*C+20)<end-st->start)) + target = 7*target/4; + else if (tf_sum < -(st->end-st->start)) + target = 3*target/2; + else if (M > 1) + target-=(target+14)/28; + + /* The current offset is removed from the target and the space used + so far is added*/ + target=target+tell; + + /* In VBR mode the frame size must not be reduced so much that it would + result in the encoder running out of bits. + The margin of 2 bytes ensures that none of the bust-prevention logic + in the decoder will have triggered so far. */ + min_allowed = ((tell+total_boost+(1<<(BITRES+3))-1)>>(BITRES+3)) + 2 - nbFilledBytes; + + nbAvailableBytes = (target+(1<<(BITRES+2)))>>(BITRES+3); + nbAvailableBytes = IMAX(min_allowed,nbAvailableBytes); + nbAvailableBytes = IMIN(nbCompressedBytes,nbAvailableBytes+nbFilledBytes) - nbFilledBytes; + + /* By how much did we "miss" the target on that frame */ + delta = target - vbr_rate; + + target=nbAvailableBytes<<(BITRES+3); + + /*If the frame is silent we don't adjust our drift, otherwise + the encoder will shoot to very high rates after hitting a + span of silence, but we do allow the bitres to refill. + This means that we'll undershoot our target in CVBR/VBR modes + on files with lots of silence. */ + if(silence) + { + nbAvailableBytes = 2; + target = 2*8<vbr_count < 970) + { + st->vbr_count++; + alpha = celt_rcp(SHL32(EXTEND32(st->vbr_count+20),16)); + } else + alpha = QCONST16(.001f,15); + /* How many bits have we used in excess of what we're allowed */ + if (st->constrained_vbr) + st->vbr_reservoir += target - vbr_rate; + /*printf ("%d\n", st->vbr_reservoir);*/ + + /* Compute the offset we need to apply in order to reach the target */ + st->vbr_drift += (opus_int32)MULT16_32_Q15(alpha,(delta*(1<vbr_offset-st->vbr_drift); + st->vbr_offset = -st->vbr_drift; + /*printf ("%d\n", st->vbr_drift);*/ + + if (st->constrained_vbr && st->vbr_reservoir < 0) + { + /* We're under the min value -- increase rate */ + int adjust = (-st->vbr_reservoir)/(8<vbr_reservoir = 0; + /*printf ("+%d\n", adjust);*/ + } + nbCompressedBytes = IMIN(nbCompressedBytes,nbAvailableBytes+nbFilledBytes); + /* This moves the raw bits to take into account the new compressed size */ + ec_enc_shrink(enc, nbCompressedBytes); + } + if (C==2) + { + int effectiveRate; + + /* Always use MS for 2.5 ms frames until we can do a better analysis */ + if (LM!=0) + dual_stereo = stereo_analysis(st->mode, X, LM, N); + + /* Account for coarse energy */ + effectiveRate = (8*effectiveBytes - 80)>>LM; + + /* effectiveRate in kb/s */ + effectiveRate = 2*effectiveRate/5; + if (effectiveRate<35) + intensity = 8; + else if (effectiveRate<50) + intensity = 12; + else if (effectiveRate<68) + intensity = 16; + else if (effectiveRate<84) + intensity = 18; + else if (effectiveRate<102) + intensity = 19; + else if (effectiveRate<130) + intensity = 20; + else + intensity = 100; + intensity = IMIN(st->end,IMAX(st->start, intensity)); + } + + /* Bit allocation */ + ALLOC(fine_quant, st->mode->nbEBands, int); + ALLOC(pulses, st->mode->nbEBands, int); + ALLOC(fine_priority, st->mode->nbEBands, int); + + /* bits = packet size - where we are - safety*/ + bits = (((opus_int32)nbCompressedBytes*8)<=2&&bits>=((LM+2)<mode, st->start, st->end, offsets, cap, + alloc_trim, &intensity, &dual_stereo, bits, &balance, pulses, + fine_quant, fine_priority, C, LM, enc, 1, st->lastCodedBands); + st->lastCodedBands = codedBands; + + quant_fine_energy(st->mode, st->start, st->end, oldBandE, error, fine_quant, enc, C); + +#ifdef MEASURE_NORM_MSE + float X0[3000]; + float bandE0[60]; + c=0; do + for (i=0;imode->nbEBands;i++) + bandE0[i] = bandE[i]; +#endif + + /* Residual quantisation */ + ALLOC(collapse_masks, C*st->mode->nbEBands, unsigned char); + quant_all_bands(1, st->mode, st->start, st->end, X, C==2 ? X+N : NULL, collapse_masks, + bandE, pulses, shortBlocks, st->spread_decision, dual_stereo, intensity, tf_res, + nbCompressedBytes*(8<rng); + + if (anti_collapse_rsv > 0) + { + anti_collapse_on = st->consec_transient<2; +#ifdef FUZZING + anti_collapse_on = rand()&0x1; +#endif + ec_enc_bits(enc, anti_collapse_on, 1); + } + quant_energy_finalise(st->mode, st->start, st->end, oldBandE, error, fine_quant, fine_priority, nbCompressedBytes*8-ec_tell(enc), enc, C); + + if (silence) + { + for (i=0;imode->nbEBands;i++) + oldBandE[i] = -QCONST16(28.f,DB_SHIFT); + } + +#ifdef RESYNTH + /* Re-synthesis of the coded audio if required */ + { + celt_sig *out_mem[2]; + celt_sig *overlap_mem[2]; + + log2Amp(st->mode, st->start, st->end, bandE, oldBandE, C); + if (silence) + { + for (i=0;imode->nbEBands;i++) + bandE[i] = 0; + } + +#ifdef MEASURE_NORM_MSE + measure_norm_mse(st->mode, X, X0, bandE, bandE0, M, N, C); +#endif + if (anti_collapse_on) + { + anti_collapse(st->mode, X, collapse_masks, LM, C, N, + st->start, st->end, oldBandE, oldLogE, oldLogE2, pulses, st->rng); + } + + /* Synthesis */ + denormalise_bands(st->mode, X, freq, bandE, effEnd, C, M); + + OPUS_MOVE(st->syn_mem[0], st->syn_mem[0]+N, MAX_PERIOD); + if (CC==2) + OPUS_MOVE(st->syn_mem[1], st->syn_mem[1]+N, MAX_PERIOD); + + c=0; do + for (i=0;imode->eBands[st->start];i++) + freq[c*N+i] = 0; + while (++cmode->eBands[st->end];isyn_mem[0]+MAX_PERIOD; + if (CC==2) + out_mem[1] = st->syn_mem[1]+MAX_PERIOD; + + overlap_mem[0] = (celt_sig*)(oldLogE2 + CC*st->mode->nbEBands); + if (CC==2) + overlap_mem[1] = overlap_mem[0] + st->overlap; + + compute_inv_mdcts(st->mode, shortBlocks, freq, out_mem, overlap_mem, CC, LM); + + c=0; do { + st->prefilter_period=IMAX(st->prefilter_period, COMBFILTER_MINPERIOD); + st->prefilter_period_old=IMAX(st->prefilter_period_old, COMBFILTER_MINPERIOD); + comb_filter(out_mem[c], out_mem[c], st->prefilter_period_old, st->prefilter_period, st->mode->shortMdctSize, + st->prefilter_gain_old, st->prefilter_gain, st->prefilter_tapset_old, st->prefilter_tapset, + st->mode->window, st->overlap); + if (LM!=0) + comb_filter(out_mem[c]+st->mode->shortMdctSize, out_mem[c]+st->mode->shortMdctSize, st->prefilter_period, pitch_index, N-st->mode->shortMdctSize, + st->prefilter_gain, gain1, st->prefilter_tapset, prefilter_tapset, + st->mode->window, st->mode->overlap); + } while (++cupsample, st->mode->preemph, st->preemph_memD); + st->prefilter_period_old = st->prefilter_period; + st->prefilter_gain_old = st->prefilter_gain; + st->prefilter_tapset_old = st->prefilter_tapset; + } +#endif + + st->prefilter_period = pitch_index; + st->prefilter_gain = gain1; + st->prefilter_tapset = prefilter_tapset; +#ifdef RESYNTH + if (LM!=0) + { + st->prefilter_period_old = st->prefilter_period; + st->prefilter_gain_old = st->prefilter_gain; + st->prefilter_tapset_old = st->prefilter_tapset; + } +#endif + + if (CC==2&&C==1) { + for (i=0;imode->nbEBands;i++) + oldBandE[st->mode->nbEBands+i]=oldBandE[i]; + } + + if (!isTransient) + { + for (i=0;imode->nbEBands;i++) + oldLogE2[i] = oldLogE[i]; + for (i=0;imode->nbEBands;i++) + oldLogE[i] = oldBandE[i]; + } else { + for (i=0;imode->nbEBands;i++) + oldLogE[i] = MIN16(oldLogE[i], oldBandE[i]); + } + /* In case start or end were to change */ + c=0; do + { + for (i=0;istart;i++) + { + oldBandE[c*st->mode->nbEBands+i]=0; + oldLogE[c*st->mode->nbEBands+i]=oldLogE2[c*st->mode->nbEBands+i]=-QCONST16(28.f,DB_SHIFT); + } + for (i=st->end;imode->nbEBands;i++) + { + oldBandE[c*st->mode->nbEBands+i]=0; + oldLogE[c*st->mode->nbEBands+i]=oldLogE2[c*st->mode->nbEBands+i]=-QCONST16(28.f,DB_SHIFT); + } + } while (++cconsec_transient++; + else + st->consec_transient=0; + st->rng = enc->rng; + + /* If there's any room left (can only happen for very high rates), + it's already filled with zeros */ + ec_enc_done(enc); + +#ifdef CUSTOM_MODES + if (st->signalling) + nbCompressedBytes++; +#endif + + RESTORE_STACK; + if (ec_get_error(enc)) + return OPUS_INTERNAL_ERROR; + else + return nbCompressedBytes; +} + + +#ifdef CUSTOM_MODES + +#ifdef FIXED_POINT +int opus_custom_encode(CELTEncoder * OPUS_RESTRICT st, const opus_int16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes) +{ + return celt_encode_with_ec(st, pcm, frame_size, compressed, nbCompressedBytes, NULL); +} + +#ifndef DISABLE_FLOAT_API +int opus_custom_encode_float(CELTEncoder * OPUS_RESTRICT st, const float * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes) +{ + int j, ret, C, N; + VARDECL(opus_int16, in); + ALLOC_STACK; + + if (pcm==NULL) + return OPUS_BAD_ARG; + + C = st->channels; + N = frame_size; + ALLOC(in, C*N, opus_int16); + + for (j=0;jchannels; + N=frame_size; + ALLOC(in, C*N, celt_sig); + for (j=0;j10) + goto bad_arg; + st->complexity = value; + } + break; + case CELT_SET_START_BAND_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<0 || value>=st->mode->nbEBands) + goto bad_arg; + st->start = value; + } + break; + case CELT_SET_END_BAND_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<1 || value>st->mode->nbEBands) + goto bad_arg; + st->end = value; + } + break; + case CELT_SET_PREDICTION_REQUEST: + { + int value = va_arg(ap, opus_int32); + if (value<0 || value>2) + goto bad_arg; + st->disable_pf = value<=1; + st->force_intra = value==0; + } + break; + case OPUS_SET_PACKET_LOSS_PERC_REQUEST: + { + int value = va_arg(ap, opus_int32); + if (value<0 || value>100) + goto bad_arg; + st->loss_rate = value; + } + break; + case OPUS_SET_VBR_CONSTRAINT_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + st->constrained_vbr = value; + } + break; + case OPUS_SET_VBR_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + st->vbr = value; + } + break; + case OPUS_SET_BITRATE_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<=500 && value!=OPUS_BITRATE_MAX) + goto bad_arg; + value = IMIN(value, 260000*st->channels); + st->bitrate = value; + } + break; + case CELT_SET_CHANNELS_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<1 || value>2) + goto bad_arg; + st->stream_channels = value; + } + break; + case OPUS_SET_LSB_DEPTH_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<8 || value>24) + goto bad_arg; + st->lsb_depth=value; + } + break; + case OPUS_GET_LSB_DEPTH_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + *value=st->lsb_depth; + } + break; + case OPUS_RESET_STATE: + { + int i; + opus_val16 *oldBandE, *oldLogE, *oldLogE2; + oldBandE = (opus_val16*)(st->in_mem+st->channels*(st->overlap+COMBFILTER_MAXPERIOD)); + oldLogE = oldBandE + st->channels*st->mode->nbEBands; + oldLogE2 = oldLogE + st->channels*st->mode->nbEBands; + OPUS_CLEAR((char*)&st->ENCODER_RESET_START, + opus_custom_encoder_get_size(st->mode, st->channels)- + ((char*)&st->ENCODER_RESET_START - (char*)st)); + for (i=0;ichannels*st->mode->nbEBands;i++) + oldLogE[i]=oldLogE2[i]=-QCONST16(28.f,DB_SHIFT); + st->vbr_offset = 0; + st->delayedIntra = 1; + st->spread_decision = SPREAD_NORMAL; + st->tonal_average = 256; + st->hf_average = 0; + st->tapset_decision = 0; + } + break; +#ifdef CUSTOM_MODES + case CELT_SET_INPUT_CLIPPING_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + st->clip = value; + } + break; +#endif + case CELT_SET_SIGNALLING_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + st->signalling = value; + } + break; + case CELT_GET_MODE_REQUEST: + { + const CELTMode ** value = va_arg(ap, const CELTMode**); + if (value==0) + goto bad_arg; + *value=st->mode; + } + break; + case OPUS_GET_FINAL_RANGE_REQUEST: + { + opus_uint32 * value = va_arg(ap, opus_uint32 *); + if (value==0) + goto bad_arg; + *value=st->rng; + } + break; + default: + goto bad_request; + } + va_end(ap); + return OPUS_OK; +bad_arg: + va_end(ap); + return OPUS_BAD_ARG; +bad_request: + va_end(ap); + return OPUS_UNIMPLEMENTED; +} + +/**********************************************************************/ +/* */ +/* DECODER */ +/* */ +/**********************************************************************/ +#define DECODE_BUFFER_SIZE 2048 + +/** Decoder state + @brief Decoder state + */ +struct OpusCustomDecoder { + const OpusCustomMode *mode; + int overlap; + int channels; + int stream_channels; + + int downsample; + int start, end; + int signalling; + + /* Everything beyond this point gets cleared on a reset */ +#define DECODER_RESET_START rng + + opus_uint32 rng; + int error; + int last_pitch_index; + int loss_count; + int postfilter_period; + int postfilter_period_old; + opus_val16 postfilter_gain; + opus_val16 postfilter_gain_old; + int postfilter_tapset; + int postfilter_tapset_old; + + celt_sig preemph_memD[2]; + + celt_sig _decode_mem[1]; /* Size = channels*(DECODE_BUFFER_SIZE+mode->overlap) */ + /* opus_val16 lpc[], Size = channels*LPC_ORDER */ + /* opus_val16 oldEBands[], Size = 2*mode->nbEBands */ + /* opus_val16 oldLogE[], Size = 2*mode->nbEBands */ + /* opus_val16 oldLogE2[], Size = 2*mode->nbEBands */ + /* opus_val16 backgroundLogE[], Size = 2*mode->nbEBands */ +}; + +int celt_decoder_get_size(int channels) +{ + const CELTMode *mode = opus_custom_mode_create(48000, 960, NULL); + return opus_custom_decoder_get_size(mode, channels); +} + +OPUS_CUSTOM_NOSTATIC int opus_custom_decoder_get_size(const CELTMode *mode, int channels) +{ + int size = sizeof(struct CELTDecoder) + + (channels*(DECODE_BUFFER_SIZE+mode->overlap)-1)*sizeof(celt_sig) + + channels*LPC_ORDER*sizeof(opus_val16) + + 4*2*mode->nbEBands*sizeof(opus_val16); + return size; +} + +#ifdef CUSTOM_MODES +CELTDecoder *opus_custom_decoder_create(const CELTMode *mode, int channels, int *error) +{ + int ret; + CELTDecoder *st = (CELTDecoder *)opus_alloc(opus_custom_decoder_get_size(mode, channels)); + ret = opus_custom_decoder_init(st, mode, channels); + if (ret != OPUS_OK) + { + opus_custom_decoder_destroy(st); + st = NULL; + } + if (error) + *error = ret; + return st; +} +#endif /* CUSTOM_MODES */ + +int celt_decoder_init(CELTDecoder *st, opus_int32 sampling_rate, int channels) +{ + int ret; + ret = opus_custom_decoder_init(st, opus_custom_mode_create(48000, 960, NULL), channels); + if (ret != OPUS_OK) + return ret; + st->downsample = resampling_factor(sampling_rate); + if (st->downsample==0) + return OPUS_BAD_ARG; + else + return OPUS_OK; +} + +OPUS_CUSTOM_NOSTATIC int opus_custom_decoder_init(CELTDecoder *st, const CELTMode *mode, int channels) +{ + if (channels < 0 || channels > 2) + return OPUS_BAD_ARG; + + if (st==NULL) + return OPUS_ALLOC_FAIL; + + OPUS_CLEAR((char*)st, opus_custom_decoder_get_size(mode, channels)); + + st->mode = mode; + st->overlap = mode->overlap; + st->stream_channels = st->channels = channels; + + st->downsample = 1; + st->start = 0; + st->end = st->mode->effEBands; + st->signalling = 1; + + st->loss_count = 0; + + opus_custom_decoder_ctl(st, OPUS_RESET_STATE); + + return OPUS_OK; +} + +#ifdef CUSTOM_MODES +void opus_custom_decoder_destroy(CELTDecoder *st) +{ + opus_free(st); +} +#endif /* CUSTOM_MODES */ + +static void celt_decode_lost(CELTDecoder * OPUS_RESTRICT st, opus_val16 * OPUS_RESTRICT pcm, int N, int LM) +{ + int c; + int pitch_index; + opus_val16 fade = Q15ONE; + int i, len; + const int C = st->channels; + int offset; + celt_sig *out_mem[2]; + celt_sig *decode_mem[2]; + celt_sig *overlap_mem[2]; + opus_val16 *lpc; + opus_val32 *out_syn[2]; + opus_val16 *oldBandE, *oldLogE, *oldLogE2, *backgroundLogE; + const OpusCustomMode *mode; + int nbEBands; + int overlap; + const opus_int16 *eBands; + SAVE_STACK; + + mode = st->mode; + nbEBands = mode->nbEBands; + overlap = mode->overlap; + eBands = mode->eBands; + + c=0; do { + decode_mem[c] = st->_decode_mem + c*(DECODE_BUFFER_SIZE+st->overlap); + out_mem[c] = decode_mem[c]+DECODE_BUFFER_SIZE-MAX_PERIOD; + overlap_mem[c] = decode_mem[c]+DECODE_BUFFER_SIZE; + } while (++c_decode_mem+(DECODE_BUFFER_SIZE+st->overlap)*C); + oldBandE = lpc+C*LPC_ORDER; + oldLogE = oldBandE + 2*nbEBands; + oldLogE2 = oldLogE + 2*nbEBands; + backgroundLogE = oldLogE2 + 2*nbEBands; + + c=0; do { + out_syn[c] = out_mem[c]+MAX_PERIOD-N; + } while (++closs_count >= 5 || st->start!=0) + { + /* Noise-based PLC/CNG */ + VARDECL(celt_sig, freq); + VARDECL(celt_norm, X); + VARDECL(celt_ener, bandE); + opus_uint32 seed; + int effEnd; + + effEnd = st->end; + if (effEnd > mode->effEBands) + effEnd = mode->effEBands; + + ALLOC(freq, C*N, celt_sig); /**< Interleaved signal MDCTs */ + ALLOC(X, C*N, celt_norm); /**< Interleaved normalised MDCTs */ + ALLOC(bandE, nbEBands*C, celt_ener); + + if (st->loss_count >= 5) + log2Amp(mode, st->start, st->end, bandE, backgroundLogE, C); + else { + /* Energy decay */ + opus_val16 decay = st->loss_count==0 ? QCONST16(1.5f, DB_SHIFT) : QCONST16(.5f, DB_SHIFT); + c=0; do + { + for (i=st->start;iend;i++) + oldBandE[c*nbEBands+i] -= decay; + } while (++cstart, st->end, bandE, oldBandE, C); + } + seed = st->rng; + for (c=0;cmode->eBands[st->start]<start;ieffEBands;i++) + { + int j; + int boffs; + int blen; + boffs = N*c+(eBands[i]<>20); + } + renormalise_vector(X+boffs, blen, Q15ONE); + } + for (i=(st->mode->eBands[st->end]<rng = seed; + + denormalise_bands(mode, X, freq, bandE, mode->effEBands, C, 1<mode->eBands[st->start]<downsample!=1) + bound = IMIN(bound, N/st->downsample); + for (i=bound;iloss_count == 0) + { + opus_val16 pitch_buf[DECODE_BUFFER_SIZE>>1]; + /* Corresponds to a min pitch of 67 Hz. It's possible to save CPU in this + search by using only part of the decode buffer */ + int poffset = 720; + pitch_downsample(decode_mem, pitch_buf, DECODE_BUFFER_SIZE, C); + /* Max pitch is 100 samples (480 Hz) */ + pitch_search(pitch_buf+((poffset)>>1), pitch_buf, DECODE_BUFFER_SIZE-poffset, + poffset-100, &pitch_index); + pitch_index = poffset-pitch_index; + st->last_pitch_index = pitch_index; + } else { + pitch_index = st->last_pitch_index; + fade = QCONST16(.8f,15); + } + + ALLOC(etmp, overlap, opus_val32); + c=0; do { + opus_val16 exc[MAX_PERIOD]; + opus_val32 ac[LPC_ORDER+1]; + opus_val16 decay; + opus_val16 attenuation; + opus_val32 S1=0; + opus_val16 mem[LPC_ORDER]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + opus_val32 *e = out_syn[c]; + + + offset = MAX_PERIOD-pitch_index; + for (i=0;iloss_count == 0) + { + _celt_autocorr(exc, ac, mode->window, overlap, + LPC_ORDER, MAX_PERIOD); + + /* Noise floor -40 dB */ +#ifdef FIXED_POINT + ac[0] += SHR32(ac[0],13); +#else + ac[0] *= 1.0001f; +#endif + /* Lag windowing */ + for (i=1;i<=LPC_ORDER;i++) + { + /*ac[i] *= exp(-.5*(2*M_PI*.002*i)*(2*M_PI*.002*i));*/ +#ifdef FIXED_POINT + ac[i] -= MULT16_32_Q15(2*i*i, ac[i]); +#else + ac[i] -= ac[i]*(.008f*i)*(.008f*i); +#endif + } + + _celt_lpc(lpc+c*LPC_ORDER, ac, LPC_ORDER); + } + /* Samples just before the beginning of exc */ + for (i=0;i E2) + E1 = E2; + decay = celt_sqrt(frac_div32(SHR32(E1,1),E2)); + attenuation = decay; + } + + /* Move memory one frame to the left */ + OPUS_MOVE(decode_mem[c], decode_mem[c]+N, DECODE_BUFFER_SIZE-N+overlap); + + /* Extrapolate excitation with the right period, taking decay into account */ + for (i=0;i= MAX_PERIOD) + { + offset -= pitch_index; + attenuation = MULT16_16_Q15(attenuation, decay); + } + e[i] = SHL32(EXTEND32(MULT16_16_Q15(attenuation, exc[offset+i])), SIG_SHIFT); + /* Compute the energy of the previously decoded signal whose + excitation we're copying */ + tmp = ROUND16(out_mem[c][-N+offset+i],SIG_SHIFT); + S1 += SHR32(MULT16_16(tmp,tmp),8); + } + + /* Copy the last decoded samples (prior to the overlap region) to + synthesis filter memory so we can have a continuous signal. */ + for (i=0;i SHR32(S2,2))) +#else + /* Float test is written this way to catch NaNs at the same time */ + if (!(S1 > 0.2f*S2)) +#endif + { + for (i=0;iwindow[i], Q15ONE-ratio); + e[i] = MULT16_32_Q15(tmp_g, e[i]); + } + for (i=overlap;ipostfilter_period, st->postfilter_period, st->overlap, + -st->postfilter_gain, -st->postfilter_gain, st->postfilter_tapset, st->postfilter_tapset, + NULL, 0); + + /* Simulate TDAC on the concealed audio so that it blends with the + MDCT of next frames. */ + for (i=0;iwindow[i], etmp[overlap-1-i]) + + MULT16_32_Q15(mode->window[overlap-i-1], etmp[i ]); + out_mem[c][MAX_PERIOD+i] = MULT16_32_Q15(mode->window[overlap-i-1], tmp); + out_mem[c][MAX_PERIOD+overlap-i-1] = MULT16_32_Q15(mode->window[i], tmp); + } + } while (++cdownsample, mode->preemph, st->preemph_memD); + + st->loss_count++; + + RESTORE_STACK; +} + +int celt_decode_with_ec(CELTDecoder * OPUS_RESTRICT st, const unsigned char *data, int len, opus_val16 * OPUS_RESTRICT pcm, int frame_size, ec_dec *dec) +{ + int c, i, N; + int spread_decision; + opus_int32 bits; + ec_dec _dec; + VARDECL(celt_sig, freq); + VARDECL(celt_norm, X); + VARDECL(celt_ener, bandE); + VARDECL(int, fine_quant); + VARDECL(int, pulses); + VARDECL(int, cap); + VARDECL(int, offsets); + VARDECL(int, fine_priority); + VARDECL(int, tf_res); + VARDECL(unsigned char, collapse_masks); + celt_sig *out_mem[2]; + celt_sig *decode_mem[2]; + celt_sig *overlap_mem[2]; + celt_sig *out_syn[2]; + opus_val16 *lpc; + opus_val16 *oldBandE, *oldLogE, *oldLogE2, *backgroundLogE; + + int shortBlocks; + int isTransient; + int intra_ener; + const int CC = st->channels; + int LM, M; + int effEnd; + int codedBands; + int alloc_trim; + int postfilter_pitch; + opus_val16 postfilter_gain; + int intensity=0; + int dual_stereo=0; + opus_int32 total_bits; + opus_int32 balance; + opus_int32 tell; + int dynalloc_logp; + int postfilter_tapset; + int anti_collapse_rsv; + int anti_collapse_on=0; + int silence; + int C = st->stream_channels; + ALLOC_STACK; + + frame_size *= st->downsample; + + c=0; do { + decode_mem[c] = st->_decode_mem + c*(DECODE_BUFFER_SIZE+st->overlap); + out_mem[c] = decode_mem[c]+DECODE_BUFFER_SIZE-MAX_PERIOD; + overlap_mem[c] = decode_mem[c]+DECODE_BUFFER_SIZE; + } while (++c_decode_mem+(DECODE_BUFFER_SIZE+st->overlap)*CC); + oldBandE = lpc+CC*LPC_ORDER; + oldLogE = oldBandE + 2*st->mode->nbEBands; + oldLogE2 = oldLogE + 2*st->mode->nbEBands; + backgroundLogE = oldLogE2 + 2*st->mode->nbEBands; + +#ifdef CUSTOM_MODES + if (st->signalling && data!=NULL) + { + int data0=data[0]; + /* Convert "standard mode" to Opus header */ + if (st->mode->Fs==48000 && st->mode->shortMdctSize==120) + { + data0 = fromOpus(data0); + if (data0<0) + return OPUS_INVALID_PACKET; + } + st->end = IMAX(1, st->mode->effEBands-2*(data0>>5)); + LM = (data0>>3)&0x3; + C = 1 + ((data0>>2)&0x1); + data++; + len--; + if (LM>st->mode->maxLM) + return OPUS_INVALID_PACKET; + if (frame_size < st->mode->shortMdctSize<mode->shortMdctSize<mode->maxLM;LM++) + if (st->mode->shortMdctSize<st->mode->maxLM) + return OPUS_BAD_ARG; + } + M=1<1275 || pcm==NULL) + return OPUS_BAD_ARG; + + N = M*st->mode->shortMdctSize; + + effEnd = st->end; + if (effEnd > st->mode->effEBands) + effEnd = st->mode->effEBands; + + if (data == NULL || len<=1) + { + celt_decode_lost(st, pcm, N, LM); + RESTORE_STACK; + return frame_size/st->downsample; + } + + ALLOC(freq, IMAX(CC,C)*N, celt_sig); /**< Interleaved signal MDCTs */ + ALLOC(X, C*N, celt_norm); /**< Interleaved normalised MDCTs */ + ALLOC(bandE, st->mode->nbEBands*C, celt_ener); + c=0; do + for (i=0;imode->eBands[st->start];i++) + X[c*N+i] = 0; + while (++cmode->eBands[effEnd];imode->nbEBands;i++) + oldBandE[i]=MAX16(oldBandE[i],oldBandE[st->mode->nbEBands+i]); + } + + total_bits = len*8; + tell = ec_tell(dec); + + if (tell >= total_bits) + silence = 1; + else if (tell==1) + silence = ec_dec_bit_logp(dec, 15); + else + silence = 0; + if (silence) + { + /* Pretend we've read all the remaining bits */ + tell = len*8; + dec->nbits_total+=tell-ec_tell(dec); + } + + postfilter_gain = 0; + postfilter_pitch = 0; + postfilter_tapset = 0; + if (st->start==0 && tell+16 <= total_bits) + { + if(ec_dec_bit_logp(dec, 1)) + { + int qg, octave; + octave = ec_dec_uint(dec, 6); + postfilter_pitch = (16< 0 && tell+3 <= total_bits) + { + isTransient = ec_dec_bit_logp(dec, 3); + tell = ec_tell(dec); + } + else + isTransient = 0; + + if (isTransient) + shortBlocks = M; + else + shortBlocks = 0; + + /* Decode the global flags (first symbols in the stream) */ + intra_ener = tell+3<=total_bits ? ec_dec_bit_logp(dec, 3) : 0; + /* Get band energies */ + unquant_coarse_energy(st->mode, st->start, st->end, oldBandE, + intra_ener, dec, C, LM); + + ALLOC(tf_res, st->mode->nbEBands, int); + tf_decode(st->start, st->end, isTransient, tf_res, LM, dec); + + tell = ec_tell(dec); + spread_decision = SPREAD_NORMAL; + if (tell+4 <= total_bits) + spread_decision = ec_dec_icdf(dec, spread_icdf, 5); + + ALLOC(pulses, st->mode->nbEBands, int); + ALLOC(cap, st->mode->nbEBands, int); + ALLOC(offsets, st->mode->nbEBands, int); + ALLOC(fine_priority, st->mode->nbEBands, int); + + init_caps(st->mode,cap,LM,C); + + dynalloc_logp = 6; + total_bits<<=BITRES; + tell = ec_tell_frac(dec); + for (i=st->start;iend;i++) + { + int width, quanta; + int dynalloc_loop_logp; + int boost; + width = C*(st->mode->eBands[i+1]-st->mode->eBands[i])<0) + dynalloc_logp = IMAX(2, dynalloc_logp-1); + } + + ALLOC(fine_quant, st->mode->nbEBands, int); + alloc_trim = tell+(6<=2&&bits>=((LM+2)<mode, st->start, st->end, offsets, cap, + alloc_trim, &intensity, &dual_stereo, bits, &balance, pulses, + fine_quant, fine_priority, C, LM, dec, 0, 0); + + unquant_fine_energy(st->mode, st->start, st->end, oldBandE, fine_quant, dec, C); + + /* Decode fixed codebook */ + ALLOC(collapse_masks, C*st->mode->nbEBands, unsigned char); + quant_all_bands(0, st->mode, st->start, st->end, X, C==2 ? X+N : NULL, collapse_masks, + NULL, pulses, shortBlocks, spread_decision, dual_stereo, intensity, tf_res, + len*(8<rng); + + if (anti_collapse_rsv > 0) + { + anti_collapse_on = ec_dec_bits(dec, 1); + } + + unquant_energy_finalise(st->mode, st->start, st->end, oldBandE, + fine_quant, fine_priority, len*8-ec_tell(dec), dec, C); + + if (anti_collapse_on) + anti_collapse(st->mode, X, collapse_masks, LM, C, N, + st->start, st->end, oldBandE, oldLogE, oldLogE2, pulses, st->rng); + + log2Amp(st->mode, st->start, st->end, bandE, oldBandE, C); + + if (silence) + { + for (i=0;imode->nbEBands;i++) + { + bandE[i] = 0; + oldBandE[i] = -QCONST16(28.f,DB_SHIFT); + } + } + /* Synthesis */ + denormalise_bands(st->mode, X, freq, bandE, effEnd, C, M); + + OPUS_MOVE(decode_mem[0], decode_mem[0]+N, DECODE_BUFFER_SIZE-N); + if (CC==2) + OPUS_MOVE(decode_mem[1], decode_mem[1]+N, DECODE_BUFFER_SIZE-N); + + c=0; do + for (i=0;imode->eBands[st->start];i++) + freq[c*N+i] = 0; + while (++cmode->eBands[effEnd]; + if (st->downsample!=1) + bound = IMIN(bound, N/st->downsample); + for (i=bound;imode, shortBlocks, freq, out_syn, overlap_mem, CC, LM); + + c=0; do { + st->postfilter_period=IMAX(st->postfilter_period, COMBFILTER_MINPERIOD); + st->postfilter_period_old=IMAX(st->postfilter_period_old, COMBFILTER_MINPERIOD); + comb_filter(out_syn[c], out_syn[c], st->postfilter_period_old, st->postfilter_period, st->mode->shortMdctSize, + st->postfilter_gain_old, st->postfilter_gain, st->postfilter_tapset_old, st->postfilter_tapset, + st->mode->window, st->overlap); + if (LM!=0) + comb_filter(out_syn[c]+st->mode->shortMdctSize, out_syn[c]+st->mode->shortMdctSize, st->postfilter_period, postfilter_pitch, N-st->mode->shortMdctSize, + st->postfilter_gain, postfilter_gain, st->postfilter_tapset, postfilter_tapset, + st->mode->window, st->mode->overlap); + + } while (++cpostfilter_period_old = st->postfilter_period; + st->postfilter_gain_old = st->postfilter_gain; + st->postfilter_tapset_old = st->postfilter_tapset; + st->postfilter_period = postfilter_pitch; + st->postfilter_gain = postfilter_gain; + st->postfilter_tapset = postfilter_tapset; + if (LM!=0) + { + st->postfilter_period_old = st->postfilter_period; + st->postfilter_gain_old = st->postfilter_gain; + st->postfilter_tapset_old = st->postfilter_tapset; + } + + if (C==1) { + for (i=0;imode->nbEBands;i++) + oldBandE[st->mode->nbEBands+i]=oldBandE[i]; + } + + /* In case start or end were to change */ + if (!isTransient) + { + for (i=0;i<2*st->mode->nbEBands;i++) + oldLogE2[i] = oldLogE[i]; + for (i=0;i<2*st->mode->nbEBands;i++) + oldLogE[i] = oldBandE[i]; + for (i=0;i<2*st->mode->nbEBands;i++) + backgroundLogE[i] = MIN16(backgroundLogE[i] + M*QCONST16(0.001f,DB_SHIFT), oldBandE[i]); + } else { + for (i=0;i<2*st->mode->nbEBands;i++) + oldLogE[i] = MIN16(oldLogE[i], oldBandE[i]); + } + c=0; do + { + for (i=0;istart;i++) + { + oldBandE[c*st->mode->nbEBands+i]=0; + oldLogE[c*st->mode->nbEBands+i]=oldLogE2[c*st->mode->nbEBands+i]=-QCONST16(28.f,DB_SHIFT); + } + for (i=st->end;imode->nbEBands;i++) + { + oldBandE[c*st->mode->nbEBands+i]=0; + oldLogE[c*st->mode->nbEBands+i]=oldLogE2[c*st->mode->nbEBands+i]=-QCONST16(28.f,DB_SHIFT); + } + } while (++c<2); + st->rng = dec->rng; + + deemphasis(out_syn, pcm, N, CC, st->downsample, st->mode->preemph, st->preemph_memD); + st->loss_count = 0; + RESTORE_STACK; + if (ec_tell(dec) > 8*len) + return OPUS_INTERNAL_ERROR; + if(ec_get_error(dec)) + st->error = 1; + return frame_size/st->downsample; +} + + +#ifdef CUSTOM_MODES + +#ifdef FIXED_POINT +int opus_custom_decode(CELTDecoder * OPUS_RESTRICT st, const unsigned char *data, int len, opus_int16 * OPUS_RESTRICT pcm, int frame_size) +{ + return celt_decode_with_ec(st, data, len, pcm, frame_size, NULL); +} + +#ifndef DISABLE_FLOAT_API +int opus_custom_decode_float(CELTDecoder * OPUS_RESTRICT st, const unsigned char *data, int len, float * OPUS_RESTRICT pcm, int frame_size) +{ + int j, ret, C, N; + VARDECL(opus_int16, out); + ALLOC_STACK; + + if (pcm==NULL) + return OPUS_BAD_ARG; + + C = st->channels; + N = frame_size; + + ALLOC(out, C*N, opus_int16); + ret=celt_decode_with_ec(st, data, len, out, frame_size, NULL); + if (ret>0) + for (j=0;jchannels; + N = frame_size; + ALLOC(out, C*N, celt_sig); + + ret=celt_decode_with_ec(st, data, len, out, frame_size, NULL); + + if (ret>0) + for (j=0;j=st->mode->nbEBands) + goto bad_arg; + st->start = value; + } + break; + case CELT_SET_END_BAND_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<1 || value>st->mode->nbEBands) + goto bad_arg; + st->end = value; + } + break; + case CELT_SET_CHANNELS_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<1 || value>2) + goto bad_arg; + st->stream_channels = value; + } + break; + case CELT_GET_AND_CLEAR_ERROR_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (value==NULL) + goto bad_arg; + *value=st->error; + st->error = 0; + } + break; + case OPUS_GET_LOOKAHEAD_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (value==NULL) + goto bad_arg; + *value = st->overlap/st->downsample; + } + break; + case OPUS_RESET_STATE: + { + int i; + opus_val16 *lpc, *oldBandE, *oldLogE, *oldLogE2; + lpc = (opus_val16*)(st->_decode_mem+(DECODE_BUFFER_SIZE+st->overlap)*st->channels); + oldBandE = lpc+st->channels*LPC_ORDER; + oldLogE = oldBandE + 2*st->mode->nbEBands; + oldLogE2 = oldLogE + 2*st->mode->nbEBands; + OPUS_CLEAR((char*)&st->DECODER_RESET_START, + opus_custom_decoder_get_size(st->mode, st->channels)- + ((char*)&st->DECODER_RESET_START - (char*)st)); + for (i=0;i<2*st->mode->nbEBands;i++) + oldLogE[i]=oldLogE2[i]=-QCONST16(28.f,DB_SHIFT); + } + break; + case OPUS_GET_PITCH_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (value==NULL) + goto bad_arg; + *value = st->postfilter_period; + } + break; + case CELT_GET_MODE_REQUEST: + { + const CELTMode ** value = va_arg(ap, const CELTMode**); + if (value==0) + goto bad_arg; + *value=st->mode; + } + break; + case CELT_SET_SIGNALLING_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + st->signalling = value; + } + break; + case OPUS_GET_FINAL_RANGE_REQUEST: + { + opus_uint32 * value = va_arg(ap, opus_uint32 *); + if (value==0) + goto bad_arg; + *value=st->rng; + } + break; + default: + goto bad_request; + } + va_end(ap); + return OPUS_OK; +bad_arg: + va_end(ap); + return OPUS_BAD_ARG; +bad_request: + va_end(ap); + return OPUS_UNIMPLEMENTED; +} + + + +const char *opus_strerror(int error) +{ + static const char * const error_strings[8] = { + "success", + "invalid argument", + "buffer too small", + "internal error", + "corrupted stream", + "request not implemented", + "invalid state", + "memory allocation failed" + }; + if (error > 0 || error < -7) + return "unknown error"; + else + return error_strings[-error]; +} + +const char *opus_get_version_string(void) +{ + return "libopus " OPUS_VERSION +#ifdef FIXED_POINT + "-fixed" +#endif +#ifdef FUZZING + "-fuzzing" +#endif + ; +} diff --git a/code/opus-1.0.2/celt/celt.h b/code/opus-1.0.2/celt/celt.h new file mode 100644 index 00000000..218cd883 --- /dev/null +++ b/code/opus-1.0.2/celt/celt.h @@ -0,0 +1,117 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2008 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/** + @file celt.h + @brief Contains all the functions for encoding and decoding audio + */ + +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (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 CELT_H +#define CELT_H + +#include "opus_types.h" +#include "opus_defines.h" +#include "opus_custom.h" +#include "entenc.h" +#include "entdec.h" +#include "arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define CELTEncoder OpusCustomEncoder +#define CELTDecoder OpusCustomDecoder +#define CELTMode OpusCustomMode + +#define _celt_check_mode_ptr_ptr(ptr) ((ptr) + ((ptr) - (const CELTMode**)(ptr))) + +/* Encoder/decoder Requests */ + +#define CELT_SET_PREDICTION_REQUEST 10002 +/** Controls the use of interframe prediction. + 0=Independent frames + 1=Short term interframe prediction allowed + 2=Long term prediction allowed + */ +#define CELT_SET_PREDICTION(x) CELT_SET_PREDICTION_REQUEST, __opus_check_int(x) + +#define CELT_SET_INPUT_CLIPPING_REQUEST 10004 +#define CELT_SET_INPUT_CLIPPING(x) CELT_SET_INPUT_CLIPPING_REQUEST, __opus_check_int(x) + +#define CELT_GET_AND_CLEAR_ERROR_REQUEST 10007 +#define CELT_GET_AND_CLEAR_ERROR(x) CELT_GET_AND_CLEAR_ERROR_REQUEST, __opus_check_int_ptr(x) + +#define CELT_SET_CHANNELS_REQUEST 10008 +#define CELT_SET_CHANNELS(x) CELT_SET_CHANNELS_REQUEST, __opus_check_int(x) + + +/* Internal */ +#define CELT_SET_START_BAND_REQUEST 10010 +#define CELT_SET_START_BAND(x) CELT_SET_START_BAND_REQUEST, __opus_check_int(x) + +#define CELT_SET_END_BAND_REQUEST 10012 +#define CELT_SET_END_BAND(x) CELT_SET_END_BAND_REQUEST, __opus_check_int(x) + +#define CELT_GET_MODE_REQUEST 10015 +/** Get the CELTMode used by an encoder or decoder */ +#define CELT_GET_MODE(x) CELT_GET_MODE_REQUEST, _celt_check_mode_ptr_ptr(x) + +#define CELT_SET_SIGNALLING_REQUEST 10016 +#define CELT_SET_SIGNALLING(x) CELT_SET_SIGNALLING_REQUEST, __opus_check_int(x) + + + +/* Encoder stuff */ + +int celt_encoder_get_size(int channels); + +int celt_encode_with_ec(OpusCustomEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc); + +int celt_encoder_init(CELTEncoder *st, opus_int32 sampling_rate, int channels); + + + +/* Decoder stuff */ + +int celt_decoder_get_size(int channels); + + +int celt_decoder_init(CELTDecoder *st, opus_int32 sampling_rate, int channels); + +int celt_decode_with_ec(OpusCustomDecoder * OPUS_RESTRICT st, const unsigned char *data, int len, opus_val16 * OPUS_RESTRICT pcm, int frame_size, ec_dec *dec); + +#define celt_encoder_ctl opus_custom_encoder_ctl +#define celt_decoder_ctl opus_custom_decoder_ctl + +#ifdef __cplusplus +} +#endif + +#endif /* CELT_H */ diff --git a/code/opus-1.0.2/celt/celt_lpc.c b/code/opus-1.0.2/celt/celt_lpc.c new file mode 100644 index 00000000..d2addbf2 --- /dev/null +++ b/code/opus-1.0.2/celt/celt_lpc.c @@ -0,0 +1,188 @@ +/* Copyright (c) 2009-2010 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "celt_lpc.h" +#include "stack_alloc.h" +#include "mathops.h" + +void _celt_lpc( + opus_val16 *_lpc, /* out: [0...p-1] LPC coefficients */ +const opus_val32 *ac, /* in: [0...p] autocorrelation values */ +int p +) +{ + int i, j; + opus_val32 r; + opus_val32 error = ac[0]; +#ifdef FIXED_POINT + opus_val32 lpc[LPC_ORDER]; +#else + float *lpc = _lpc; +#endif + + for (i = 0; i < p; i++) + lpc[i] = 0; + if (ac[0] != 0) + { + for (i = 0; i < p; i++) { + /* Sum up this iteration's reflection coefficient */ + opus_val32 rr = 0; + for (j = 0; j < i; j++) + rr += MULT32_32_Q31(lpc[j],ac[i - j]); + rr += SHR32(ac[i + 1],3); + r = -frac_div32(SHL32(rr,3), error); + /* Update LPC coefficients and total error */ + lpc[i] = SHR32(r,3); + for (j = 0; j < (i+1)>>1; j++) + { + opus_val32 tmp1, tmp2; + tmp1 = lpc[j]; + tmp2 = lpc[i-1-j]; + lpc[j] = tmp1 + MULT32_32_Q31(r,tmp2); + lpc[i-1-j] = tmp2 + MULT32_32_Q31(r,tmp1); + } + + error = error - MULT32_32_Q31(MULT32_32_Q31(r,r),error); + /* Bail out once we get 30 dB gain */ +#ifdef FIXED_POINT + if (error=1;j--) + { + mem[j]=mem[j-1]; + } + mem[0] = x[i]; + y[i] = ROUND16(sum, SIG_SHIFT); + } +} + +void celt_iir(const opus_val32 *x, + const opus_val16 *den, + opus_val32 *y, + int N, + int ord, + opus_val16 *mem) +{ + int i,j; + for (i=0;i=1;j--) + { + mem[j]=mem[j-1]; + } + mem[0] = ROUND16(sum,SIG_SHIFT); + y[i] = sum; + } +} + +void _celt_autocorr( + const opus_val16 *x, /* in: [0...n-1] samples x */ + opus_val32 *ac, /* out: [0...lag-1] ac values */ + const opus_val16 *window, + int overlap, + int lag, + int n + ) +{ + opus_val32 d; + int i; + VARDECL(opus_val16, xx); + SAVE_STACK; + ALLOC(xx, n, opus_val16); + celt_assert(n>0); + celt_assert(overlap>=0); + for (i=0;i=0) + { + for (i = lag, d = 0; i < n; i++) + d += xx[i] * xx[i-lag]; + ac[lag] = d; + /*printf ("%f ", ac[lag]);*/ + lag--; + } + /*printf ("\n");*/ + ac[0] += 10; + + RESTORE_STACK; +} diff --git a/code/opus-1.0.2/celt/celt_lpc.h b/code/opus-1.0.2/celt/celt_lpc.h new file mode 100644 index 00000000..2baa77ed --- /dev/null +++ b/code/opus-1.0.2/celt/celt_lpc.h @@ -0,0 +1,53 @@ +/* Copyright (c) 2009-2010 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (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 PLC_H +#define PLC_H + +#include "arch.h" + +#define LPC_ORDER 24 + +void _celt_lpc(opus_val16 *_lpc, const opus_val32 *ac, int p); + +void celt_fir(const opus_val16 *x, + const opus_val16 *num, + opus_val16 *y, + int N, + int ord, + opus_val16 *mem); + +void celt_iir(const opus_val32 *x, + const opus_val16 *den, + opus_val32 *y, + int N, + int ord, + opus_val16 *mem); + +void _celt_autocorr(const opus_val16 *x, opus_val32 *ac, const opus_val16 *window, int overlap, int lag, int n); + +#endif /* PLC_H */ diff --git a/code/opus-1.0.2/celt/cwrs.c b/code/opus-1.0.2/celt/cwrs.c new file mode 100644 index 00000000..8edc919d --- /dev/null +++ b/code/opus-1.0.2/celt/cwrs.c @@ -0,0 +1,645 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2007-2009 Timothy B. Terriberry + Written by Timothy B. Terriberry and Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "os_support.h" +#include "cwrs.h" +#include "mathops.h" +#include "arch.h" + +#ifdef CUSTOM_MODES + +/*Guaranteed to return a conservatively large estimate of the binary logarithm + with frac bits of fractional precision. + Tested for all possible 32-bit inputs with frac=4, where the maximum + overestimation is 0.06254243 bits.*/ +int log2_frac(opus_uint32 val, int frac) +{ + int l; + l=EC_ILOG(val); + if(val&(val-1)){ + /*This is (val>>l-16), but guaranteed to round up, even if adding a bias + before the shift would cause overflow (e.g., for 0xFFFFxxxx). + Doesn't work for val=0, but that case fails the test above.*/ + if(l>16)val=((val-1)>>(l-16))+1; + else val<<=16-l; + l=(l-1)<>16); + l+=b<>b; + val=(val*val+0x7FFF)>>15; + } + while(frac-->0); + /*If val is not exactly 0x8000, then we have to round up the remainder.*/ + return l+(val>0x8000); + } + /*Exact powers of two require no rounding.*/ + else return (l-1)<0); + celt_assert(_d<=54); + shift=EC_ILOG(_d^(_d-1)); + inv=INV_TABLE[(_d-1)>>shift]; + shift--; + one=1<>shift)-(_c>>shift)+ + ((_a*(_b&mask)+one-(_c&mask))>>shift)-1)*inv&MASK32; +} + +#endif /* SMALL_FOOTPRINT */ + +/*Although derived separately, the pulse vector coding scheme is equivalent to + a Pyramid Vector Quantizer \cite{Fis86}. + Some additional notes about an early version appear at + http://people.xiph.org/~tterribe/notes/cwrs.html, but the codebook ordering + and the definitions of some terms have evolved since that was written. + + The conversion from a pulse vector to an integer index (encoding) and back + (decoding) is governed by two related functions, V(N,K) and U(N,K). + + V(N,K) = the number of combinations, with replacement, of N items, taken K + at a time, when a sign bit is added to each item taken at least once (i.e., + the number of N-dimensional unit pulse vectors with K pulses). + One way to compute this is via + V(N,K) = K>0 ? sum(k=1...K,2**k*choose(N,k)*choose(K-1,k-1)) : 1, + where choose() is the binomial function. + A table of values for N<10 and K<10 looks like: + V[10][10] = { + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {1, 2, 2, 2, 2, 2, 2, 2, 2, 2}, + {1, 4, 8, 12, 16, 20, 24, 28, 32, 36}, + {1, 6, 18, 38, 66, 102, 146, 198, 258, 326}, + {1, 8, 32, 88, 192, 360, 608, 952, 1408, 1992}, + {1, 10, 50, 170, 450, 1002, 1970, 3530, 5890, 9290}, + {1, 12, 72, 292, 912, 2364, 5336, 10836, 20256, 35436}, + {1, 14, 98, 462, 1666, 4942, 12642, 28814, 59906, 115598}, + {1, 16, 128, 688, 2816, 9424, 27008, 68464, 157184, 332688}, + {1, 18, 162, 978, 4482, 16722, 53154, 148626, 374274, 864146} + }; + + U(N,K) = the number of such combinations wherein N-1 objects are taken at + most K-1 at a time. + This is given by + U(N,K) = sum(k=0...K-1,V(N-1,k)) + = K>0 ? (V(N-1,K-1) + V(N,K-1))/2 : 0. + The latter expression also makes clear that U(N,K) is half the number of such + combinations wherein the first object is taken at least once. + Although it may not be clear from either of these definitions, U(N,K) is the + natural function to work with when enumerating the pulse vector codebooks, + not V(N,K). + U(N,K) is not well-defined for N=0, but with the extension + U(0,K) = K>0 ? 0 : 1, + the function becomes symmetric: U(N,K) = U(K,N), with a similar table: + U[10][10] = { + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + {0, 1, 3, 5, 7, 9, 11, 13, 15, 17}, + {0, 1, 5, 13, 25, 41, 61, 85, 113, 145}, + {0, 1, 7, 25, 63, 129, 231, 377, 575, 833}, + {0, 1, 9, 41, 129, 321, 681, 1289, 2241, 3649}, + {0, 1, 11, 61, 231, 681, 1683, 3653, 7183, 13073}, + {0, 1, 13, 85, 377, 1289, 3653, 8989, 19825, 40081}, + {0, 1, 15, 113, 575, 2241, 7183, 19825, 48639, 108545}, + {0, 1, 17, 145, 833, 3649, 13073, 40081, 108545, 265729} + }; + + With this extension, V(N,K) may be written in terms of U(N,K): + V(N,K) = U(N,K) + U(N,K+1) + for all N>=0, K>=0. + Thus U(N,K+1) represents the number of combinations where the first element + is positive or zero, and U(N,K) represents the number of combinations where + it is negative. + With a large enough table of U(N,K) values, we could write O(N) encoding + and O(min(N*log(K),N+K)) decoding routines, but such a table would be + prohibitively large for small embedded devices (K may be as large as 32767 + for small N, and N may be as large as 200). + + Both functions obey the same recurrence relation: + V(N,K) = V(N-1,K) + V(N,K-1) + V(N-1,K-1), + U(N,K) = U(N-1,K) + U(N,K-1) + U(N-1,K-1), + for all N>0, K>0, with different initial conditions at N=0 or K=0. + This allows us to construct a row of one of the tables above given the + previous row or the next row. + Thus we can derive O(NK) encoding and decoding routines with O(K) memory + using only addition and subtraction. + + When encoding, we build up from the U(2,K) row and work our way forwards. + When decoding, we need to start at the U(N,K) row and work our way backwards, + which requires a means of computing U(N,K). + U(N,K) may be computed from two previous values with the same N: + U(N,K) = ((2*N-1)*U(N,K-1) - U(N,K-2))/(K-1) + U(N,K-2) + for all N>1, and since U(N,K) is symmetric, a similar relation holds for two + previous values with the same K: + U(N,K>1) = ((2*K-1)*U(N-1,K) - U(N-2,K))/(N-1) + U(N-2,K) + for all K>1. + This allows us to construct an arbitrary row of the U(N,K) table by starting + with the first two values, which are constants. + This saves roughly 2/3 the work in our O(NK) decoding routine, but costs O(K) + multiplications. + Similar relations can be derived for V(N,K), but are not used here. + + For N>0 and K>0, U(N,K) and V(N,K) take on the form of an (N-1)-degree + polynomial for fixed N. + The first few are + U(1,K) = 1, + U(2,K) = 2*K-1, + U(3,K) = (2*K-2)*K+1, + U(4,K) = (((4*K-6)*K+8)*K-3)/3, + U(5,K) = ((((2*K-4)*K+10)*K-8)*K+3)/3, + and + V(1,K) = 2, + V(2,K) = 4*K, + V(3,K) = 4*K*K+2, + V(4,K) = 8*(K*K+2)*K/3, + V(5,K) = ((4*K*K+20)*K*K+6)/3, + for all K>0. + This allows us to derive O(N) encoding and O(N*log(K)) decoding routines for + small N (and indeed decoding is also O(N) for N<3). + + @ARTICLE{Fis86, + author="Thomas R. Fischer", + title="A Pyramid Vector Quantizer", + journal="IEEE Transactions on Information Theory", + volume="IT-32", + number=4, + pages="568--583", + month=Jul, + year=1986 + }*/ + +#ifndef SMALL_FOOTPRINT +/*Compute U(2,_k). + Note that this may be called with _k=32768 (maxK[2]+1).*/ +static inline unsigned ucwrs2(unsigned _k){ + celt_assert(_k>0); + return _k+(_k-1); +} + +/*Compute V(2,_k).*/ +static inline opus_uint32 ncwrs2(int _k){ + celt_assert(_k>0); + return 4*(opus_uint32)_k; +} + +/*Compute U(3,_k). + Note that this may be called with _k=32768 (maxK[3]+1).*/ +static inline opus_uint32 ucwrs3(unsigned _k){ + celt_assert(_k>0); + return (2*(opus_uint32)_k-2)*_k+1; +} + +/*Compute V(3,_k).*/ +static inline opus_uint32 ncwrs3(int _k){ + celt_assert(_k>0); + return 2*(2*(unsigned)_k*(opus_uint32)_k+1); +} + +/*Compute U(4,_k).*/ +static inline opus_uint32 ucwrs4(int _k){ + celt_assert(_k>0); + return imusdiv32odd(2*_k,(2*_k-3)*(opus_uint32)_k+4,3,1); +} + +/*Compute V(4,_k).*/ +static inline opus_uint32 ncwrs4(int _k){ + celt_assert(_k>0); + return ((_k*(opus_uint32)_k+2)*_k)/3<<3; +} + +#endif /* SMALL_FOOTPRINT */ + +/*Computes the next row/column of any recurrence that obeys the relation + u[i][j]=u[i-1][j]+u[i][j-1]+u[i-1][j-1]. + _ui0 is the base case for the new row/column.*/ +static inline void unext(opus_uint32 *_ui,unsigned _len,opus_uint32 _ui0){ + opus_uint32 ui1; + unsigned j; + /*This do-while will overrun the array if we don't have storage for at least + 2 values.*/ + j=1; do { + ui1=UADD32(UADD32(_ui[j],_ui[j-1]),_ui0); + _ui[j-1]=_ui0; + _ui0=ui1; + } while (++j<_len); + _ui[j-1]=_ui0; +} + +/*Computes the previous row/column of any recurrence that obeys the relation + u[i-1][j]=u[i][j]-u[i][j-1]-u[i-1][j-1]. + _ui0 is the base case for the new row/column.*/ +static inline void uprev(opus_uint32 *_ui,unsigned _n,opus_uint32 _ui0){ + opus_uint32 ui1; + unsigned j; + /*This do-while will overrun the array if we don't have storage for at least + 2 values.*/ + j=1; do { + ui1=USUB32(USUB32(_ui[j],_ui[j-1]),_ui0); + _ui[j-1]=_ui0; + _ui0=ui1; + } while (++j<_n); + _ui[j-1]=_ui0; +} + +/*Compute V(_n,_k), as well as U(_n,0..._k+1). + _u: On exit, _u[i] contains U(_n,i) for i in [0..._k+1].*/ +static opus_uint32 ncwrs_urow(unsigned _n,unsigned _k,opus_uint32 *_u){ + opus_uint32 um2; + unsigned len; + unsigned k; + len=_k+2; + /*We require storage at least 3 values (e.g., _k>0).*/ + celt_assert(len>=3); + _u[0]=0; + _u[1]=um2=1; +#ifndef SMALL_FOOTPRINT + /*_k>52 doesn't work in the false branch due to the limits of INV_TABLE, + but _k isn't tested here because k<=52 for n=7*/ + if(_n<=6) +#endif + { + /*If _n==0, _u[0] should be 1 and the rest should be 0.*/ + /*If _n==1, _u[i] should be 1 for i>1.*/ + celt_assert(_n>=2); + /*If _k==0, the following do-while loop will overflow the buffer.*/ + celt_assert(_k>0); + k=2; + do _u[k]=(k<<1)-1; + while(++k=len)break; + _u[k]=um1=imusdiv32odd(n2m1,um2,um1,(k-1)>>1)+um1; + } + } +#endif /* SMALL_FOOTPRINT */ + return _u[_k]+_u[_k+1]; +} + +#ifndef SMALL_FOOTPRINT + +/*Returns the _i'th combination of _k elements (at most 32767) chosen from a + set of size 1 with associated sign bits. + _y: Returns the vector of pulses.*/ +static inline void cwrsi1(int _k,opus_uint32 _i,int *_y){ + int s; + s=-(int)_i; + _y[0]=(_k+s)^s; +} + +/*Returns the _i'th combination of _k elements (at most 32767) chosen from a + set of size 2 with associated sign bits. + _y: Returns the vector of pulses.*/ +static inline void cwrsi2(int _k,opus_uint32 _i,int *_y){ + opus_uint32 p; + int s; + int yj; + p=ucwrs2(_k+1U); + s=-(_i>=p); + _i-=p&s; + yj=_k; + _k=(_i+1)>>1; + p=_k?ucwrs2(_k):0; + _i-=p; + yj-=_k; + _y[0]=(yj+s)^s; + cwrsi1(_k,_i,_y+1); +} + +/*Returns the _i'th combination of _k elements (at most 32767) chosen from a + set of size 3 with associated sign bits. + _y: Returns the vector of pulses.*/ +static void cwrsi3(int _k,opus_uint32 _i,int *_y){ + opus_uint32 p; + int s; + int yj; + p=ucwrs3(_k+1U); + s=-(_i>=p); + _i-=p&s; + yj=_k; + /*Finds the maximum _k such that ucwrs3(_k)<=_i (tested for all + _i<2147418113=U(3,32768)).*/ + _k=_i>0?(isqrt32(2*_i-1)+1)>>1:0; + p=_k?ucwrs3(_k):0; + _i-=p; + yj-=_k; + _y[0]=(yj+s)^s; + cwrsi2(_k,_i,_y+1); +} + +/*Returns the _i'th combination of _k elements (at most 1172) chosen from a set + of size 4 with associated sign bits. + _y: Returns the vector of pulses.*/ +static void cwrsi4(int _k,opus_uint32 _i,int *_y){ + opus_uint32 p; + int s; + int yj; + int kl; + int kr; + p=ucwrs4(_k+1); + s=-(_i>=p); + _i-=p&s; + yj=_k; + /*We could solve a cubic for k here, but the form of the direct solution does + not lend itself well to exact integer arithmetic. + Instead we do a binary search on U(4,K).*/ + kl=0; + kr=_k; + for(;;){ + _k=(kl+kr)>>1; + p=_k?ucwrs4(_k):0; + if(p<_i){ + if(_k>=kr)break; + kl=_k+1; + } + else if(p>_i)kr=_k-1; + else break; + } + _i-=p; + yj-=_k; + _y[0]=(yj+s)^s; + cwrsi3(_k,_i,_y+1); +} + +#endif /* SMALL_FOOTPRINT */ + +/*Returns the _i'th combination of _k elements chosen from a set of size _n + with associated sign bits. + _y: Returns the vector of pulses. + _u: Must contain entries [0..._k+1] of row _n of U() on input. + Its contents will be destructively modified.*/ +static void cwrsi(int _n,int _k,opus_uint32 _i,int *_y,opus_uint32 *_u){ + int j; + celt_assert(_n>0); + j=0; + do{ + opus_uint32 p; + int s; + int yj; + p=_u[_k+1]; + s=-(_i>=p); + _i-=p&s; + yj=_k; + p=_u[_k]; + while(p>_i)p=_u[--_k]; + _i-=p; + yj-=_k; + _y[j]=(yj+s)^s; + uprev(_u,_k+2,0); + } + while(++j<_n); +} + +/*Returns the index of the given combination of K elements chosen from a set + of size 1 with associated sign bits. + _y: The vector of pulses, whose sum of absolute values is K. + _k: Returns K.*/ +static inline opus_uint32 icwrs1(const int *_y,int *_k){ + *_k=abs(_y[0]); + return _y[0]<0; +} + +#ifndef SMALL_FOOTPRINT + +/*Returns the index of the given combination of K elements chosen from a set + of size 2 with associated sign bits. + _y: The vector of pulses, whose sum of absolute values is K. + _k: Returns K.*/ +static inline opus_uint32 icwrs2(const int *_y,int *_k){ + opus_uint32 i; + int k; + i=icwrs1(_y+1,&k); + i+=k?ucwrs2(k):0; + k+=abs(_y[0]); + if(_y[0]<0)i+=ucwrs2(k+1U); + *_k=k; + return i; +} + +/*Returns the index of the given combination of K elements chosen from a set + of size 3 with associated sign bits. + _y: The vector of pulses, whose sum of absolute values is K. + _k: Returns K.*/ +static inline opus_uint32 icwrs3(const int *_y,int *_k){ + opus_uint32 i; + int k; + i=icwrs2(_y+1,&k); + i+=k?ucwrs3(k):0; + k+=abs(_y[0]); + if(_y[0]<0)i+=ucwrs3(k+1U); + *_k=k; + return i; +} + +/*Returns the index of the given combination of K elements chosen from a set + of size 4 with associated sign bits. + _y: The vector of pulses, whose sum of absolute values is K. + _k: Returns K.*/ +static inline opus_uint32 icwrs4(const int *_y,int *_k){ + opus_uint32 i; + int k; + i=icwrs3(_y+1,&k); + i+=k?ucwrs4(k):0; + k+=abs(_y[0]); + if(_y[0]<0)i+=ucwrs4(k+1); + *_k=k; + return i; +} + +#endif /* SMALL_FOOTPRINT */ + +/*Returns the index of the given combination of K elements chosen from a set + of size _n with associated sign bits. + _y: The vector of pulses, whose sum of absolute values must be _k. + _nc: Returns V(_n,_k).*/ +static inline opus_uint32 icwrs(int _n,int _k,opus_uint32 *_nc,const int *_y, + opus_uint32 *_u){ + opus_uint32 i; + int j; + int k; + /*We can't unroll the first two iterations of the loop unless _n>=2.*/ + celt_assert(_n>=2); + _u[0]=0; + for(k=1;k<=_k+1;k++)_u[k]=(k<<1)-1; + i=icwrs1(_y+_n-1,&k); + j=_n-2; + i+=_u[k]; + k+=abs(_y[j]); + if(_y[j]<0)i+=_u[k+1]; + while(j-->0){ + unext(_u,_k+2,0); + i+=_u[k]; + k+=abs(_y[j]); + if(_y[j]<0)i+=_u[k+1]; + } + *_nc=_u[k]+_u[k+1]; + return i; +} + +#ifdef CUSTOM_MODES +void get_required_bits(opus_int16 *_bits,int _n,int _maxk,int _frac){ + int k; + /*_maxk==0 => there's nothing to do.*/ + celt_assert(_maxk>0); + _bits[0]=0; + if (_n==1) + { + for (k=1;k<=_maxk;k++) + _bits[k] = 1<<_frac; + } + else { + VARDECL(opus_uint32,u); + SAVE_STACK; + ALLOC(u,_maxk+2U,opus_uint32); + ncwrs_urow(_n,_maxk,u); + for(k=1;k<=_maxk;k++) + _bits[k]=log2_frac(u[k]+u[k+1],_frac); + RESTORE_STACK; + } +} +#endif /* CUSTOM_MODES */ + +void encode_pulses(const int *_y,int _n,int _k,ec_enc *_enc){ + opus_uint32 i; + celt_assert(_k>0); +#ifndef SMALL_FOOTPRINT + switch(_n){ + case 2:{ + i=icwrs2(_y,&_k); + ec_enc_uint(_enc,i,ncwrs2(_k)); + }break; + case 3:{ + i=icwrs3(_y,&_k); + ec_enc_uint(_enc,i,ncwrs3(_k)); + }break; + case 4:{ + i=icwrs4(_y,&_k); + ec_enc_uint(_enc,i,ncwrs4(_k)); + }break; + default: + { +#endif + VARDECL(opus_uint32,u); + opus_uint32 nc; + SAVE_STACK; + ALLOC(u,_k+2U,opus_uint32); + i=icwrs(_n,_k,&nc,_y,u); + ec_enc_uint(_enc,i,nc); + RESTORE_STACK; +#ifndef SMALL_FOOTPRINT + } + break; + } +#endif +} + +void decode_pulses(int *_y,int _n,int _k,ec_dec *_dec) +{ + celt_assert(_k>0); +#ifndef SMALL_FOOTPRINT + switch(_n){ + case 2:cwrsi2(_k,ec_dec_uint(_dec,ncwrs2(_k)),_y);break; + case 3:cwrsi3(_k,ec_dec_uint(_dec,ncwrs3(_k)),_y);break; + case 4:cwrsi4(_k,ec_dec_uint(_dec,ncwrs4(_k)),_y);break; + default: + { +#endif + VARDECL(opus_uint32,u); + SAVE_STACK; + ALLOC(u,_k+2U,opus_uint32); + cwrsi(_n,_k,ec_dec_uint(_dec,ncwrs_urow(_n,_k,u)),_y,u); + RESTORE_STACK; +#ifndef SMALL_FOOTPRINT + } + break; + } +#endif +} diff --git a/code/opus-1.0.2/celt/cwrs.h b/code/opus-1.0.2/celt/cwrs.h new file mode 100644 index 00000000..7dfbd076 --- /dev/null +++ b/code/opus-1.0.2/celt/cwrs.h @@ -0,0 +1,48 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2007-2009 Timothy B. Terriberry + Written by Timothy B. Terriberry and Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (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 CWRS_H +#define CWRS_H + +#include "arch.h" +#include "stack_alloc.h" +#include "entenc.h" +#include "entdec.h" + +#ifdef CUSTOM_MODES +int log2_frac(opus_uint32 val, int frac); +#endif + +void get_required_bits(opus_int16 *bits, int N, int K, int frac); + +void encode_pulses(const int *_y, int N, int K, ec_enc *enc); + +void decode_pulses(int *_y, int N, int K, ec_dec *dec); + +#endif /* CWRS_H */ diff --git a/code/opus-1.0.2/celt/ecintrin.h b/code/opus-1.0.2/celt/ecintrin.h new file mode 100644 index 00000000..be57dd40 --- /dev/null +++ b/code/opus-1.0.2/celt/ecintrin.h @@ -0,0 +1,87 @@ +/* Copyright (c) 2003-2008 Timothy B. Terriberry + Copyright (c) 2008 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/*Some common macros for potential platform-specific optimization.*/ +#include "opus_types.h" +#include +#include +#include "arch.h" +#if !defined(_ecintrin_H) +# define _ecintrin_H (1) + +/*Some specific platforms may have optimized intrinsic or inline assembly + versions of these functions which can substantially improve performance. + We define macros for them to allow easy incorporation of these non-ANSI + features.*/ + +/*Modern gcc (4.x) can compile the naive versions of min and max with cmov if + given an appropriate architecture, but the branchless bit-twiddling versions + are just as fast, and do not require any special target architecture. + Earlier gcc versions (3.x) compiled both code to the same assembly + instructions, because of the way they represented ((_b)>(_a)) internally.*/ +# define EC_MINI(_a,_b) ((_a)+(((_b)-(_a))&-((_b)<(_a)))) + +/*Count leading zeros. + This macro should only be used for implementing ec_ilog(), if it is defined. + All other code should use EC_ILOG() instead.*/ +#if defined(_MSC_VER) && (_MSC_VER >= 1400) +# include +/*In _DEBUG mode this is not an intrinsic by default.*/ +# pragma intrinsic(_BitScanReverse) + +static __inline int ec_bsr(unsigned long _x){ + unsigned long ret; + _BitScanReverse(&ret,_x); + return (int)ret; +} +# define EC_CLZ0 (1) +# define EC_CLZ(_x) (-ec_bsr(_x)) +#elif defined(ENABLE_TI_DSPLIB) +# include "dsplib.h" +# define EC_CLZ0 (31) +# define EC_CLZ(_x) (_lnorm(_x)) +#elif __GNUC_PREREQ(3,4) +# if INT_MAX>=2147483647 +# define EC_CLZ0 ((int)sizeof(unsigned)*CHAR_BIT) +# define EC_CLZ(_x) (__builtin_clz(_x)) +# elif LONG_MAX>=2147483647L +# define EC_CLZ0 ((int)sizeof(unsigned long)*CHAR_BIT) +# define EC_CLZ(_x) (__builtin_clzl(_x)) +# endif +#endif + +#if defined(EC_CLZ) +/*Note that __builtin_clz is not defined when _x==0, according to the gcc + documentation (and that of the BSR instruction that implements it on x86). + The majority of the time we can never pass it zero. + When we need to, it can be special cased.*/ +# define EC_ILOG(_x) (EC_CLZ0-EC_CLZ(_x)) +#else +int ec_ilog(opus_uint32 _v); +# define EC_ILOG(_x) (ec_ilog(_x)) +#endif +#endif diff --git a/code/opus-1.0.2/celt/entcode.c b/code/opus-1.0.2/celt/entcode.c new file mode 100644 index 00000000..fa5d7c7c --- /dev/null +++ b/code/opus-1.0.2/celt/entcode.c @@ -0,0 +1,93 @@ +/* Copyright (c) 2001-2011 Timothy B. Terriberry +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "entcode.h" +#include "arch.h" + +#if !defined(EC_CLZ) +/*This is a fallback for systems where we don't know how to access + a BSR or CLZ instruction (see ecintrin.h). + If you are optimizing Opus on a new platform and it has a native CLZ or + BZR (e.g. cell, MIPS, x86, etc) then making it available to Opus will be + an easy performance win.*/ +int ec_ilog(opus_uint32 _v){ + /*On a Pentium M, this branchless version tested as the fastest on + 1,000,000,000 random 32-bit integers, edging out a similar version with + branches, and a 256-entry LUT version.*/ + int ret; + int m; + ret=!!_v; + m=!!(_v&0xFFFF0000)<<4; + _v>>=m; + ret|=m; + m=!!(_v&0xFF00)<<3; + _v>>=m; + ret|=m; + m=!!(_v&0xF0)<<2; + _v>>=m; + ret|=m; + m=!!(_v&0xC)<<1; + _v>>=m; + ret|=m; + ret+=!!(_v&0x2); + return ret; +} +#endif + +opus_uint32 ec_tell_frac(ec_ctx *_this){ + opus_uint32 nbits; + opus_uint32 r; + int l; + int i; + /*To handle the non-integral number of bits still left in the encoder/decoder + state, we compute the worst-case number of bits of val that must be + encoded to ensure that the value is inside the range for any possible + subsequent bits. + The computation here is independent of val itself (the decoder does not + even track that value), even though the real number of bits used after + ec_enc_done() may be 1 smaller if rng is a power of two and the + corresponding trailing bits of val are all zeros. + If we did try to track that special case, then coding a value with a + probability of 1/(1<nbits_total<rng); + r=_this->rng>>(l-16); + for(i=BITRES;i-->0;){ + int b; + r=r*r>>15; + b=(int)(r>>16); + l=l<<1|b; + r>>=b; + } + return nbits-l; +} diff --git a/code/opus-1.0.2/celt/entcode.h b/code/opus-1.0.2/celt/entcode.h new file mode 100644 index 00000000..aebecc06 --- /dev/null +++ b/code/opus-1.0.2/celt/entcode.h @@ -0,0 +1,116 @@ +/* Copyright (c) 2001-2011 Timothy B. Terriberry + Copyright (c) 2008-2009 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (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 "opus_types.h" + +#if !defined(_entcode_H) +# define _entcode_H (1) +# include +# include +# include "ecintrin.h" + +/*OPT: ec_window must be at least 32 bits, but if you have fast arithmetic on a + larger type, you can speed up the decoder by using it here.*/ +typedef opus_uint32 ec_window; +typedef struct ec_ctx ec_ctx; +typedef struct ec_ctx ec_enc; +typedef struct ec_ctx ec_dec; + +# define EC_WINDOW_SIZE ((int)sizeof(ec_window)*CHAR_BIT) + +/*The number of bits to use for the range-coded part of unsigned integers.*/ +# define EC_UINT_BITS (8) + +/*The resolution of fractional-precision bit usage measurements, i.e., + 3 => 1/8th bits.*/ +# define BITRES 3 + +/*The entropy encoder/decoder context. + We use the same structure for both, so that common functions like ec_tell() + can be used on either one.*/ +struct ec_ctx{ + /*Buffered input/output.*/ + unsigned char *buf; + /*The size of the buffer.*/ + opus_uint32 storage; + /*The offset at which the last byte containing raw bits was read/written.*/ + opus_uint32 end_offs; + /*Bits that will be read from/written at the end.*/ + ec_window end_window; + /*Number of valid bits in end_window.*/ + int nend_bits; + /*The total number of whole bits read/written. + This does not include partial bits currently in the range coder.*/ + int nbits_total; + /*The offset at which the next range coder byte will be read/written.*/ + opus_uint32 offs; + /*The number of values in the current range.*/ + opus_uint32 rng; + /*In the decoder: the difference between the top of the current range and + the input value, minus one. + In the encoder: the low end of the current range.*/ + opus_uint32 val; + /*In the decoder: the saved normalization factor from ec_decode(). + In the encoder: the number of oustanding carry propagating symbols.*/ + opus_uint32 ext; + /*A buffered input/output symbol, awaiting carry propagation.*/ + int rem; + /*Nonzero if an error occurred.*/ + int error; +}; + +static inline opus_uint32 ec_range_bytes(ec_ctx *_this){ + return _this->offs; +} + +static inline unsigned char *ec_get_buffer(ec_ctx *_this){ + return _this->buf; +} + +static inline int ec_get_error(ec_ctx *_this){ + return _this->error; +} + +/*Returns the number of bits "used" by the encoded or decoded symbols so far. + This same number can be computed in either the encoder or the decoder, and is + suitable for making coding decisions. + Return: The number of bits. + This will always be slightly larger than the exact value (e.g., all + rounding error is in the positive direction).*/ +static inline int ec_tell(ec_ctx *_this){ + return _this->nbits_total-EC_ILOG(_this->rng); +} + +/*Returns the number of bits "used" by the encoded or decoded symbols so far. + This same number can be computed in either the encoder or the decoder, and is + suitable for making coding decisions. + Return: The number of bits scaled by 2**BITRES. + This will always be slightly larger than the exact value (e.g., all + rounding error is in the positive direction).*/ +opus_uint32 ec_tell_frac(ec_ctx *_this); + +#endif diff --git a/code/opus-1.0.2/celt/entdec.c b/code/opus-1.0.2/celt/entdec.c new file mode 100644 index 00000000..75e3e45a --- /dev/null +++ b/code/opus-1.0.2/celt/entdec.c @@ -0,0 +1,245 @@ +/* Copyright (c) 2001-2011 Timothy B. Terriberry + Copyright (c) 2008-2009 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "os_support.h" +#include "arch.h" +#include "entdec.h" +#include "mfrngcod.h" + +/*A range decoder. + This is an entropy decoder based upon \cite{Mar79}, which is itself a + rediscovery of the FIFO arithmetic code introduced by \cite{Pas76}. + It is very similar to arithmetic encoding, except that encoding is done with + digits in any base, instead of with bits, and so it is faster when using + larger bases (i.e.: a byte). + The author claims an average waste of $\frac{1}{2}\log_b(2b)$ bits, where $b$ + is the base, longer than the theoretical optimum, but to my knowledge there + is no published justification for this claim. + This only seems true when using near-infinite precision arithmetic so that + the process is carried out with no rounding errors. + + An excellent description of implementation details is available at + http://www.arturocampos.com/ac_range.html + A recent work \cite{MNW98} which proposes several changes to arithmetic + encoding for efficiency actually re-discovers many of the principles + behind range encoding, and presents a good theoretical analysis of them. + + End of stream is handled by writing out the smallest number of bits that + ensures that the stream will be correctly decoded regardless of the value of + any subsequent bits. + ec_tell() can be used to determine how many bits were needed to decode + all the symbols thus far; other data can be packed in the remaining bits of + the input buffer. + @PHDTHESIS{Pas76, + author="Richard Clark Pasco", + title="Source coding algorithms for fast data compression", + school="Dept. of Electrical Engineering, Stanford University", + address="Stanford, CA", + month=May, + year=1976 + } + @INPROCEEDINGS{Mar79, + author="Martin, G.N.N.", + title="Range encoding: an algorithm for removing redundancy from a digitised + message", + booktitle="Video & Data Recording Conference", + year=1979, + address="Southampton", + month=Jul + } + @ARTICLE{MNW98, + author="Alistair Moffat and Radford Neal and Ian H. Witten", + title="Arithmetic Coding Revisited", + journal="{ACM} Transactions on Information Systems", + year=1998, + volume=16, + number=3, + pages="256--294", + month=Jul, + URL="http://www.stanford.edu/class/ee398/handouts/papers/Moffat98ArithmCoding.pdf" + }*/ + +static int ec_read_byte(ec_dec *_this){ + return _this->offs<_this->storage?_this->buf[_this->offs++]:0; +} + +static int ec_read_byte_from_end(ec_dec *_this){ + return _this->end_offs<_this->storage? + _this->buf[_this->storage-++(_this->end_offs)]:0; +} + +/*Normalizes the contents of val and rng so that rng lies entirely in the + high-order symbol.*/ +static void ec_dec_normalize(ec_dec *_this){ + /*If the range is too small, rescale it and input some bits.*/ + while(_this->rng<=EC_CODE_BOT){ + int sym; + _this->nbits_total+=EC_SYM_BITS; + _this->rng<<=EC_SYM_BITS; + /*Use up the remaining bits from our last symbol.*/ + sym=_this->rem; + /*Read the next value from the input.*/ + _this->rem=ec_read_byte(_this); + /*Take the rest of the bits we need from this new symbol.*/ + sym=(sym<rem)>>(EC_SYM_BITS-EC_CODE_EXTRA); + /*And subtract them from val, capped to be less than EC_CODE_TOP.*/ + _this->val=((_this->val<buf=_buf; + _this->storage=_storage; + _this->end_offs=0; + _this->end_window=0; + _this->nend_bits=0; + /*This is the offset from which ec_tell() will subtract partial bits. + The final value after the ec_dec_normalize() call will be the same as in + the encoder, but we have to compensate for the bits that are added there.*/ + _this->nbits_total=EC_CODE_BITS+1 + -((EC_CODE_BITS-EC_CODE_EXTRA)/EC_SYM_BITS)*EC_SYM_BITS; + _this->offs=0; + _this->rng=1U<rem=ec_read_byte(_this); + _this->val=_this->rng-1-(_this->rem>>(EC_SYM_BITS-EC_CODE_EXTRA)); + _this->error=0; + /*Normalize the interval.*/ + ec_dec_normalize(_this); +} + +unsigned ec_decode(ec_dec *_this,unsigned _ft){ + unsigned s; + _this->ext=_this->rng/_ft; + s=(unsigned)(_this->val/_this->ext); + return _ft-EC_MINI(s+1,_ft); +} + +unsigned ec_decode_bin(ec_dec *_this,unsigned _bits){ + unsigned s; + _this->ext=_this->rng>>_bits; + s=(unsigned)(_this->val/_this->ext); + return (1U<<_bits)-EC_MINI(s+1U,1U<<_bits); +} + +void ec_dec_update(ec_dec *_this,unsigned _fl,unsigned _fh,unsigned _ft){ + opus_uint32 s; + s=IMUL32(_this->ext,_ft-_fh); + _this->val-=s; + _this->rng=_fl>0?IMUL32(_this->ext,_fh-_fl):_this->rng-s; + ec_dec_normalize(_this); +} + +/*The probability of having a "one" is 1/(1<<_logp).*/ +int ec_dec_bit_logp(ec_dec *_this,unsigned _logp){ + opus_uint32 r; + opus_uint32 d; + opus_uint32 s; + int ret; + r=_this->rng; + d=_this->val; + s=r>>_logp; + ret=dval=d-s; + _this->rng=ret?s:r-s; + ec_dec_normalize(_this); + return ret; +} + +int ec_dec_icdf(ec_dec *_this,const unsigned char *_icdf,unsigned _ftb){ + opus_uint32 r; + opus_uint32 d; + opus_uint32 s; + opus_uint32 t; + int ret; + s=_this->rng; + d=_this->val; + r=s>>_ftb; + ret=-1; + do{ + t=s; + s=IMUL32(r,_icdf[++ret]); + } + while(dval=d-s; + _this->rng=t-s; + ec_dec_normalize(_this); + return ret; +} + +opus_uint32 ec_dec_uint(ec_dec *_this,opus_uint32 _ft){ + unsigned ft; + unsigned s; + int ftb; + /*In order to optimize EC_ILOG(), it is undefined for the value 0.*/ + celt_assert(_ft>1); + _ft--; + ftb=EC_ILOG(_ft); + if(ftb>EC_UINT_BITS){ + opus_uint32 t; + ftb-=EC_UINT_BITS; + ft=(unsigned)(_ft>>ftb)+1; + s=ec_decode(_this,ft); + ec_dec_update(_this,s,s+1,ft); + t=(opus_uint32)s<error=1; + return _ft; + } + else{ + _ft++; + s=ec_decode(_this,(unsigned)_ft); + ec_dec_update(_this,s,s+1,(unsigned)_ft); + return s; + } +} + +opus_uint32 ec_dec_bits(ec_dec *_this,unsigned _bits){ + ec_window window; + int available; + opus_uint32 ret; + window=_this->end_window; + available=_this->nend_bits; + if((unsigned)available<_bits){ + do{ + window|=(ec_window)ec_read_byte_from_end(_this)<>=_bits; + available-=_bits; + _this->end_window=window; + _this->nend_bits=available; + _this->nbits_total+=_bits; + return ret; +} diff --git a/code/opus-1.0.2/celt/entdec.h b/code/opus-1.0.2/celt/entdec.h new file mode 100644 index 00000000..d8ab3187 --- /dev/null +++ b/code/opus-1.0.2/celt/entdec.h @@ -0,0 +1,100 @@ +/* Copyright (c) 2001-2011 Timothy B. Terriberry + Copyright (c) 2008-2009 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#if !defined(_entdec_H) +# define _entdec_H (1) +# include +# include "entcode.h" + +/*Initializes the decoder. + _buf: The input buffer to use. + Return: 0 on success, or a negative value on error.*/ +void ec_dec_init(ec_dec *_this,unsigned char *_buf,opus_uint32 _storage); + +/*Calculates the cumulative frequency for the next symbol. + This can then be fed into the probability model to determine what that + symbol is, and the additional frequency information required to advance to + the next symbol. + This function cannot be called more than once without a corresponding call to + ec_dec_update(), or decoding will not proceed correctly. + _ft: The total frequency of the symbols in the alphabet the next symbol was + encoded with. + Return: A cumulative frequency representing the encoded symbol. + If the cumulative frequency of all the symbols before the one that + was encoded was fl, and the cumulative frequency of all the symbols + up to and including the one encoded is fh, then the returned value + will fall in the range [fl,fh).*/ +unsigned ec_decode(ec_dec *_this,unsigned _ft); + +/*Equivalent to ec_decode() with _ft==1<<_bits.*/ +unsigned ec_decode_bin(ec_dec *_this,unsigned _bits); + +/*Advance the decoder past the next symbol using the frequency information the + symbol was encoded with. + Exactly one call to ec_decode() must have been made so that all necessary + intermediate calculations are performed. + _fl: The cumulative frequency of all symbols that come before the symbol + decoded. + _fh: The cumulative frequency of all symbols up to and including the symbol + decoded. + Together with _fl, this defines the range [_fl,_fh) in which the value + returned above must fall. + _ft: The total frequency of the symbols in the alphabet the symbol decoded + was encoded in. + This must be the same as passed to the preceding call to ec_decode().*/ +void ec_dec_update(ec_dec *_this,unsigned _fl,unsigned _fh,unsigned _ft); + +/* Decode a bit that has a 1/(1<<_logp) probability of being a one */ +int ec_dec_bit_logp(ec_dec *_this,unsigned _logp); + +/*Decodes a symbol given an "inverse" CDF table. + No call to ec_dec_update() is necessary after this call. + _icdf: The "inverse" CDF, such that symbol s falls in the range + [s>0?ft-_icdf[s-1]:0,ft-_icdf[s]), where ft=1<<_ftb. + The values must be monotonically non-increasing, and the last value + must be 0. + _ftb: The number of bits of precision in the cumulative distribution. + Return: The decoded symbol s.*/ +int ec_dec_icdf(ec_dec *_this,const unsigned char *_icdf,unsigned _ftb); + +/*Extracts a raw unsigned integer with a non-power-of-2 range from the stream. + The bits must have been encoded with ec_enc_uint(). + No call to ec_dec_update() is necessary after this call. + _ft: The number of integers that can be decoded (one more than the max). + This must be at least one, and no more than 2**32-1. + Return: The decoded bits.*/ +opus_uint32 ec_dec_uint(ec_dec *_this,opus_uint32 _ft); + +/*Extracts a sequence of raw bits from the stream. + The bits must have been encoded with ec_enc_bits(). + No call to ec_dec_update() is necessary after this call. + _ftb: The number of bits to extract. + This must be between 0 and 25, inclusive. + Return: The decoded bits.*/ +opus_uint32 ec_dec_bits(ec_dec *_this,unsigned _ftb); + +#endif diff --git a/code/opus-1.0.2/celt/entenc.c b/code/opus-1.0.2/celt/entenc.c new file mode 100644 index 00000000..a7e34ece --- /dev/null +++ b/code/opus-1.0.2/celt/entenc.c @@ -0,0 +1,294 @@ +/* Copyright (c) 2001-2011 Timothy B. Terriberry + Copyright (c) 2008-2009 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#if defined(HAVE_CONFIG_H) +# include "config.h" +#endif +#include "os_support.h" +#include "arch.h" +#include "entenc.h" +#include "mfrngcod.h" + +/*A range encoder. + See entdec.c and the references for implementation details \cite{Mar79,MNW98}. + + @INPROCEEDINGS{Mar79, + author="Martin, G.N.N.", + title="Range encoding: an algorithm for removing redundancy from a digitised + message", + booktitle="Video \& Data Recording Conference", + year=1979, + address="Southampton", + month=Jul + } + @ARTICLE{MNW98, + author="Alistair Moffat and Radford Neal and Ian H. Witten", + title="Arithmetic Coding Revisited", + journal="{ACM} Transactions on Information Systems", + year=1998, + volume=16, + number=3, + pages="256--294", + month=Jul, + URL="http://www.stanford.edu/class/ee398/handouts/papers/Moffat98ArithmCoding.pdf" + }*/ + +static int ec_write_byte(ec_enc *_this,unsigned _value){ + if(_this->offs+_this->end_offs>=_this->storage)return -1; + _this->buf[_this->offs++]=(unsigned char)_value; + return 0; +} + +static int ec_write_byte_at_end(ec_enc *_this,unsigned _value){ + if(_this->offs+_this->end_offs>=_this->storage)return -1; + _this->buf[_this->storage-++(_this->end_offs)]=(unsigned char)_value; + return 0; +} + +/*Outputs a symbol, with a carry bit. + If there is a potential to propagate a carry over several symbols, they are + buffered until it can be determined whether or not an actual carry will + occur. + If the counter for the buffered symbols overflows, then the stream becomes + undecodable. + This gives a theoretical limit of a few billion symbols in a single packet on + 32-bit systems. + The alternative is to truncate the range in order to force a carry, but + requires similar carry tracking in the decoder, needlessly slowing it down.*/ +static void ec_enc_carry_out(ec_enc *_this,int _c){ + if(_c!=EC_SYM_MAX){ + /*No further carry propagation possible, flush buffer.*/ + int carry; + carry=_c>>EC_SYM_BITS; + /*Don't output a byte on the first write. + This compare should be taken care of by branch-prediction thereafter.*/ + if(_this->rem>=0)_this->error|=ec_write_byte(_this,_this->rem+carry); + if(_this->ext>0){ + unsigned sym; + sym=(EC_SYM_MAX+carry)&EC_SYM_MAX; + do _this->error|=ec_write_byte(_this,sym); + while(--(_this->ext)>0); + } + _this->rem=_c&EC_SYM_MAX; + } + else _this->ext++; +} + +static void ec_enc_normalize(ec_enc *_this){ + /*If the range is too small, output some bits and rescale it.*/ + while(_this->rng<=EC_CODE_BOT){ + ec_enc_carry_out(_this,(int)(_this->val>>EC_CODE_SHIFT)); + /*Move the next-to-high-order symbol into the high-order position.*/ + _this->val=(_this->val<rng<<=EC_SYM_BITS; + _this->nbits_total+=EC_SYM_BITS; + } +} + +void ec_enc_init(ec_enc *_this,unsigned char *_buf,opus_uint32 _size){ + _this->buf=_buf; + _this->end_offs=0; + _this->end_window=0; + _this->nend_bits=0; + /*This is the offset from which ec_tell() will subtract partial bits.*/ + _this->nbits_total=EC_CODE_BITS+1; + _this->offs=0; + _this->rng=EC_CODE_TOP; + _this->rem=-1; + _this->val=0; + _this->ext=0; + _this->storage=_size; + _this->error=0; +} + +void ec_encode(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _ft){ + opus_uint32 r; + r=_this->rng/_ft; + if(_fl>0){ + _this->val+=_this->rng-IMUL32(r,(_ft-_fl)); + _this->rng=IMUL32(r,(_fh-_fl)); + } + else _this->rng-=IMUL32(r,(_ft-_fh)); + ec_enc_normalize(_this); +} + +void ec_encode_bin(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _bits){ + opus_uint32 r; + r=_this->rng>>_bits; + if(_fl>0){ + _this->val+=_this->rng-IMUL32(r,((1U<<_bits)-_fl)); + _this->rng=IMUL32(r,(_fh-_fl)); + } + else _this->rng-=IMUL32(r,((1U<<_bits)-_fh)); + ec_enc_normalize(_this); +} + +/*The probability of having a "one" is 1/(1<<_logp).*/ +void ec_enc_bit_logp(ec_enc *_this,int _val,unsigned _logp){ + opus_uint32 r; + opus_uint32 s; + opus_uint32 l; + r=_this->rng; + l=_this->val; + s=r>>_logp; + r-=s; + if(_val)_this->val=l+r; + _this->rng=_val?s:r; + ec_enc_normalize(_this); +} + +void ec_enc_icdf(ec_enc *_this,int _s,const unsigned char *_icdf,unsigned _ftb){ + opus_uint32 r; + r=_this->rng>>_ftb; + if(_s>0){ + _this->val+=_this->rng-IMUL32(r,_icdf[_s-1]); + _this->rng=IMUL32(r,_icdf[_s-1]-_icdf[_s]); + } + else _this->rng-=IMUL32(r,_icdf[_s]); + ec_enc_normalize(_this); +} + +void ec_enc_uint(ec_enc *_this,opus_uint32 _fl,opus_uint32 _ft){ + unsigned ft; + unsigned fl; + int ftb; + /*In order to optimize EC_ILOG(), it is undefined for the value 0.*/ + celt_assert(_ft>1); + _ft--; + ftb=EC_ILOG(_ft); + if(ftb>EC_UINT_BITS){ + ftb-=EC_UINT_BITS; + ft=(_ft>>ftb)+1; + fl=(unsigned)(_fl>>ftb); + ec_encode(_this,fl,fl+1,ft); + ec_enc_bits(_this,_fl&(((opus_uint32)1<end_window; + used=_this->nend_bits; + celt_assert(_bits>0); + if(used+_bits>EC_WINDOW_SIZE){ + do{ + _this->error|=ec_write_byte_at_end(_this,(unsigned)window&EC_SYM_MAX); + window>>=EC_SYM_BITS; + used-=EC_SYM_BITS; + } + while(used>=EC_SYM_BITS); + } + window|=(ec_window)_fl<end_window=window; + _this->nend_bits=used; + _this->nbits_total+=_bits; +} + +void ec_enc_patch_initial_bits(ec_enc *_this,unsigned _val,unsigned _nbits){ + int shift; + unsigned mask; + celt_assert(_nbits<=EC_SYM_BITS); + shift=EC_SYM_BITS-_nbits; + mask=((1<<_nbits)-1)<offs>0){ + /*The first byte has been finalized.*/ + _this->buf[0]=(unsigned char)((_this->buf[0]&~mask)|_val<rem>=0){ + /*The first byte is still awaiting carry propagation.*/ + _this->rem=(_this->rem&~mask)|_val<rng<=(EC_CODE_TOP>>_nbits)){ + /*The renormalization loop has never been run.*/ + _this->val=(_this->val&~((opus_uint32)mask<error=-1; +} + +void ec_enc_shrink(ec_enc *_this,opus_uint32 _size){ + celt_assert(_this->offs+_this->end_offs<=_size); + OPUS_MOVE(_this->buf+_size-_this->end_offs, + _this->buf+_this->storage-_this->end_offs,_this->end_offs); + _this->storage=_size; +} + +void ec_enc_done(ec_enc *_this){ + ec_window window; + int used; + opus_uint32 msk; + opus_uint32 end; + int l; + /*We output the minimum number of bits that ensures that the symbols encoded + thus far will be decoded correctly regardless of the bits that follow.*/ + l=EC_CODE_BITS-EC_ILOG(_this->rng); + msk=(EC_CODE_TOP-1)>>l; + end=(_this->val+msk)&~msk; + if((end|msk)>=_this->val+_this->rng){ + l++; + msk>>=1; + end=(_this->val+msk)&~msk; + } + while(l>0){ + ec_enc_carry_out(_this,(int)(end>>EC_CODE_SHIFT)); + end=(end<rem>=0||_this->ext>0)ec_enc_carry_out(_this,0); + /*If we have buffered extra bits, flush them as well.*/ + window=_this->end_window; + used=_this->nend_bits; + while(used>=EC_SYM_BITS){ + _this->error|=ec_write_byte_at_end(_this,(unsigned)window&EC_SYM_MAX); + window>>=EC_SYM_BITS; + used-=EC_SYM_BITS; + } + /*Clear any excess space and add any remaining extra bits to the last byte.*/ + if(!_this->error){ + OPUS_CLEAR(_this->buf+_this->offs, + _this->storage-_this->offs-_this->end_offs); + if(used>0){ + /*If there's no range coder data at all, give up.*/ + if(_this->end_offs>=_this->storage)_this->error=-1; + else{ + l=-l; + /*If we've busted, don't add too many extra bits to the last byte; it + would corrupt the range coder data, and that's more important.*/ + if(_this->offs+_this->end_offs>=_this->storage&&lerror=-1; + } + _this->buf[_this->storage-_this->end_offs-1]|=(unsigned char)window; + } + } + } +} diff --git a/code/opus-1.0.2/celt/entenc.h b/code/opus-1.0.2/celt/entenc.h new file mode 100644 index 00000000..796bc4d5 --- /dev/null +++ b/code/opus-1.0.2/celt/entenc.h @@ -0,0 +1,110 @@ +/* Copyright (c) 2001-2011 Timothy B. Terriberry + Copyright (c) 2008-2009 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#if !defined(_entenc_H) +# define _entenc_H (1) +# include +# include "entcode.h" + +/*Initializes the encoder. + _buf: The buffer to store output bytes in. + _size: The size of the buffer, in chars.*/ +void ec_enc_init(ec_enc *_this,unsigned char *_buf,opus_uint32 _size); +/*Encodes a symbol given its frequency information. + The frequency information must be discernable by the decoder, assuming it + has read only the previous symbols from the stream. + It is allowable to change the frequency information, or even the entire + source alphabet, so long as the decoder can tell from the context of the + previously encoded information that it is supposed to do so as well. + _fl: The cumulative frequency of all symbols that come before the one to be + encoded. + _fh: The cumulative frequency of all symbols up to and including the one to + be encoded. + Together with _fl, this defines the range [_fl,_fh) in which the + decoded value will fall. + _ft: The sum of the frequencies of all the symbols*/ +void ec_encode(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _ft); + +/*Equivalent to ec_encode() with _ft==1<<_bits.*/ +void ec_encode_bin(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _bits); + +/* Encode a bit that has a 1/(1<<_logp) probability of being a one */ +void ec_enc_bit_logp(ec_enc *_this,int _val,unsigned _logp); + +/*Encodes a symbol given an "inverse" CDF table. + _s: The index of the symbol to encode. + _icdf: The "inverse" CDF, such that symbol _s falls in the range + [_s>0?ft-_icdf[_s-1]:0,ft-_icdf[_s]), where ft=1<<_ftb. + The values must be monotonically non-increasing, and the last value + must be 0. + _ftb: The number of bits of precision in the cumulative distribution.*/ +void ec_enc_icdf(ec_enc *_this,int _s,const unsigned char *_icdf,unsigned _ftb); + +/*Encodes a raw unsigned integer in the stream. + _fl: The integer to encode. + _ft: The number of integers that can be encoded (one more than the max). + This must be at least one, and no more than 2**32-1.*/ +void ec_enc_uint(ec_enc *_this,opus_uint32 _fl,opus_uint32 _ft); + +/*Encodes a sequence of raw bits in the stream. + _fl: The bits to encode. + _ftb: The number of bits to encode. + This must be between 1 and 25, inclusive.*/ +void ec_enc_bits(ec_enc *_this,opus_uint32 _fl,unsigned _ftb); + +/*Overwrites a few bits at the very start of an existing stream, after they + have already been encoded. + This makes it possible to have a few flags up front, where it is easy for + decoders to access them without parsing the whole stream, even if their + values are not determined until late in the encoding process, without having + to buffer all the intermediate symbols in the encoder. + In order for this to work, at least _nbits bits must have already been + encoded using probabilities that are an exact power of two. + The encoder can verify the number of encoded bits is sufficient, but cannot + check this latter condition. + _val: The bits to encode (in the least _nbits significant bits). + They will be decoded in order from most-significant to least. + _nbits: The number of bits to overwrite. + This must be no more than 8.*/ +void ec_enc_patch_initial_bits(ec_enc *_this,unsigned _val,unsigned _nbits); + +/*Compacts the data to fit in the target size. + This moves up the raw bits at the end of the current buffer so they are at + the end of the new buffer size. + The caller must ensure that the amount of data that's already been written + will fit in the new size. + _size: The number of bytes in the new buffer. + This must be large enough to contain the bits already written, and + must be no larger than the existing size.*/ +void ec_enc_shrink(ec_enc *_this,opus_uint32 _size); + +/*Indicates that there are no more symbols to encode. + All reamining output bytes are flushed to the output buffer. + ec_enc_init() must be called before the encoder can be used again.*/ +void ec_enc_done(ec_enc *_this); + +#endif diff --git a/code/opus-1.0.2/celt/fixed_debug.h b/code/opus-1.0.2/celt/fixed_debug.h new file mode 100644 index 00000000..f11d890d --- /dev/null +++ b/code/opus-1.0.2/celt/fixed_debug.h @@ -0,0 +1,763 @@ +/* Copyright (C) 2003-2008 Jean-Marc Valin + Copyright (C) 2007-2012 Xiph.Org Foundation */ +/** + @file fixed_debug.h + @brief Fixed-point operations with debugging +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (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 FIXED_DEBUG_H +#define FIXED_DEBUG_H + +#include + +#ifdef CELT_C +#include "opus_defines.h" +OPUS_EXPORT opus_int64 celt_mips=0; +#else +extern opus_int64 celt_mips; +#endif + +#define MULT16_16SU(a,b) ((opus_val32)(opus_val16)(a)*(opus_val32)(opus_uint16)(b)) +#define MULT32_32_Q31(a,b) ADD32(ADD32(SHL32(MULT16_16(SHR32((a),16),SHR((b),16)),1), SHR32(MULT16_16SU(SHR32((a),16),((b)&0x0000ffff)),15)), SHR32(MULT16_16SU(SHR32((b),16),((a)&0x0000ffff)),15)) + +/** 16x32 multiplication, followed by a 16-bit shift right. Results fits in 32 bits */ +#define MULT16_32_Q16(a,b) ADD32(MULT16_16((a),SHR32((b),16)), SHR32(MULT16_16SU((a),((b)&0x0000ffff)),16)) + +#define MULT16_32_P16(a,b) MULT16_32_PX(a,b,16) + +#define QCONST16(x,bits) ((opus_val16)(.5+(x)*(((opus_val32)1)<<(bits)))) +#define QCONST32(x,bits) ((opus_val32)(.5+(x)*(((opus_val32)1)<<(bits)))) + +#define VERIFY_SHORT(x) ((x)<=32767&&(x)>=-32768) +#define VERIFY_INT(x) ((x)<=2147483647LL&&(x)>=-2147483648LL) +#define VERIFY_UINT(x) ((x)<=(2147483647LLU<<1)) + +#define SHR(a,b) SHR32(a,b) +#define PSHR(a,b) PSHR32(a,b) + +static inline short NEG16(int x) +{ + int res; + if (!VERIFY_SHORT(x)) + { + fprintf (stderr, "NEG16: input is not short: %d\n", (int)x); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = -x; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "NEG16: output is not short: %d\n", (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips++; + return res; +} +static inline int NEG32(opus_int64 x) +{ + opus_int64 res; + if (!VERIFY_INT(x)) + { + fprintf (stderr, "NEG16: input is not int: %d\n", (int)x); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = -x; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "NEG16: output is not int: %d\n", (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=2; + return res; +} + +#define EXTRACT16(x) EXTRACT16_(x, __FILE__, __LINE__) +static inline short EXTRACT16_(int x, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(x)) + { + fprintf (stderr, "EXTRACT16: input is not short: %d in %s: line %d\n", x, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = x; + celt_mips++; + return res; +} + +#define EXTEND32(x) EXTEND32_(x, __FILE__, __LINE__) +static inline int EXTEND32_(int x, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(x)) + { + fprintf (stderr, "EXTEND32: input is not short: %d in %s: line %d\n", x, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = x; + celt_mips++; + return res; +} + +#define SHR16(a, shift) SHR16_(a, shift, __FILE__, __LINE__) +static inline short SHR16_(int a, int shift, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift)) + { + fprintf (stderr, "SHR16: inputs are not short: %d >> %d in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a>>shift; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "SHR16: output is not short: %d in %s: line %d\n", res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips++; + return res; +} +#define SHL16(a, shift) SHL16_(a, shift, __FILE__, __LINE__) +static inline short SHL16_(int a, int shift, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift)) + { + fprintf (stderr, "SHL16: inputs are not short: %d %d in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a<>shift; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "SHR32: output is not int: %d\n", (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=2; + return res; +} +#define SHL32(a, shift) SHL32_(a, shift, __FILE__, __LINE__) +static inline int SHL32_(opus_int64 a, int shift, char *file, int line) +{ + opus_int64 res; + if (!VERIFY_INT(a) || !VERIFY_SHORT(shift)) + { + fprintf (stderr, "SHL32: inputs are not int: %lld %d in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a<>1))),shift)) +#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift))) + +#define ROUND16(x,a) (celt_mips--,EXTRACT16(PSHR32((x),(a)))) +#define HALF16(x) (SHR16(x,1)) +#define HALF32(x) (SHR32(x,1)) + +//#define SHR(a,shift) ((a) >> (shift)) +//#define SHL(a,shift) ((a) << (shift)) + +#define ADD16(a, b) ADD16_(a, b, __FILE__, __LINE__) +static inline short ADD16_(int a, int b, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "ADD16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a+b; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "ADD16: output is not short: %d+%d=%d in %s: line %d\n", a,b,res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips++; + return res; +} + +#define SUB16(a, b) SUB16_(a, b, __FILE__, __LINE__) +static inline short SUB16_(int a, int b, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "SUB16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a-b; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "SUB16: output is not short: %d in %s: line %d\n", res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips++; + return res; +} + +#define ADD32(a, b) ADD32_(a, b, __FILE__, __LINE__) +static inline int ADD32_(opus_int64 a, opus_int64 b, char *file, int line) +{ + opus_int64 res; + if (!VERIFY_INT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "ADD32: inputs are not int: %d %d in %s: line %d\n", (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a+b; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "ADD32: output is not int: %d in %s: line %d\n", (int)res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=2; + return res; +} + +#define SUB32(a, b) SUB32_(a, b, __FILE__, __LINE__) +static inline int SUB32_(opus_int64 a, opus_int64 b, char *file, int line) +{ + opus_int64 res; + if (!VERIFY_INT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "SUB32: inputs are not int: %d %d in %s: line %d\n", (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a-b; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "SUB32: output is not int: %d in %s: line %d\n", (int)res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=2; + return res; +} + +#undef UADD32 +#define UADD32(a, b) UADD32_(a, b, __FILE__, __LINE__) +static inline unsigned int UADD32_(opus_uint64 a, opus_uint64 b, char *file, int line) +{ + opus_uint64 res; + if (!VERIFY_UINT(a) || !VERIFY_UINT(b)) + { + fprintf (stderr, "UADD32: inputs are not uint32: %llu %llu in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a+b; + if (!VERIFY_UINT(res)) + { + fprintf (stderr, "UADD32: output is not uint32: %llu in %s: line %d\n", res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=2; + return res; +} + +#undef USUB32 +#define USUB32(a, b) USUB32_(a, b, __FILE__, __LINE__) +static inline unsigned int USUB32_(opus_uint64 a, opus_uint64 b, char *file, int line) +{ + opus_uint64 res; + if (!VERIFY_UINT(a) || !VERIFY_UINT(b)) + { + fprintf (stderr, "USUB32: inputs are not uint32: %llu %llu in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + if (a=((opus_val32)(1)<<(15+Q))) + { + fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = (((opus_int64)a)*(opus_int64)b) >> Q; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "MULT16_32_Q%d: output is not int: %d*%d=%d in %s: line %d\n", Q, (int)a, (int)b,(int)res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + if (Q==15) + celt_mips+=3; + else + celt_mips+=4; + return res; +} + +#define MULT16_32_PX(a, b, Q) MULT16_32_PX_(a, b, Q, __FILE__, __LINE__) +static inline int MULT16_32_PX_(int a, opus_int64 b, int Q, char *file, int line) +{ + opus_int64 res; + if (!VERIFY_SHORT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "MULT16_32_P%d: inputs are not short+int: %d %d in %s: line %d\n\n", Q, (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + if (ABS32(b)>=((opus_int64)(1)<<(15+Q))) + { + fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n\n", Q, (int)a, (int)b,file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = ((((opus_int64)a)*(opus_int64)b) + (((opus_val32)(1)<>1))>> Q; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "MULT16_32_P%d: output is not int: %d*%d=%d in %s: line %d\n\n", Q, (int)a, (int)b,(int)res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + if (Q==15) + celt_mips+=4; + else + celt_mips+=5; + return res; +} + +#define MULT16_32_Q15(a,b) MULT16_32_QX(a,b,15) +#define MAC16_32_Q15(c,a,b) (celt_mips-=2,ADD32((c),MULT16_32_Q15((a),(b)))) + +static inline int SATURATE(int a, int b) +{ + if (a>b) + a=b; + if (a<-b) + a = -b; + celt_mips+=3; + return a; +} + +static inline int MULT16_16_Q11_32(int a, int b) +{ + opus_int64 res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_Q11: inputs are not short: %d %d\n", a, b); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = ((opus_int64)a)*b; + res >>= 11; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "MULT16_16_Q11: output is not short: %d*%d=%d\n", (int)a, (int)b, (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=3; + return res; +} +static inline short MULT16_16_Q13(int a, int b) +{ + opus_int64 res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_Q13: inputs are not short: %d %d\n", a, b); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = ((opus_int64)a)*b; + res >>= 13; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "MULT16_16_Q13: output is not short: %d*%d=%d\n", a, b, (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=3; + return res; +} +static inline short MULT16_16_Q14(int a, int b) +{ + opus_int64 res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_Q14: inputs are not short: %d %d\n", a, b); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = ((opus_int64)a)*b; + res >>= 14; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "MULT16_16_Q14: output is not short: %d\n", (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=3; + return res; +} + +#define MULT16_16_Q15(a, b) MULT16_16_Q15_(a, b, __FILE__, __LINE__) +static inline short MULT16_16_Q15_(int a, int b, char *file, int line) +{ + opus_int64 res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_Q15: inputs are not short: %d %d in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = ((opus_int64)a)*b; + res >>= 15; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "MULT16_16_Q15: output is not short: %d in %s: line %d\n", (int)res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=1; + return res; +} + +static inline short MULT16_16_P13(int a, int b) +{ + opus_int64 res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_P13: inputs are not short: %d %d\n", a, b); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = ((opus_int64)a)*b; + res += 4096; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "MULT16_16_P13: overflow: %d*%d=%d\n", a, b, (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res >>= 13; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "MULT16_16_P13: output is not short: %d*%d=%d\n", a, b, (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=4; + return res; +} +static inline short MULT16_16_P14(int a, int b) +{ + opus_int64 res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_P14: inputs are not short: %d %d\n", a, b); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = ((opus_int64)a)*b; + res += 8192; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "MULT16_16_P14: overflow: %d*%d=%d\n", a, b, (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res >>= 14; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "MULT16_16_P14: output is not short: %d*%d=%d\n", a, b, (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=4; + return res; +} +static inline short MULT16_16_P15(int a, int b) +{ + opus_int64 res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_P15: inputs are not short: %d %d\n", a, b); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = ((opus_int64)a)*b; + res += 16384; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "MULT16_16_P15: overflow: %d*%d=%d\n", a, b, (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res >>= 15; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "MULT16_16_P15: output is not short: %d*%d=%d\n", a, b, (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=2; + return res; +} + +#define DIV32_16(a, b) DIV32_16_(a, b, __FILE__, __LINE__) + +static inline int DIV32_16_(opus_int64 a, opus_int64 b, char *file, int line) +{ + opus_int64 res; + if (b==0) + { + fprintf(stderr, "DIV32_16: divide by zero: %d/%d in %s: line %d\n", (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + return 0; + } + if (!VERIFY_INT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "DIV32_16: inputs are not int/short: %d %d in %s: line %d\n", (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a/b; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "DIV32_16: output is not short: %d / %d = %d in %s: line %d\n", (int)a,(int)b,(int)res, file, line); + if (res>32767) + res = 32767; + if (res<-32768) + res = -32768; +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=35; + return res; +} + +#define DIV32(a, b) DIV32_(a, b, __FILE__, __LINE__) +static inline int DIV32_(opus_int64 a, opus_int64 b, char *file, int line) +{ + opus_int64 res; + if (b==0) + { + fprintf(stderr, "DIV32: divide by zero: %d/%d in %s: line %d\n", (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + return 0; + } + + if (!VERIFY_INT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "DIV32: inputs are not int/short: %d %d in %s: line %d\n", (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a/b; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "DIV32: output is not int: %d in %s: line %d\n", (int)res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=70; + return res; +} + +#undef PRINT_MIPS +#define PRINT_MIPS(file) do {fprintf (file, "total complexity = %llu MIPS\n", celt_mips);} while (0); + +#endif diff --git a/code/opus-1.0.2/celt/fixed_generic.h b/code/opus-1.0.2/celt/fixed_generic.h new file mode 100644 index 00000000..71e28d62 --- /dev/null +++ b/code/opus-1.0.2/celt/fixed_generic.h @@ -0,0 +1,129 @@ +/* Copyright (C) 2007-2009 Xiph.Org Foundation + Copyright (C) 2003-2008 Jean-Marc Valin + Copyright (C) 2007-2008 CSIRO */ +/** + @file fixed_generic.h + @brief Generic fixed-point operations +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (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 FIXED_GENERIC_H +#define FIXED_GENERIC_H + +/** Multiply a 16-bit signed value by a 16-bit unsigned value. The result is a 32-bit signed value */ +#define MULT16_16SU(a,b) ((opus_val32)(opus_val16)(a)*(opus_val32)(opus_uint16)(b)) + +/** 16x32 multiplication, followed by a 16-bit shift right. Results fits in 32 bits */ +#define MULT16_32_Q16(a,b) ADD32(MULT16_16((a),SHR((b),16)), SHR(MULT16_16SU((a),((b)&0x0000ffff)),16)) + +/** 16x32 multiplication, followed by a 16-bit shift right (round-to-nearest). Results fits in 32 bits */ +#define MULT16_32_P16(a,b) ADD32(MULT16_16((a),SHR((b),16)), PSHR(MULT16_16((a),((b)&0x0000ffff)),16)) + +/** 16x32 multiplication, followed by a 15-bit shift right. Results fits in 32 bits */ +#define MULT16_32_Q15(a,b) ADD32(SHL(MULT16_16((a),SHR((b),16)),1), SHR(MULT16_16SU((a),((b)&0x0000ffff)),15)) + +/** 32x32 multiplication, followed by a 31-bit shift right. Results fits in 32 bits */ +#define MULT32_32_Q31(a,b) ADD32(ADD32(SHL(MULT16_16(SHR((a),16),SHR((b),16)),1), SHR(MULT16_16SU(SHR((a),16),((b)&0x0000ffff)),15)), SHR(MULT16_16SU(SHR((b),16),((a)&0x0000ffff)),15)) + +/** Compile-time conversion of float constant to 16-bit value */ +#define QCONST16(x,bits) ((opus_val16)(.5+(x)*(((opus_val32)1)<<(bits)))) + +/** Compile-time conversion of float constant to 32-bit value */ +#define QCONST32(x,bits) ((opus_val32)(.5+(x)*(((opus_val32)1)<<(bits)))) + +/** Negate a 16-bit value */ +#define NEG16(x) (-(x)) +/** Negate a 32-bit value */ +#define NEG32(x) (-(x)) + +/** Change a 32-bit value into a 16-bit value. The value is assumed to fit in 16-bit, otherwise the result is undefined */ +#define EXTRACT16(x) ((opus_val16)(x)) +/** Change a 16-bit value into a 32-bit value */ +#define EXTEND32(x) ((opus_val32)(x)) + +/** Arithmetic shift-right of a 16-bit value */ +#define SHR16(a,shift) ((a) >> (shift)) +/** Arithmetic shift-left of a 16-bit value */ +#define SHL16(a,shift) ((opus_int16)((opus_uint16)(a)<<(shift))) +/** Arithmetic shift-right of a 32-bit value */ +#define SHR32(a,shift) ((a) >> (shift)) +/** Arithmetic shift-left of a 32-bit value */ +#define SHL32(a,shift) ((opus_int32)((opus_uint32)(a)<<(shift))) + +/** 32-bit arithmetic shift right with rounding-to-nearest instead of rounding down */ +#define PSHR32(a,shift) (SHR32((a)+((EXTEND32(1)<<((shift))>>1)),shift)) +/** 32-bit arithmetic shift right where the argument can be negative */ +#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift))) + +/** "RAW" macros, should not be used outside of this header file */ +#define SHR(a,shift) ((a) >> (shift)) +#define SHL(a,shift) SHL32(a,shift) +#define PSHR(a,shift) (SHR((a)+((EXTEND32(1)<<((shift))>>1)),shift)) +#define SATURATE(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) + +/** Shift by a and round-to-neareast 32-bit value. Result is a 16-bit value */ +#define ROUND16(x,a) (EXTRACT16(PSHR32((x),(a)))) +/** Divide by two */ +#define HALF16(x) (SHR16(x,1)) +#define HALF32(x) (SHR32(x,1)) + +/** Add two 16-bit values */ +#define ADD16(a,b) ((opus_val16)((opus_val16)(a)+(opus_val16)(b))) +/** Subtract two 16-bit values */ +#define SUB16(a,b) ((opus_val16)(a)-(opus_val16)(b)) +/** Add two 32-bit values */ +#define ADD32(a,b) ((opus_val32)(a)+(opus_val32)(b)) +/** Subtract two 32-bit values */ +#define SUB32(a,b) ((opus_val32)(a)-(opus_val32)(b)) + +/** 16x16 multiplication where the result fits in 16 bits */ +#define MULT16_16_16(a,b) ((((opus_val16)(a))*((opus_val16)(b)))) + +/* (opus_val32)(opus_val16) gives TI compiler a hint that it's 16x16->32 multiply */ +/** 16x16 multiplication where the result fits in 32 bits */ +#define MULT16_16(a,b) (((opus_val32)(opus_val16)(a))*((opus_val32)(opus_val16)(b))) + +/** 16x16 multiply-add where the result fits in 32 bits */ +#define MAC16_16(c,a,b) (ADD32((c),MULT16_16((a),(b)))) +/** 16x32 multiply-add, followed by a 15-bit shift right. Results fits in 32 bits */ +#define MAC16_32_Q15(c,a,b) ADD32(c,ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15))) + +#define MULT16_16_Q11_32(a,b) (SHR(MULT16_16((a),(b)),11)) +#define MULT16_16_Q13(a,b) (SHR(MULT16_16((a),(b)),13)) +#define MULT16_16_Q14(a,b) (SHR(MULT16_16((a),(b)),14)) +#define MULT16_16_Q15(a,b) (SHR(MULT16_16((a),(b)),15)) + +#define MULT16_16_P13(a,b) (SHR(ADD32(4096,MULT16_16((a),(b))),13)) +#define MULT16_16_P14(a,b) (SHR(ADD32(8192,MULT16_16((a),(b))),14)) +#define MULT16_16_P15(a,b) (SHR(ADD32(16384,MULT16_16((a),(b))),15)) + +/** Divide a 32-bit value by a 16-bit value. Result fits in 16 bits */ +#define DIV32_16(a,b) ((opus_val16)(((opus_val32)(a))/((opus_val16)(b)))) + +/** Divide a 32-bit value by a 32-bit value. Result fits in 32 bits */ +#define DIV32(a,b) (((opus_val32)(a))/((opus_val32)(b))) + +#endif diff --git a/code/opus-1.0.2/celt/float_cast.h b/code/opus-1.0.2/celt/float_cast.h new file mode 100644 index 00000000..5ded2915 --- /dev/null +++ b/code/opus-1.0.2/celt/float_cast.h @@ -0,0 +1,140 @@ +/* Copyright (C) 2001 Erik de Castro Lopo */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* Version 1.1 */ + +#ifndef FLOAT_CAST_H +#define FLOAT_CAST_H + + +#include "arch.h" + +/*============================================================================ +** On Intel Pentium processors (especially PIII and probably P4), converting +** from float to int is very slow. To meet the C specs, the code produced by +** most C compilers targeting Pentium needs to change the FPU rounding mode +** before the float to int conversion is performed. +** +** Changing the FPU rounding mode causes the FPU pipeline to be flushed. It +** is this flushing of the pipeline which is so slow. +** +** Fortunately the ISO C99 specifications define the functions lrint, lrintf, +** llrint and llrintf which fix this problem as a side effect. +** +** On Unix-like systems, the configure process should have detected the +** presence of these functions. If they weren't found we have to replace them +** here with a standard C cast. +*/ + +/* +** The C99 prototypes for lrint and lrintf are as follows: +** +** long int lrintf (float x) ; +** long int lrint (double x) ; +*/ + +/* The presence of the required functions are detected during the configure +** process and the values HAVE_LRINT and HAVE_LRINTF are set accordingly in +** the config.h file. +*/ + +#if (HAVE_LRINTF) + +/* These defines enable functionality introduced with the 1999 ISO C +** standard. They must be defined before the inclusion of math.h to +** engage them. If optimisation is enabled, these functions will be +** inlined. With optimisation switched off, you have to link in the +** maths library using -lm. +*/ + +#define _ISOC9X_SOURCE 1 +#define _ISOC99_SOURCE 1 + +#define __USE_ISOC9X 1 +#define __USE_ISOC99 1 + +#include +#define float2int(x) lrintf(x) + +#elif (defined(HAVE_LRINT)) + +#define _ISOC9X_SOURCE 1 +#define _ISOC99_SOURCE 1 + +#define __USE_ISOC9X 1 +#define __USE_ISOC99 1 + +#include +#define float2int(x) lrint(x) + +#elif (defined(_MSC_VER) && _MSC_VER >= 1400) && (defined (WIN64) || defined (_WIN64)) + #include + + __inline long int float2int(float value) + { + return _mm_cvtss_si32(_mm_load_ss(&value)); + } +#elif (defined(_MSC_VER) && _MSC_VER >= 1400) && (defined (WIN32) || defined (_WIN32)) + #include + + /* Win32 doesn't seem to have these functions. + ** Therefore implement inline versions of these functions here. + */ + + __inline long int + float2int (float flt) + { int intgr; + + _asm + { fld flt + fistp intgr + } ; + + return intgr ; + } + +#else + +#if (defined(__GNUC__) && defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) + /* supported by gcc in C99 mode, but not by all other compilers */ + #warning "Don't have the functions lrint() and lrintf ()." + #warning "Replacing these functions with a standard C cast." +#endif /* __STDC_VERSION__ >= 199901L */ + #include + #define float2int(flt) ((int)(floor(.5+flt))) +#endif + +#ifndef DISABLE_FLOAT_API +static inline opus_int16 FLOAT2INT16(float x) +{ + x = x*CELT_SIG_SCALE; + x = MAX32(x, -32768); + x = MIN32(x, 32767); + return (opus_int16)float2int(x); +} +#endif /* DISABLE_FLOAT_API */ + +#endif /* FLOAT_CAST_H */ diff --git a/code/opus-1.0.2/celt/kiss_fft.c b/code/opus-1.0.2/celt/kiss_fft.c new file mode 100644 index 00000000..dcd69686 --- /dev/null +++ b/code/opus-1.0.2/celt/kiss_fft.c @@ -0,0 +1,722 @@ +/*Copyright (c) 2003-2004, Mark Borgerding + Lots of modifications by Jean-Marc Valin + Copyright (c) 2005-2007, Xiph.Org Foundation + Copyright (c) 2008, Xiph.Org Foundation, CSIRO + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (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 code is originally from Mark Borgerding's KISS-FFT but has been + heavily modified to better suit Opus */ + +#ifndef SKIP_CONFIG_H +# ifdef HAVE_CONFIG_H +# include "config.h" +# endif +#endif + +#include "_kiss_fft_guts.h" +#include "arch.h" +#include "os_support.h" +#include "mathops.h" +#include "stack_alloc.h" +#include "os_support.h" + +/* The guts header contains all the multiplication and addition macros that are defined for + complex numbers. It also delares the kf_ internal functions. +*/ + +static void kf_bfly2( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_state *st, + int m, + int N, + int mm + ) +{ + kiss_fft_cpx * Fout2; + const kiss_twiddle_cpx * tw1; + int i,j; + kiss_fft_cpx * Fout_beg = Fout; + for (i=0;itwiddles; + for(j=0;jr = SHR32(Fout->r, 1);Fout->i = SHR32(Fout->i, 1); + Fout2->r = SHR32(Fout2->r, 1);Fout2->i = SHR32(Fout2->i, 1); + C_MUL (t, *Fout2 , *tw1); + tw1 += fstride; + C_SUB( *Fout2 , *Fout , t ); + C_ADDTO( *Fout , t ); + ++Fout2; + ++Fout; + } + } +} + +static void ki_bfly2( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_state *st, + int m, + int N, + int mm + ) +{ + kiss_fft_cpx * Fout2; + const kiss_twiddle_cpx * tw1; + kiss_fft_cpx t; + int i,j; + kiss_fft_cpx * Fout_beg = Fout; + for (i=0;itwiddles; + for(j=0;jtwiddles; + for (j=0;jr = PSHR32(Fout->r, 2); + Fout->i = PSHR32(Fout->i, 2); + C_SUB( scratch[5] , *Fout, scratch[1] ); + C_ADDTO(*Fout, scratch[1]); + C_ADD( scratch[3] , scratch[0] , scratch[2] ); + C_SUB( scratch[4] , scratch[0] , scratch[2] ); + Fout[m2].r = PSHR32(Fout[m2].r, 2); + Fout[m2].i = PSHR32(Fout[m2].i, 2); + C_SUB( Fout[m2], *Fout, scratch[3] ); + tw1 += fstride; + tw2 += fstride*2; + tw3 += fstride*3; + C_ADDTO( *Fout , scratch[3] ); + + Fout[m].r = scratch[5].r + scratch[4].i; + Fout[m].i = scratch[5].i - scratch[4].r; + Fout[m3].r = scratch[5].r - scratch[4].i; + Fout[m3].i = scratch[5].i + scratch[4].r; + ++Fout; + } + } +} + +static void ki_bfly4( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_state *st, + int m, + int N, + int mm + ) +{ + const kiss_twiddle_cpx *tw1,*tw2,*tw3; + kiss_fft_cpx scratch[6]; + const size_t m2=2*m; + const size_t m3=3*m; + int i, j; + + kiss_fft_cpx * Fout_beg = Fout; + for (i=0;itwiddles; + for (j=0;jtwiddles[fstride*m]; + for (i=0;itwiddles; + k=m; + do { + C_FIXDIV(*Fout,3); C_FIXDIV(Fout[m],3); C_FIXDIV(Fout[m2],3); + + C_MUL(scratch[1],Fout[m] , *tw1); + C_MUL(scratch[2],Fout[m2] , *tw2); + + C_ADD(scratch[3],scratch[1],scratch[2]); + C_SUB(scratch[0],scratch[1],scratch[2]); + tw1 += fstride; + tw2 += fstride*2; + + Fout[m].r = Fout->r - HALF_OF(scratch[3].r); + Fout[m].i = Fout->i - HALF_OF(scratch[3].i); + + C_MULBYSCALAR( scratch[0] , epi3.i ); + + C_ADDTO(*Fout,scratch[3]); + + Fout[m2].r = Fout[m].r + scratch[0].i; + Fout[m2].i = Fout[m].i - scratch[0].r; + + Fout[m].r -= scratch[0].i; + Fout[m].i += scratch[0].r; + + ++Fout; + } while(--k); + } +} + +static void ki_bfly3( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_state *st, + int m, + int N, + int mm + ) +{ + int i, k; + const size_t m2 = 2*m; + const kiss_twiddle_cpx *tw1,*tw2; + kiss_fft_cpx scratch[5]; + kiss_twiddle_cpx epi3; + + kiss_fft_cpx * Fout_beg = Fout; + epi3 = st->twiddles[fstride*m]; + for (i=0;itwiddles; + k=m; + do{ + + C_MULC(scratch[1],Fout[m] , *tw1); + C_MULC(scratch[2],Fout[m2] , *tw2); + + C_ADD(scratch[3],scratch[1],scratch[2]); + C_SUB(scratch[0],scratch[1],scratch[2]); + tw1 += fstride; + tw2 += fstride*2; + + Fout[m].r = Fout->r - HALF_OF(scratch[3].r); + Fout[m].i = Fout->i - HALF_OF(scratch[3].i); + + C_MULBYSCALAR( scratch[0] , -epi3.i ); + + C_ADDTO(*Fout,scratch[3]); + + Fout[m2].r = Fout[m].r + scratch[0].i; + Fout[m2].i = Fout[m].i - scratch[0].r; + + Fout[m].r -= scratch[0].i; + Fout[m].i += scratch[0].r; + + ++Fout; + }while(--k); + } +} + +static void kf_bfly5( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_state *st, + int m, + int N, + int mm + ) +{ + kiss_fft_cpx *Fout0,*Fout1,*Fout2,*Fout3,*Fout4; + int i, u; + kiss_fft_cpx scratch[13]; + const kiss_twiddle_cpx * twiddles = st->twiddles; + const kiss_twiddle_cpx *tw; + kiss_twiddle_cpx ya,yb; + kiss_fft_cpx * Fout_beg = Fout; + + ya = twiddles[fstride*m]; + yb = twiddles[fstride*2*m]; + tw=st->twiddles; + + for (i=0;ir += scratch[7].r + scratch[8].r; + Fout0->i += scratch[7].i + scratch[8].i; + + scratch[5].r = scratch[0].r + S_MUL(scratch[7].r,ya.r) + S_MUL(scratch[8].r,yb.r); + scratch[5].i = scratch[0].i + S_MUL(scratch[7].i,ya.r) + S_MUL(scratch[8].i,yb.r); + + scratch[6].r = S_MUL(scratch[10].i,ya.i) + S_MUL(scratch[9].i,yb.i); + scratch[6].i = -S_MUL(scratch[10].r,ya.i) - S_MUL(scratch[9].r,yb.i); + + C_SUB(*Fout1,scratch[5],scratch[6]); + C_ADD(*Fout4,scratch[5],scratch[6]); + + scratch[11].r = scratch[0].r + S_MUL(scratch[7].r,yb.r) + S_MUL(scratch[8].r,ya.r); + scratch[11].i = scratch[0].i + S_MUL(scratch[7].i,yb.r) + S_MUL(scratch[8].i,ya.r); + scratch[12].r = - S_MUL(scratch[10].i,yb.i) + S_MUL(scratch[9].i,ya.i); + scratch[12].i = S_MUL(scratch[10].r,yb.i) - S_MUL(scratch[9].r,ya.i); + + C_ADD(*Fout2,scratch[11],scratch[12]); + C_SUB(*Fout3,scratch[11],scratch[12]); + + ++Fout0;++Fout1;++Fout2;++Fout3;++Fout4; + } + } +} + +static void ki_bfly5( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_state *st, + int m, + int N, + int mm + ) +{ + kiss_fft_cpx *Fout0,*Fout1,*Fout2,*Fout3,*Fout4; + int i, u; + kiss_fft_cpx scratch[13]; + const kiss_twiddle_cpx * twiddles = st->twiddles; + const kiss_twiddle_cpx *tw; + kiss_twiddle_cpx ya,yb; + kiss_fft_cpx * Fout_beg = Fout; + + ya = twiddles[fstride*m]; + yb = twiddles[fstride*2*m]; + tw=st->twiddles; + + for (i=0;ir += scratch[7].r + scratch[8].r; + Fout0->i += scratch[7].i + scratch[8].i; + + scratch[5].r = scratch[0].r + S_MUL(scratch[7].r,ya.r) + S_MUL(scratch[8].r,yb.r); + scratch[5].i = scratch[0].i + S_MUL(scratch[7].i,ya.r) + S_MUL(scratch[8].i,yb.r); + + scratch[6].r = -S_MUL(scratch[10].i,ya.i) - S_MUL(scratch[9].i,yb.i); + scratch[6].i = S_MUL(scratch[10].r,ya.i) + S_MUL(scratch[9].r,yb.i); + + C_SUB(*Fout1,scratch[5],scratch[6]); + C_ADD(*Fout4,scratch[5],scratch[6]); + + scratch[11].r = scratch[0].r + S_MUL(scratch[7].r,yb.r) + S_MUL(scratch[8].r,ya.r); + scratch[11].i = scratch[0].i + S_MUL(scratch[7].i,yb.r) + S_MUL(scratch[8].i,ya.r); + scratch[12].r = S_MUL(scratch[10].i,yb.i) - S_MUL(scratch[9].i,ya.i); + scratch[12].i = -S_MUL(scratch[10].r,yb.i) + S_MUL(scratch[9].r,ya.i); + + C_ADD(*Fout2,scratch[11],scratch[12]); + C_SUB(*Fout3,scratch[11],scratch[12]); + + ++Fout0;++Fout1;++Fout2;++Fout3;++Fout4; + } + } +} + +#endif + + +#ifdef CUSTOM_MODES + +static +void compute_bitrev_table( + int Fout, + opus_int16 *f, + const size_t fstride, + int in_stride, + opus_int16 * factors, + const kiss_fft_state *st + ) +{ + const int p=*factors++; /* the radix */ + const int m=*factors++; /* stage's fft length/p */ + + /*printf ("fft %d %d %d %d %d %d\n", p*m, m, p, s2, fstride*in_stride, N);*/ + if (m==1) + { + int j; + for (j=0;j32000 || (opus_int32)p*(opus_int32)p > n) + p = n; /* no more factors, skip to end */ + } + n /= p; +#ifdef RADIX_TWO_ONLY + if (p!=2 && p != 4) +#else + if (p>5) +#endif + { + return 0; + } + *facbuf++ = p; + *facbuf++ = n; + } while (n > 1); + return 1; +} + +static void compute_twiddles(kiss_twiddle_cpx *twiddles, int nfft) +{ + int i; +#ifdef FIXED_POINT + for (i=0;i= memneeded) + st = (kiss_fft_state*)mem; + *lenmem = memneeded; + } + if (st) { + opus_int16 *bitrev; + kiss_twiddle_cpx *twiddles; + + st->nfft=nfft; +#ifndef FIXED_POINT + st->scale = 1.f/nfft; +#endif + if (base != NULL) + { + st->twiddles = base->twiddles; + st->shift = 0; + while (nfft<shift != base->nfft && st->shift < 32) + st->shift++; + if (st->shift>=32) + goto fail; + } else { + st->twiddles = twiddles = (kiss_twiddle_cpx*)KISS_FFT_MALLOC(sizeof(kiss_twiddle_cpx)*nfft); + compute_twiddles(twiddles, nfft); + st->shift = -1; + } + if (!kf_factor(nfft,st->factors)) + { + goto fail; + } + + /* bitrev */ + st->bitrev = bitrev = (opus_int16*)KISS_FFT_MALLOC(sizeof(opus_int16)*nfft); + if (st->bitrev==NULL) + goto fail; + compute_bitrev_table(0, bitrev, 1,1, st->factors,st); + } + return st; +fail: + opus_fft_free(st); + return NULL; +} + +kiss_fft_state *opus_fft_alloc(int nfft,void * mem,size_t * lenmem ) +{ + return opus_fft_alloc_twiddles(nfft, mem, lenmem, NULL); +} + +void opus_fft_free(const kiss_fft_state *cfg) +{ + if (cfg) + { + opus_free((opus_int16*)cfg->bitrev); + if (cfg->shift < 0) + opus_free((kiss_twiddle_cpx*)cfg->twiddles); + opus_free((kiss_fft_state*)cfg); + } +} + +#endif /* CUSTOM_MODES */ + +void opus_fft(const kiss_fft_state *st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout) +{ + int m2, m; + int p; + int L; + int fstride[MAXFACTORS]; + int i; + int shift; + + /* st->shift can be -1 */ + shift = st->shift>0 ? st->shift : 0; + + celt_assert2 (fin != fout, "In-place FFT not supported"); + /* Bit-reverse the input */ + for (i=0;infft;i++) + { + fout[st->bitrev[i]] = fin[i]; +#ifndef FIXED_POINT + fout[st->bitrev[i]].r *= st->scale; + fout[st->bitrev[i]].i *= st->scale; +#endif + } + + fstride[0] = 1; + L=0; + do { + p = st->factors[2*L]; + m = st->factors[2*L+1]; + fstride[L+1] = fstride[L]*p; + L++; + } while(m!=1); + m = st->factors[2*L-1]; + for (i=L-1;i>=0;i--) + { + if (i!=0) + m2 = st->factors[2*i-1]; + else + m2 = 1; + switch (st->factors[2*i]) + { + case 2: + kf_bfly2(fout,fstride[i]<shift can be -1 */ + shift = st->shift>0 ? st->shift : 0; + celt_assert2 (fin != fout, "In-place FFT not supported"); + /* Bit-reverse the input */ + for (i=0;infft;i++) + fout[st->bitrev[i]] = fin[i]; + + fstride[0] = 1; + L=0; + do { + p = st->factors[2*L]; + m = st->factors[2*L+1]; + fstride[L+1] = fstride[L]*p; + L++; + } while(m!=1); + m = st->factors[2*L-1]; + for (i=L-1;i>=0;i--) + { + if (i!=0) + m2 = st->factors[2*i-1]; + else + m2 = 1; + switch (st->factors[2*i]) + { + case 2: + ki_bfly2(fout,fstride[i]< +#include +#include "arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef USE_SIMD +# include +# define kiss_fft_scalar __m128 +#define KISS_FFT_MALLOC(nbytes) memalign(16,nbytes) +#else +#define KISS_FFT_MALLOC opus_alloc +#endif + +#ifdef FIXED_POINT +#include "arch.h" + +# define kiss_fft_scalar opus_int32 +# define kiss_twiddle_scalar opus_int16 + + +#else +# ifndef kiss_fft_scalar +/* default is float */ +# define kiss_fft_scalar float +# define kiss_twiddle_scalar float +# define KF_SUFFIX _celt_single +# endif +#endif + +typedef struct { + kiss_fft_scalar r; + kiss_fft_scalar i; +}kiss_fft_cpx; + +typedef struct { + kiss_twiddle_scalar r; + kiss_twiddle_scalar i; +}kiss_twiddle_cpx; + +#define MAXFACTORS 8 +/* e.g. an fft of length 128 has 4 factors + as far as kissfft is concerned + 4*4*4*2 + */ + +typedef struct kiss_fft_state{ + int nfft; +#ifndef FIXED_POINT + kiss_fft_scalar scale; +#endif + int shift; + opus_int16 factors[2*MAXFACTORS]; + const opus_int16 *bitrev; + const kiss_twiddle_cpx *twiddles; +} kiss_fft_state; + +/*typedef struct kiss_fft_state* kiss_fft_cfg;*/ + +/** + * opus_fft_alloc + * + * Initialize a FFT (or IFFT) algorithm's cfg/state buffer. + * + * typical usage: kiss_fft_cfg mycfg=opus_fft_alloc(1024,0,NULL,NULL); + * + * The return value from fft_alloc is a cfg buffer used internally + * by the fft routine or NULL. + * + * If lenmem is NULL, then opus_fft_alloc will allocate a cfg buffer using malloc. + * The returned value should be free()d when done to avoid memory leaks. + * + * The state can be placed in a user supplied buffer 'mem': + * If lenmem is not NULL and mem is not NULL and *lenmem is large enough, + * then the function places the cfg in mem and the size used in *lenmem + * and returns mem. + * + * If lenmem is not NULL and ( mem is NULL or *lenmem is not large enough), + * then the function returns NULL and places the minimum cfg + * buffer size in *lenmem. + * */ + +kiss_fft_state *opus_fft_alloc_twiddles(int nfft,void * mem,size_t * lenmem, const kiss_fft_state *base); + +kiss_fft_state *opus_fft_alloc(int nfft,void * mem,size_t * lenmem); + +/** + * opus_fft(cfg,in_out_buf) + * + * Perform an FFT on a complex input buffer. + * for a forward FFT, + * fin should be f[0] , f[1] , ... ,f[nfft-1] + * fout will be F[0] , F[1] , ... ,F[nfft-1] + * Note that each element is complex and can be accessed like + f[k].r and f[k].i + * */ +void opus_fft(const kiss_fft_state *cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout); +void opus_ifft(const kiss_fft_state *cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout); + +void opus_fft_free(const kiss_fft_state *cfg); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/code/opus-1.0.2/celt/laplace.c b/code/opus-1.0.2/celt/laplace.c new file mode 100644 index 00000000..a7bca874 --- /dev/null +++ b/code/opus-1.0.2/celt/laplace.c @@ -0,0 +1,134 @@ +/* Copyright (c) 2007 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "laplace.h" +#include "mathops.h" + +/* The minimum probability of an energy delta (out of 32768). */ +#define LAPLACE_LOG_MINP (0) +#define LAPLACE_MINP (1<>15; +} + +void ec_laplace_encode(ec_enc *enc, int *value, unsigned fs, int decay) +{ + unsigned fl; + int val = *value; + fl = 0; + if (val) + { + int s; + int i; + s = -(val<0); + val = (val+s)^s; + fl = fs; + fs = ec_laplace_get_freq1(fs, decay); + /* Search the decaying part of the PDF.*/ + for (i=1; fs > 0 && i < val; i++) + { + fs *= 2; + fl += fs+2*LAPLACE_MINP; + fs = (fs*(opus_int32)decay)>>15; + } + /* Everything beyond that has probability LAPLACE_MINP. */ + if (!fs) + { + int di; + int ndi_max; + ndi_max = (32768-fl+LAPLACE_MINP-1)>>LAPLACE_LOG_MINP; + ndi_max = (ndi_max-s)>>1; + di = IMIN(val - i, ndi_max - 1); + fl += (2*di+1+s)*LAPLACE_MINP; + fs = IMIN(LAPLACE_MINP, 32768-fl); + *value = (i+di+s)^s; + } + else + { + fs += LAPLACE_MINP; + fl += fs&~s; + } + celt_assert(fl+fs<=32768); + celt_assert(fs>0); + } + ec_encode_bin(enc, fl, fl+fs, 15); +} + +int ec_laplace_decode(ec_dec *dec, unsigned fs, int decay) +{ + int val=0; + unsigned fl; + unsigned fm; + fm = ec_decode_bin(dec, 15); + fl = 0; + if (fm >= fs) + { + val++; + fl = fs; + fs = ec_laplace_get_freq1(fs, decay)+LAPLACE_MINP; + /* Search the decaying part of the PDF.*/ + while(fs > LAPLACE_MINP && fm >= fl+2*fs) + { + fs *= 2; + fl += fs; + fs = ((fs-2*LAPLACE_MINP)*(opus_int32)decay)>>15; + fs += LAPLACE_MINP; + val++; + } + /* Everything beyond that has probability LAPLACE_MINP. */ + if (fs <= LAPLACE_MINP) + { + int di; + di = (fm-fl)>>(LAPLACE_LOG_MINP+1); + val += di; + fl += 2*di*LAPLACE_MINP; + } + if (fm < fl+fs) + val = -val; + else + fl += fs; + } + celt_assert(fl<32768); + celt_assert(fs>0); + celt_assert(fl<=fm); + celt_assert(fm>1; + b=1U<>=1; + bshift--; + } + while(bshift>=0); + return g; +} + +#ifdef FIXED_POINT + +opus_val32 frac_div32(opus_val32 a, opus_val32 b) +{ + opus_val16 rcp; + opus_val32 result, rem; + int shift = celt_ilog2(b)-29; + a = VSHR32(a,shift); + b = VSHR32(b,shift); + /* 16-bit reciprocal */ + rcp = ROUND16(celt_rcp(ROUND16(b,16)),3); + result = MULT16_32_Q15(rcp, a); + rem = PSHR32(a,2)-MULT32_32_Q31(result, b); + result = ADD32(result, SHL32(MULT16_32_Q15(rcp, rem),2)); + if (result >= 536870912) /* 2^29 */ + return 2147483647; /* 2^31 - 1 */ + else if (result <= -536870912) /* -2^29 */ + return -2147483647; /* -2^31 */ + else + return SHL32(result, 2); +} + +/** Reciprocal sqrt approximation in the range [0.25,1) (Q16 in, Q14 out) */ +opus_val16 celt_rsqrt_norm(opus_val32 x) +{ + opus_val16 n; + opus_val16 r; + opus_val16 r2; + opus_val16 y; + /* Range of n is [-16384,32767] ([-0.5,1) in Q15). */ + n = x-32768; + /* Get a rough initial guess for the root. + The optimal minimax quadratic approximation (using relative error) is + r = 1.437799046117536+n*(-0.823394375837328+n*0.4096419668459485). + Coefficients here, and the final result r, are Q14.*/ + r = ADD16(23557, MULT16_16_Q15(n, ADD16(-13490, MULT16_16_Q15(n, 6713)))); + /* We want y = x*r*r-1 in Q15, but x is 32-bit Q16 and r is Q14. + We can compute the result from n and r using Q15 multiplies with some + adjustment, carefully done to avoid overflow. + Range of y is [-1564,1594]. */ + r2 = MULT16_16_Q15(r, r); + y = SHL16(SUB16(ADD16(MULT16_16_Q15(r2, n), r2), 16384), 1); + /* Apply a 2nd-order Householder iteration: r += r*y*(y*0.375-0.5). + This yields the Q14 reciprocal square root of the Q16 x, with a maximum + relative error of 1.04956E-4, a (relative) RMSE of 2.80979E-5, and a + peak absolute error of 2.26591/16384. */ + return ADD16(r, MULT16_16_Q15(r, MULT16_16_Q15(y, + SUB16(MULT16_16_Q15(y, 12288), 16384)))); +} + +/** Sqrt approximation (QX input, QX/2 output) */ +opus_val32 celt_sqrt(opus_val32 x) +{ + int k; + opus_val16 n; + opus_val32 rt; + static const opus_val16 C[5] = {23175, 11561, -3011, 1699, -664}; + if (x==0) + return 0; + k = (celt_ilog2(x)>>1)-7; + x = VSHR32(x, 2*k); + n = x-32768; + rt = ADD16(C[0], MULT16_16_Q15(n, ADD16(C[1], MULT16_16_Q15(n, ADD16(C[2], + MULT16_16_Q15(n, ADD16(C[3], MULT16_16_Q15(n, (C[4]))))))))); + rt = VSHR32(rt,7-k); + return rt; +} + +#define L1 32767 +#define L2 -7651 +#define L3 8277 +#define L4 -626 + +static inline opus_val16 _celt_cos_pi_2(opus_val16 x) +{ + opus_val16 x2; + + x2 = MULT16_16_P15(x,x); + return ADD16(1,MIN16(32766,ADD32(SUB16(L1,x2), MULT16_16_P15(x2, ADD32(L2, MULT16_16_P15(x2, ADD32(L3, MULT16_16_P15(L4, x2 + )))))))); +} + +#undef L1 +#undef L2 +#undef L3 +#undef L4 + +opus_val16 celt_cos_norm(opus_val32 x) +{ + x = x&0x0001ffff; + if (x>SHL32(EXTEND32(1), 16)) + x = SUB32(SHL32(EXTEND32(1), 17),x); + if (x&0x00007fff) + { + if (x0, "celt_rcp() only defined for positive values"); + i = celt_ilog2(x); + /* n is Q15 with range [0,1). */ + n = VSHR32(x,i-15)-32768; + /* Start with a linear approximation: + r = 1.8823529411764706-0.9411764705882353*n. + The coefficients and the result are Q14 in the range [15420,30840].*/ + r = ADD16(30840, MULT16_16_Q15(-15420, n)); + /* Perform two Newton iterations: + r -= r*((r*n)-1.Q15) + = r*((r*n)+(r-1.Q15)). */ + r = SUB16(r, MULT16_16_Q15(r, + ADD16(MULT16_16_Q15(r, n), ADD16(r, -32768)))); + /* We subtract an extra 1 in the second iteration to avoid overflow; it also + neatly compensates for truncation error in the rest of the process. */ + r = SUB16(r, ADD16(1, MULT16_16_Q15(r, + ADD16(MULT16_16_Q15(r, n), ADD16(r, -32768))))); + /* r is now the Q15 solution to 2/(n+1), with a maximum relative error + of 7.05346E-5, a (relative) RMSE of 2.14418E-5, and a peak absolute + error of 1.24665/32768. */ + return VSHR32(EXTEND32(r),i-16); +} + +#endif diff --git a/code/opus-1.0.2/celt/mathops.h b/code/opus-1.0.2/celt/mathops.h new file mode 100644 index 00000000..4e977956 --- /dev/null +++ b/code/opus-1.0.2/celt/mathops.h @@ -0,0 +1,237 @@ +/* Copyright (c) 2002-2008 Jean-Marc Valin + Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/** + @file mathops.h + @brief Various math functions +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (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 MATHOPS_H +#define MATHOPS_H + +#include "arch.h" +#include "entcode.h" +#include "os_support.h" + +/* Multiplies two 16-bit fractional values. Bit-exactness of this macro is important */ +#define FRAC_MUL16(a,b) ((16384+((opus_int32)(opus_int16)(a)*(opus_int16)(b)))>>15) + +unsigned isqrt32(opus_uint32 _val); + +#ifndef FIXED_POINT + +#define PI 3.141592653f +#define celt_sqrt(x) ((float)sqrt(x)) +#define celt_rsqrt(x) (1.f/celt_sqrt(x)) +#define celt_rsqrt_norm(x) (celt_rsqrt(x)) +#define celt_cos_norm(x) ((float)cos((.5f*PI)*(x))) +#define celt_rcp(x) (1.f/(x)) +#define celt_div(a,b) ((a)/(b)) +#define frac_div32(a,b) ((float)(a)/(b)) + +#ifdef FLOAT_APPROX + +/* Note: This assumes radix-2 floating point with the exponent at bits 23..30 and an offset of 127 + denorm, +/- inf and NaN are *not* handled */ + +/** Base-2 log approximation (log2(x)). */ +static inline float celt_log2(float x) +{ + int integer; + float frac; + union { + float f; + opus_uint32 i; + } in; + in.f = x; + integer = (in.i>>23)-127; + in.i -= integer<<23; + frac = in.f - 1.5f; + frac = -0.41445418f + frac*(0.95909232f + + frac*(-0.33951290f + frac*0.16541097f)); + return 1+integer+frac; +} + +/** Base-2 exponential approximation (2^x). */ +static inline float celt_exp2(float x) +{ + int integer; + float frac; + union { + float f; + opus_uint32 i; + } res; + integer = floor(x); + if (integer < -50) + return 0; + frac = x-integer; + /* K0 = 1, K1 = log(2), K2 = 3-4*log(2), K3 = 3*log(2) - 2 */ + res.f = 0.99992522f + frac * (0.69583354f + + frac * (0.22606716f + 0.078024523f*frac)); + res.i = (res.i + (integer<<23)) & 0x7fffffff; + return res.f; +} + +#else +#define celt_log2(x) ((float)(1.442695040888963387*log(x))) +#define celt_exp2(x) ((float)exp(0.6931471805599453094*(x))) +#endif + +#endif + +#ifdef FIXED_POINT + +#include "os_support.h" + +#ifndef OVERRIDE_CELT_ILOG2 +/** Integer log in base2. Undefined for zero and negative numbers */ +static inline opus_int16 celt_ilog2(opus_int32 x) +{ + celt_assert2(x>0, "celt_ilog2() only defined for strictly positive numbers"); + return EC_ILOG(x)-1; +} +#endif + +#ifndef OVERRIDE_CELT_MAXABS16 +static inline opus_val16 celt_maxabs16(opus_val16 *x, int len) +{ + int i; + opus_val16 maxval = 0; + for (i=0;i14) + return 0x7f000000; + else if (integer < -15) + return 0; + frac = SHL16(x-SHL16(integer,10),4); + frac = ADD16(D0, MULT16_16_Q15(frac, ADD16(D1, MULT16_16_Q15(frac, ADD16(D2 , MULT16_16_Q15(D3,frac)))))); + return VSHR32(EXTEND32(frac), -integer-2); +} + +opus_val32 celt_rcp(opus_val32 x); + +#define celt_div(a,b) MULT32_32_Q31((opus_val32)(a),celt_rcp(b)) + +opus_val32 frac_div32(opus_val32 a, opus_val32 b); + +#define M1 32767 +#define M2 -21 +#define M3 -11943 +#define M4 4936 + +/* Atan approximation using a 4th order polynomial. Input is in Q15 format + and normalized by pi/4. Output is in Q15 format */ +static inline opus_val16 celt_atan01(opus_val16 x) +{ + return MULT16_16_P15(x, ADD32(M1, MULT16_16_P15(x, ADD32(M2, MULT16_16_P15(x, ADD32(M3, MULT16_16_P15(M4, x))))))); +} + +#undef M1 +#undef M2 +#undef M3 +#undef M4 + +/* atan2() approximation valid for positive input values */ +static inline opus_val16 celt_atan2p(opus_val16 y, opus_val16 x) +{ + if (y < x) + { + opus_val32 arg; + arg = celt_div(SHL32(EXTEND32(y),15),x); + if (arg >= 32767) + arg = 32767; + return SHR16(celt_atan01(EXTRACT16(arg)),1); + } else { + opus_val32 arg; + arg = celt_div(SHL32(EXTEND32(x),15),y); + if (arg >= 32767) + arg = 32767; + return 25736-SHR16(celt_atan01(EXTRACT16(arg)),1); + } +} + +#endif /* FIXED_POINT */ +#endif /* MATHOPS_H */ diff --git a/code/opus-1.0.2/celt/mdct.c b/code/opus-1.0.2/celt/mdct.c new file mode 100644 index 00000000..16a36c69 --- /dev/null +++ b/code/opus-1.0.2/celt/mdct.c @@ -0,0 +1,332 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2008 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (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 is a simple MDCT implementation that uses a N/4 complex FFT + to do most of the work. It should be relatively straightforward to + plug in pretty much and FFT here. + + This replaces the Vorbis FFT (and uses the exact same API), which + was a bit too messy and that was ending up duplicating code + (might as well use the same FFT everywhere). + + The algorithm is similar to (and inspired from) Fabrice Bellard's + MDCT implementation in FFMPEG, but has differences in signs, ordering + and scaling in many places. +*/ + +#ifndef SKIP_CONFIG_H +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#endif + +#include "mdct.h" +#include "kiss_fft.h" +#include "_kiss_fft_guts.h" +#include +#include "os_support.h" +#include "mathops.h" +#include "stack_alloc.h" + +#ifdef CUSTOM_MODES + +int clt_mdct_init(mdct_lookup *l,int N, int maxshift) +{ + int i; + int N4; + kiss_twiddle_scalar *trig; +#if defined(FIXED_POINT) + int N2=N>>1; +#endif + l->n = N; + N4 = N>>2; + l->maxshift = maxshift; + for (i=0;i<=maxshift;i++) + { + if (i==0) + l->kfft[i] = opus_fft_alloc(N>>2>>i, 0, 0); + else + l->kfft[i] = opus_fft_alloc_twiddles(N>>2>>i, 0, 0, l->kfft[0]); +#ifndef ENABLE_TI_DSPLIB55 + if (l->kfft[i]==NULL) + return 0; +#endif + } + l->trig = trig = (kiss_twiddle_scalar*)opus_alloc((N4+1)*sizeof(kiss_twiddle_scalar)); + if (l->trig==NULL) + return 0; + /* We have enough points that sine isn't necessary */ +#if defined(FIXED_POINT) + for (i=0;i<=N4;i++) + trig[i] = TRIG_UPSCALE*celt_cos_norm(DIV32(ADD32(SHL32(EXTEND32(i),17),N2),N)); +#else + for (i=0;i<=N4;i++) + trig[i] = (kiss_twiddle_scalar)cos(2*PI*i/N); +#endif + return 1; +} + +void clt_mdct_clear(mdct_lookup *l) +{ + int i; + for (i=0;i<=l->maxshift;i++) + opus_fft_free(l->kfft[i]); + opus_free((kiss_twiddle_scalar*)l->trig); +} + +#endif /* CUSTOM_MODES */ + +/* Forward MDCT trashes the input array */ +void clt_mdct_forward(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 *window, int overlap, int shift, int stride) +{ + int i; + int N, N2, N4; + kiss_twiddle_scalar sine; + VARDECL(kiss_fft_scalar, f); + SAVE_STACK; + N = l->n; + N >>= shift; + N2 = N>>1; + N4 = N>>2; + ALLOC(f, N2, kiss_fft_scalar); + /* sin(x) ~= x here */ +#ifdef FIXED_POINT + sine = TRIG_UPSCALE*(QCONST16(0.7853981f, 15)+N2)/N; +#else + sine = (kiss_twiddle_scalar)2*PI*(.125f)/N; +#endif + + /* Consider the input to be composed of four blocks: [a, b, c, d] */ + /* Window, shuffle, fold */ + { + /* Temp pointers to make it really clear to the compiler what we're doing */ + const kiss_fft_scalar * OPUS_RESTRICT xp1 = in+(overlap>>1); + const kiss_fft_scalar * OPUS_RESTRICT xp2 = in+N2-1+(overlap>>1); + kiss_fft_scalar * OPUS_RESTRICT yp = f; + const opus_val16 * OPUS_RESTRICT wp1 = window+(overlap>>1); + const opus_val16 * OPUS_RESTRICT wp2 = window+(overlap>>1)-1; + for(i=0;i<(overlap>>2);i++) + { + /* Real part arranged as -d-cR, Imag part arranged as -b+aR*/ + *yp++ = MULT16_32_Q15(*wp2, xp1[N2]) + MULT16_32_Q15(*wp1,*xp2); + *yp++ = MULT16_32_Q15(*wp1, *xp1) - MULT16_32_Q15(*wp2, xp2[-N2]); + xp1+=2; + xp2-=2; + wp1+=2; + wp2-=2; + } + wp1 = window; + wp2 = window+overlap-1; + for(;i>2);i++) + { + /* Real part arranged as a-bR, Imag part arranged as -c-dR */ + *yp++ = *xp2; + *yp++ = *xp1; + xp1+=2; + xp2-=2; + } + for(;itrig[0]; + for(i=0;ikfft[shift], (kiss_fft_cpx *)f, (kiss_fft_cpx *)in); + + /* Post-rotate */ + { + /* Temp pointers to make it really clear to the compiler what we're doing */ + const kiss_fft_scalar * OPUS_RESTRICT fp = in; + kiss_fft_scalar * OPUS_RESTRICT yp1 = out; + kiss_fft_scalar * OPUS_RESTRICT yp2 = out+stride*(N2-1); + const kiss_twiddle_scalar *t = &l->trig[0]; + /* Temp pointers to make it really clear to the compiler what we're doing */ + for(i=0;in; + N >>= shift; + N2 = N>>1; + N4 = N>>2; + ALLOC(f, N2, kiss_fft_scalar); + ALLOC(f2, N2, kiss_fft_scalar); + /* sin(x) ~= x here */ +#ifdef FIXED_POINT + sine = TRIG_UPSCALE*(QCONST16(0.7853981f, 15)+N2)/N; +#else + sine = (kiss_twiddle_scalar)2*PI*(.125f)/N; +#endif + + /* Pre-rotate */ + { + /* Temp pointers to make it really clear to the compiler what we're doing */ + const kiss_fft_scalar * OPUS_RESTRICT xp1 = in; + const kiss_fft_scalar * OPUS_RESTRICT xp2 = in+stride*(N2-1); + kiss_fft_scalar * OPUS_RESTRICT yp = f2; + const kiss_twiddle_scalar *t = &l->trig[0]; + for(i=0;ikfft[shift], (kiss_fft_cpx *)f2, (kiss_fft_cpx *)f); + + /* Post-rotate */ + { + kiss_fft_scalar * OPUS_RESTRICT fp = f; + const kiss_twiddle_scalar *t = &l->trig[0]; + + for(i=0;i>1; + /* Mirror on both sides for TDAC */ + { + kiss_fft_scalar * OPUS_RESTRICT fp1 = f2+N4-1; + kiss_fft_scalar * OPUS_RESTRICT xp1 = out+N2-1; + kiss_fft_scalar * OPUS_RESTRICT yp1 = out+N4-overlap/2; + const opus_val16 * OPUS_RESTRICT wp1 = window; + const opus_val16 * OPUS_RESTRICT wp2 = window+overlap-1; + for(i = 0; i< N4-overlap/2; i++) + { + *xp1 = *fp1; + xp1--; + fp1--; + } + for(; i < N4; i++) + { + kiss_fft_scalar x1; + x1 = *fp1--; + *yp1++ +=-MULT16_32_Q15(*wp1, x1); + *xp1-- += MULT16_32_Q15(*wp2, x1); + wp1++; + wp2--; + } + } + { + kiss_fft_scalar * OPUS_RESTRICT fp2 = f2+N4; + kiss_fft_scalar * OPUS_RESTRICT xp2 = out+N2; + kiss_fft_scalar * OPUS_RESTRICT yp2 = out+N-1-(N4-overlap/2); + const opus_val16 * OPUS_RESTRICT wp1 = window; + const opus_val16 * OPUS_RESTRICT wp2 = window+overlap-1; + for(i = 0; i< N4-overlap/2; i++) + { + *xp2 = *fp2; + xp2++; + fp2++; + } + for(; i < N4; i++) + { + kiss_fft_scalar x2; + x2 = *fp2++; + *yp2-- = MULT16_32_Q15(*wp1, x2); + *xp2++ = MULT16_32_Q15(*wp2, x2); + wp1++; + wp2--; + } + } + RESTORE_STACK; +} diff --git a/code/opus-1.0.2/celt/mdct.h b/code/opus-1.0.2/celt/mdct.h new file mode 100644 index 00000000..d7218213 --- /dev/null +++ b/code/opus-1.0.2/celt/mdct.h @@ -0,0 +1,70 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2008 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (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 is a simple MDCT implementation that uses a N/4 complex FFT + to do most of the work. It should be relatively straightforward to + plug in pretty much and FFT here. + + This replaces the Vorbis FFT (and uses the exact same API), which + was a bit too messy and that was ending up duplicating code + (might as well use the same FFT everywhere). + + The algorithm is similar to (and inspired from) Fabrice Bellard's + MDCT implementation in FFMPEG, but has differences in signs, ordering + and scaling in many places. +*/ + +#ifndef MDCT_H +#define MDCT_H + +#include "opus_defines.h" +#include "kiss_fft.h" +#include "arch.h" + +typedef struct { + int n; + int maxshift; + const kiss_fft_state *kfft[4]; + const kiss_twiddle_scalar * OPUS_RESTRICT trig; +} mdct_lookup; + +int clt_mdct_init(mdct_lookup *l,int N, int maxshift); +void clt_mdct_clear(mdct_lookup *l); + +/** Compute a forward MDCT and scale by 4/N, trashes the input array */ +void clt_mdct_forward(const mdct_lookup *l, kiss_fft_scalar *in, + kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 *window, int overlap, int shift, int stride); + +/** Compute a backward MDCT (no scaling) and performs weighted overlap-add + (scales implicitly by 1/2) */ +void clt_mdct_backward(const mdct_lookup *l, kiss_fft_scalar *in, + kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 * OPUS_RESTRICT window, int overlap, int shift, int stride); + +#endif diff --git a/code/opus-1.0.2/celt/mfrngcod.h b/code/opus-1.0.2/celt/mfrngcod.h new file mode 100644 index 00000000..809152a5 --- /dev/null +++ b/code/opus-1.0.2/celt/mfrngcod.h @@ -0,0 +1,48 @@ +/* Copyright (c) 2001-2008 Timothy B. Terriberry + Copyright (c) 2008-2009 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#if !defined(_mfrngcode_H) +# define _mfrngcode_H (1) +# include "entcode.h" + +/*Constants used by the entropy encoder/decoder.*/ + +/*The number of bits to output at a time.*/ +# define EC_SYM_BITS (8) +/*The total number of bits in each of the state registers.*/ +# define EC_CODE_BITS (32) +/*The maximum symbol value.*/ +# define EC_SYM_MAX ((1U<>EC_SYM_BITS) +/*The number of bits available for the last, partial symbol in the code field.*/ +# define EC_CODE_EXTRA ((EC_CODE_BITS-2)%EC_SYM_BITS+1) +#endif diff --git a/code/opus-1.0.2/celt/modes.c b/code/opus-1.0.2/celt/modes.c new file mode 100644 index 00000000..ed204d7d --- /dev/null +++ b/code/opus-1.0.2/celt/modes.c @@ -0,0 +1,430 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2008 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "celt.h" +#include "modes.h" +#include "rate.h" +#include "os_support.h" +#include "stack_alloc.h" +#include "quant_bands.h" + +static const opus_int16 eband5ms[] = { +/*0 200 400 600 800 1k 1.2 1.4 1.6 2k 2.4 2.8 3.2 4k 4.8 5.6 6.8 8k 9.6 12k 15.6 */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 34, 40, 48, 60, 78, 100 +}; + +/* Alternate tuning (partially derived from Vorbis) */ +#define BITALLOC_SIZE 11 +/* Bit allocation table in units of 1/32 bit/sample (0.1875 dB SNR) */ +static const unsigned char band_allocation[] = { +/*0 200 400 600 800 1k 1.2 1.4 1.6 2k 2.4 2.8 3.2 4k 4.8 5.6 6.8 8k 9.6 12k 15.6 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 90, 80, 75, 69, 63, 56, 49, 40, 34, 29, 20, 18, 10, 0, 0, 0, 0, 0, 0, 0, 0, +110,100, 90, 84, 78, 71, 65, 58, 51, 45, 39, 32, 26, 20, 12, 0, 0, 0, 0, 0, 0, +118,110,103, 93, 86, 80, 75, 70, 65, 59, 53, 47, 40, 31, 23, 15, 4, 0, 0, 0, 0, +126,119,112,104, 95, 89, 83, 78, 72, 66, 60, 54, 47, 39, 32, 25, 17, 12, 1, 0, 0, +134,127,120,114,103, 97, 91, 85, 78, 72, 66, 60, 54, 47, 41, 35, 29, 23, 16, 10, 1, +144,137,130,124,113,107,101, 95, 88, 82, 76, 70, 64, 57, 51, 45, 39, 33, 26, 15, 1, +152,145,138,132,123,117,111,105, 98, 92, 86, 80, 74, 67, 61, 55, 49, 43, 36, 20, 1, +162,155,148,142,133,127,121,115,108,102, 96, 90, 84, 77, 71, 65, 59, 53, 46, 30, 1, +172,165,158,152,143,137,131,125,118,112,106,100, 94, 87, 81, 75, 69, 63, 56, 45, 20, +200,200,200,200,200,200,200,200,198,193,188,183,178,173,168,163,158,153,148,129,104, +}; + +#ifndef CUSTOM_MODES_ONLY + #ifdef FIXED_POINT + #include "static_modes_fixed.h" + #else + #include "static_modes_float.h" + #endif +#endif /* CUSTOM_MODES_ONLY */ + +#ifndef M_PI +#define M_PI 3.141592653 +#endif + +#ifdef CUSTOM_MODES + +/* Defining 25 critical bands for the full 0-20 kHz audio bandwidth + Taken from http://ccrma.stanford.edu/~jos/bbt/Bark_Frequency_Scale.html */ +#define BARK_BANDS 25 +static const opus_int16 bark_freq[BARK_BANDS+1] = { + 0, 100, 200, 300, 400, + 510, 630, 770, 920, 1080, + 1270, 1480, 1720, 2000, 2320, + 2700, 3150, 3700, 4400, 5300, + 6400, 7700, 9500, 12000, 15500, + 20000}; + +static opus_int16 *compute_ebands(opus_int32 Fs, int frame_size, int res, int *nbEBands) +{ + opus_int16 *eBands; + int i, j, lin, low, high, nBark, offset=0; + + /* All modes that have 2.5 ms short blocks use the same definition */ + if (Fs == 400*(opus_int32)frame_size) + { + *nbEBands = sizeof(eband5ms)/sizeof(eband5ms[0])-1; + eBands = opus_alloc(sizeof(opus_int16)*(*nbEBands+1)); + for (i=0;i<*nbEBands+1;i++) + eBands[i] = eband5ms[i]; + return eBands; + } + /* Find the number of critical bands supported by our sampling rate */ + for (nBark=1;nBark= Fs) + break; + + /* Find where the linear part ends (i.e. where the spacing is more than min_width */ + for (lin=0;lin= res) + break; + + low = (bark_freq[lin]+res/2)/res; + high = nBark-lin; + *nbEBands = low+high; + eBands = opus_alloc(sizeof(opus_int16)*(*nbEBands+2)); + + if (eBands==NULL) + return NULL; + + /* Linear spacing (min_width) */ + for (i=0;i0) + offset = eBands[low-1]*res - bark_freq[lin-1]; + /* Spacing follows critical bands */ + for (i=0;i frame_size) + eBands[*nbEBands] = frame_size; + for (i=1;i<*nbEBands-1;i++) + { + if (eBands[i+1]-eBands[i] < eBands[i]-eBands[i-1]) + { + eBands[i] -= (2*eBands[i]-eBands[i-1]-eBands[i+1])/2; + } + } + /* Remove any empty bands. */ + for (i=j=0;i<*nbEBands;i++) + if(eBands[i+1]>eBands[j]) + eBands[++j]=eBands[i+1]; + *nbEBands=j; + + for (i=1;i<*nbEBands;i++) + { + /* Every band must be smaller than the last band. */ + celt_assert(eBands[i]-eBands[i-1]<=eBands[*nbEBands]-eBands[*nbEBands-1]); + /* Each band must be no larger than twice the size of the previous one. */ + celt_assert(eBands[i+1]-eBands[i]<=2*(eBands[i]-eBands[i-1])); + } + + return eBands; +} + +static void compute_allocation_table(CELTMode *mode) +{ + int i, j; + unsigned char *allocVectors; + int maxBands = sizeof(eband5ms)/sizeof(eband5ms[0])-1; + + mode->nbAllocVectors = BITALLOC_SIZE; + allocVectors = opus_alloc(sizeof(unsigned char)*(BITALLOC_SIZE*mode->nbEBands)); + if (allocVectors==NULL) + return; + + /* Check for standard mode */ + if (mode->Fs == 400*(opus_int32)mode->shortMdctSize) + { + for (i=0;inbEBands;i++) + allocVectors[i] = band_allocation[i]; + mode->allocVectors = allocVectors; + return; + } + /* If not the standard mode, interpolate */ + /* Compute per-codec-band allocation from per-critical-band matrix */ + for (i=0;inbEBands;j++) + { + int k; + for (k=0;k mode->eBands[j]*(opus_int32)mode->Fs/mode->shortMdctSize) + break; + } + if (k>maxBands-1) + allocVectors[i*mode->nbEBands+j] = band_allocation[i*maxBands + maxBands-1]; + else { + opus_int32 a0, a1; + a1 = mode->eBands[j]*(opus_int32)mode->Fs/mode->shortMdctSize - 400*(opus_int32)eband5ms[k-1]; + a0 = 400*(opus_int32)eband5ms[k] - mode->eBands[j]*(opus_int32)mode->Fs/mode->shortMdctSize; + allocVectors[i*mode->nbEBands+j] = (a0*band_allocation[i*maxBands+k-1] + + a1*band_allocation[i*maxBands+k])/(a0+a1); + } + } + } + + /*printf ("\n"); + for (i=0;inbEBands;j++) + printf ("%d ", allocVectors[i*mode->nbEBands+j]); + printf ("\n"); + } + exit(0);*/ + + mode->allocVectors = allocVectors; +} + +#endif /* CUSTOM_MODES */ + +CELTMode *opus_custom_mode_create(opus_int32 Fs, int frame_size, int *error) +{ + int i; +#ifdef CUSTOM_MODES + CELTMode *mode=NULL; + int res; + opus_val16 *window; + opus_int16 *logN; + int LM; + ALLOC_STACK; +#if !defined(VAR_ARRAYS) && !defined(USE_ALLOCA) + if (global_stack==NULL) + goto failure; +#endif +#endif + +#ifndef CUSTOM_MODES_ONLY + for (i=0;iFs && + (frame_size<shortMdctSize*static_mode_list[i]->nbShortMdcts) + { + if (error) + *error = OPUS_OK; + return (CELTMode*)static_mode_list[i]; + } + } + } +#endif /* CUSTOM_MODES_ONLY */ + +#ifndef CUSTOM_MODES + if (error) + *error = OPUS_BAD_ARG; + return NULL; +#else + + /* The good thing here is that permutation of the arguments will automatically be invalid */ + + if (Fs < 8000 || Fs > 96000) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + if (frame_size < 40 || frame_size > 1024 || frame_size%2!=0) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + /* Frames of less than 1ms are not supported. */ + if ((opus_int32)frame_size*1000 < Fs) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + + if ((opus_int32)frame_size*75 >= Fs && (frame_size%16)==0) + { + LM = 3; + } else if ((opus_int32)frame_size*150 >= Fs && (frame_size%8)==0) + { + LM = 2; + } else if ((opus_int32)frame_size*300 >= Fs && (frame_size%4)==0) + { + LM = 1; + } else + { + LM = 0; + } + + /* Shorts longer than 3.3ms are not supported. */ + if ((opus_int32)(frame_size>>LM)*300 > Fs) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + + mode = opus_alloc(sizeof(CELTMode)); + if (mode==NULL) + goto failure; + mode->Fs = Fs; + + /* Pre/de-emphasis depends on sampling rate. The "standard" pre-emphasis + is defined as A(z) = 1 - 0.85*z^-1 at 48 kHz. Other rates should + approximate that. */ + if(Fs < 12000) /* 8 kHz */ + { + mode->preemph[0] = QCONST16(0.3500061035f, 15); + mode->preemph[1] = -QCONST16(0.1799926758f, 15); + mode->preemph[2] = QCONST16(0.2719968125f, SIG_SHIFT); /* exact 1/preemph[3] */ + mode->preemph[3] = QCONST16(3.6765136719f, 13); + } else if(Fs < 24000) /* 16 kHz */ + { + mode->preemph[0] = QCONST16(0.6000061035f, 15); + mode->preemph[1] = -QCONST16(0.1799926758f, 15); + mode->preemph[2] = QCONST16(0.4424998650f, SIG_SHIFT); /* exact 1/preemph[3] */ + mode->preemph[3] = QCONST16(2.2598876953f, 13); + } else if(Fs < 40000) /* 32 kHz */ + { + mode->preemph[0] = QCONST16(0.7799987793f, 15); + mode->preemph[1] = -QCONST16(0.1000061035f, 15); + mode->preemph[2] = QCONST16(0.7499771125f, SIG_SHIFT); /* exact 1/preemph[3] */ + mode->preemph[3] = QCONST16(1.3333740234f, 13); + } else /* 48 kHz */ + { + mode->preemph[0] = QCONST16(0.8500061035f, 15); + mode->preemph[1] = QCONST16(0.0f, 15); + mode->preemph[2] = QCONST16(1.f, SIG_SHIFT); + mode->preemph[3] = QCONST16(1.f, 13); + } + + mode->maxLM = LM; + mode->nbShortMdcts = 1<shortMdctSize = frame_size/mode->nbShortMdcts; + res = (mode->Fs+mode->shortMdctSize)/(2*mode->shortMdctSize); + + mode->eBands = compute_ebands(Fs, mode->shortMdctSize, res, &mode->nbEBands); + if (mode->eBands==NULL) + goto failure; + + mode->effEBands = mode->nbEBands; + while (mode->eBands[mode->effEBands] > mode->shortMdctSize) + mode->effEBands--; + + /* Overlap must be divisible by 4 */ + mode->overlap = ((mode->shortMdctSize>>2)<<2); + + compute_allocation_table(mode); + if (mode->allocVectors==NULL) + goto failure; + + window = (opus_val16*)opus_alloc(mode->overlap*sizeof(opus_val16)); + if (window==NULL) + goto failure; + +#ifndef FIXED_POINT + for (i=0;ioverlap;i++) + window[i] = Q15ONE*sin(.5*M_PI* sin(.5*M_PI*(i+.5)/mode->overlap) * sin(.5*M_PI*(i+.5)/mode->overlap)); +#else + for (i=0;ioverlap;i++) + window[i] = MIN32(32767,floor(.5+32768.*sin(.5*M_PI* sin(.5*M_PI*(i+.5)/mode->overlap) * sin(.5*M_PI*(i+.5)/mode->overlap)))); +#endif + mode->window = window; + + logN = (opus_int16*)opus_alloc(mode->nbEBands*sizeof(opus_int16)); + if (logN==NULL) + goto failure; + + for (i=0;inbEBands;i++) + logN[i] = log2_frac(mode->eBands[i+1]-mode->eBands[i], BITRES); + mode->logN = logN; + + compute_pulse_cache(mode, mode->maxLM); + + if (clt_mdct_init(&mode->mdct, 2*mode->shortMdctSize*mode->nbShortMdcts, + mode->maxLM) == 0) + goto failure; + + if (error) + *error = OPUS_OK; + + return mode; +failure: + if (error) + *error = OPUS_ALLOC_FAIL; + if (mode!=NULL) + opus_custom_mode_destroy(mode); + return NULL; +#endif /* !CUSTOM_MODES */ +} + +#ifdef CUSTOM_MODES +void opus_custom_mode_destroy(CELTMode *mode) +{ + if (mode == NULL) + return; +#ifndef CUSTOM_MODES_ONLY + { + int i; + for (i=0;ieBands); + opus_free((opus_int16*)mode->allocVectors); + + opus_free((opus_val16*)mode->window); + opus_free((opus_int16*)mode->logN); + + opus_free((opus_int16*)mode->cache.index); + opus_free((unsigned char*)mode->cache.bits); + opus_free((unsigned char*)mode->cache.caps); + clt_mdct_clear(&mode->mdct); + + opus_free((CELTMode *)mode); +} +#endif diff --git a/code/opus-1.0.2/celt/modes.h b/code/opus-1.0.2/celt/modes.h new file mode 100644 index 00000000..c8340f98 --- /dev/null +++ b/code/opus-1.0.2/celt/modes.h @@ -0,0 +1,83 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2008 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (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 MODES_H +#define MODES_H + +#include "opus_types.h" +#include "celt.h" +#include "arch.h" +#include "mdct.h" +#include "entenc.h" +#include "entdec.h" + +#define MAX_PERIOD 1024 + +#ifndef OVERLAP +#define OVERLAP(mode) ((mode)->overlap) +#endif + +#ifndef FRAMESIZE +#define FRAMESIZE(mode) ((mode)->mdctSize) +#endif + +typedef struct { + int size; + const opus_int16 *index; + const unsigned char *bits; + const unsigned char *caps; +} PulseCache; + +/** Mode definition (opaque) + @brief Mode definition + */ +struct OpusCustomMode { + opus_int32 Fs; + int overlap; + + int nbEBands; + int effEBands; + opus_val16 preemph[4]; + const opus_int16 *eBands; /**< Definition for each "pseudo-critical band" */ + + int maxLM; + int nbShortMdcts; + int shortMdctSize; + + int nbAllocVectors; /**< Number of lines in the matrix below */ + const unsigned char *allocVectors; /**< Number of bits in each band for several rates */ + const opus_int16 *logN; + + const opus_val16 *window; + mdct_lookup mdct; + PulseCache cache; +}; + + +#endif diff --git a/code/opus-1.0.2/celt/opus_custom_demo.c b/code/opus-1.0.2/celt/opus_custom_demo.c new file mode 100644 index 00000000..ae41c0de --- /dev/null +++ b/code/opus-1.0.2/celt/opus_custom_demo.c @@ -0,0 +1,210 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "opus_custom.h" +#include "arch.h" +#include +#include +#include +#include + +#define MAX_PACKET 1275 + +int main(int argc, char *argv[]) +{ + int err; + char *inFile, *outFile; + FILE *fin, *fout; + OpusCustomMode *mode=NULL; + OpusCustomEncoder *enc; + OpusCustomDecoder *dec; + int len; + opus_int32 frame_size, channels, rate; + int bytes_per_packet; + unsigned char data[MAX_PACKET]; + int complexity; +#if !(defined (FIXED_POINT) && !defined(CUSTOM_MODES)) && defined(RESYNTH) + int i; + double rmsd = 0; +#endif + int count = 0; + opus_int32 skip; + opus_int16 *in, *out; + if (argc != 9 && argc != 8 && argc != 7) + { + fprintf (stderr, "Usage: test_opus_custom " + " [ [packet loss rate]] " + " \n"); + return 1; + } + + rate = (opus_int32)atol(argv[1]); + channels = atoi(argv[2]); + frame_size = atoi(argv[3]); + mode = opus_custom_mode_create(rate, frame_size, NULL); + if (mode == NULL) + { + fprintf(stderr, "failed to create a mode\n"); + return 1; + } + + bytes_per_packet = atoi(argv[4]); + if (bytes_per_packet < 0 || bytes_per_packet > MAX_PACKET) + { + fprintf (stderr, "bytes per packet must be between 0 and %d\n", + MAX_PACKET); + return 1; + } + + inFile = argv[argc-2]; + fin = fopen(inFile, "rb"); + if (!fin) + { + fprintf (stderr, "Could not open input file %s\n", argv[argc-2]); + return 1; + } + outFile = argv[argc-1]; + fout = fopen(outFile, "wb+"); + if (!fout) + { + fprintf (stderr, "Could not open output file %s\n", argv[argc-1]); + fclose(fin); + return 1; + } + + enc = opus_custom_encoder_create(mode, channels, &err); + if (err != 0) + { + fprintf(stderr, "Failed to create the encoder: %s\n", opus_strerror(err)); + fclose(fin); + fclose(fout); + return 1; + } + dec = opus_custom_decoder_create(mode, channels, &err); + if (err != 0) + { + fprintf(stderr, "Failed to create the decoder: %s\n", opus_strerror(err)); + fclose(fin); + fclose(fout); + return 1; + } + opus_custom_decoder_ctl(dec, OPUS_GET_LOOKAHEAD(&skip)); + + if (argc>7) + { + complexity=atoi(argv[5]); + opus_custom_encoder_ctl(enc,OPUS_SET_COMPLEXITY(complexity)); + } + + in = (opus_int16*)malloc(frame_size*channels*sizeof(opus_int16)); + out = (opus_int16*)malloc(frame_size*channels*sizeof(opus_int16)); + + while (!feof(fin)) + { + int ret; + err = fread(in, sizeof(short), frame_size*channels, fin); + if (feof(fin)) + break; + len = opus_custom_encode(enc, in, frame_size, data, bytes_per_packet); + if (len <= 0) + fprintf (stderr, "opus_custom_encode() failed: %s\n", opus_strerror(len)); + + /* This is for simulating bit errors */ +#if 0 + int errors = 0; + int eid = 0; + /* This simulates random bit error */ + for (i=0;i 0) + { + rmsd = sqrt(rmsd/(1.0*frame_size*channels*count)); + fprintf (stderr, "Error: encoder doesn't match decoder\n"); + fprintf (stderr, "RMS mismatch is %f\n", rmsd); + return 1; + } else { + fprintf (stderr, "Encoder matches decoder!!\n"); + } +#endif + return 0; +} + diff --git a/code/opus-1.0.2/celt/os_support.h b/code/opus-1.0.2/celt/os_support.h new file mode 100644 index 00000000..2484f0b2 --- /dev/null +++ b/code/opus-1.0.2/celt/os_support.h @@ -0,0 +1,89 @@ +/* Copyright (C) 2007 Jean-Marc Valin + + File: os_support.h + This is the (tiny) OS abstraction layer. Aside from math.h, this is the + only place where system headers are allowed. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (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 OS_SUPPORT_H +#define OS_SUPPORT_H + +#ifdef CUSTOM_SUPPORT +# include "custom_support.h" +#endif + +#include +#include +#include + +/** Opus wrapper for malloc(). To do your own dynamic allocation, all you need to do is replace this function and opus_free */ +#ifndef OVERRIDE_OPUS_ALLOC +static inline void *opus_alloc (size_t size) +{ + return malloc(size); +} +#endif + +/** Same as celt_alloc(), except that the area is only needed inside a CELT call (might cause problem with wideband though) */ +#ifndef OVERRIDE_OPUS_ALLOC_SCRATCH +static inline void *opus_alloc_scratch (size_t size) +{ + /* Scratch space doesn't need to be cleared */ + return opus_alloc(size); +} +#endif + +/** Opus wrapper for free(). To do your own dynamic allocation, all you need to do is replace this function and opus_alloc */ +#ifndef OVERRIDE_OPUS_FREE +static inline void opus_free (void *ptr) +{ + free(ptr); +} +#endif + +/** Copy n bytes of memory from src to dst. The 0* term provides compile-time type checking */ +#ifndef OVERRIDE_OPUS_COPY +#define OPUS_COPY(dst, src, n) (memcpy((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) )) +#endif + +/** Copy n bytes of memory from src to dst, allowing overlapping regions. The 0* term + provides compile-time type checking */ +#ifndef OVERRIDE_OPUS_MOVE +#define OPUS_MOVE(dst, src, n) (memmove((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) )) +#endif + +/** Set n elements of dst to zero, starting at address s */ +#ifndef OVERRIDE_OPUS_CLEAR +#define OPUS_CLEAR(dst, n) (memset((dst), 0, (n)*sizeof(*(dst)))) +#endif + +/*#ifdef __GNUC__ +#pragma GCC poison printf sprintf +#pragma GCC poison malloc free realloc calloc +#endif*/ + +#endif /* OS_SUPPORT_H */ + diff --git a/code/opus-1.0.2/celt/pitch.c b/code/opus-1.0.2/celt/pitch.c new file mode 100644 index 00000000..ca0f523e --- /dev/null +++ b/code/opus-1.0.2/celt/pitch.c @@ -0,0 +1,410 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/** + @file pitch.c + @brief Pitch analysis + */ + +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "pitch.h" +#include "os_support.h" +#include "modes.h" +#include "stack_alloc.h" +#include "mathops.h" +#include "celt_lpc.h" + +static void find_best_pitch(opus_val32 *xcorr, opus_val16 *y, int len, + int max_pitch, int *best_pitch +#ifdef FIXED_POINT + , int yshift, opus_val32 maxcorr +#endif + ) +{ + int i, j; + opus_val32 Syy=1; + opus_val16 best_num[2]; + opus_val32 best_den[2]; +#ifdef FIXED_POINT + int xshift; + + xshift = celt_ilog2(maxcorr)-14; +#endif + + best_num[0] = -1; + best_num[1] = -1; + best_den[0] = 0; + best_den[1] = 0; + best_pitch[0] = 0; + best_pitch[1] = 1; + for (j=0;j0) + { + opus_val16 num; + opus_val32 xcorr16; + xcorr16 = EXTRACT16(VSHR32(xcorr[i], xshift)); +#ifndef FIXED_POINT + /* Considering the range of xcorr16, this should avoid both underflows + and overflows (inf) when squaring xcorr16 */ + xcorr16 *= 1e-12f; +#endif + num = MULT16_16_Q15(xcorr16,xcorr16); + if (MULT16_32_Q15(num,best_den[1]) > MULT16_32_Q15(best_num[1],Syy)) + { + if (MULT16_32_Q15(num,best_den[0]) > MULT16_32_Q15(best_num[0],Syy)) + { + best_num[1] = best_num[0]; + best_den[1] = best_den[0]; + best_pitch[1] = best_pitch[0]; + best_num[0] = num; + best_den[0] = Syy; + best_pitch[0] = i; + } else { + best_num[1] = num; + best_den[1] = Syy; + best_pitch[1] = i; + } + } + } + Syy += SHR32(MULT16_16(y[i+len],y[i+len]),yshift) - SHR32(MULT16_16(y[i],y[i]),yshift); + Syy = MAX32(1, Syy); + } +} + +void pitch_downsample(celt_sig * OPUS_RESTRICT x[], opus_val16 * OPUS_RESTRICT x_lp, + int len, int C) +{ + int i; + opus_val32 ac[5]; + opus_val16 tmp=Q15ONE; + opus_val16 lpc[4], mem[4]={0,0,0,0}; +#ifdef FIXED_POINT + int shift; + opus_val32 maxabs = celt_maxabs32(x[0], len); + if (C==2) + { + opus_val32 maxabs_1 = celt_maxabs32(x[1], len); + maxabs = MAX32(maxabs, maxabs_1); + } + if (maxabs<1) + maxabs=1; + shift = celt_ilog2(maxabs)-10; + if (shift<0) + shift=0; + if (C==2) + shift++; +#endif + for (i=1;i>1;i++) + x_lp[i] = SHR32(HALF32(HALF32(x[0][(2*i-1)]+x[0][(2*i+1)])+x[0][2*i]), shift); + x_lp[0] = SHR32(HALF32(HALF32(x[0][1])+x[0][0]), shift); + if (C==2) + { + for (i=1;i>1;i++) + x_lp[i] += SHR32(HALF32(HALF32(x[1][(2*i-1)]+x[1][(2*i+1)])+x[1][2*i]), shift); + x_lp[0] += SHR32(HALF32(HALF32(x[1][1])+x[1][0]), shift); + } + + _celt_autocorr(x_lp, ac, NULL, 0, + 4, len>>1); + + /* Noise floor -40 dB */ +#ifdef FIXED_POINT + ac[0] += SHR32(ac[0],13); +#else + ac[0] *= 1.0001f; +#endif + /* Lag windowing */ + for (i=1;i<=4;i++) + { + /*ac[i] *= exp(-.5*(2*M_PI*.002*i)*(2*M_PI*.002*i));*/ +#ifdef FIXED_POINT + ac[i] -= MULT16_32_Q15(2*i*i, ac[i]); +#else + ac[i] -= ac[i]*(.008f*i)*(.008f*i); +#endif + } + + _celt_lpc(lpc, ac, 4); + for (i=0;i<4;i++) + { + tmp = MULT16_16_Q15(QCONST16(.9f,15), tmp); + lpc[i] = MULT16_16_Q15(lpc[i], tmp); + } + celt_fir(x_lp, lpc, x_lp, len>>1, 4, mem); + + mem[0]=0; + lpc[0]=QCONST16(.8f,12); + celt_fir(x_lp, lpc, x_lp, len>>1, 1, mem); + +} + +void pitch_search(const opus_val16 * OPUS_RESTRICT x_lp, opus_val16 * OPUS_RESTRICT y, + int len, int max_pitch, int *pitch) +{ + int i, j; + int lag; + int best_pitch[2]={0,0}; + VARDECL(opus_val16, x_lp4); + VARDECL(opus_val16, y_lp4); + VARDECL(opus_val32, xcorr); +#ifdef FIXED_POINT + opus_val32 maxcorr=1; + opus_val16 xmax, ymax; + int shift=0; +#endif + int offset; + + SAVE_STACK; + + celt_assert(len>0); + celt_assert(max_pitch>0); + lag = len+max_pitch; + + ALLOC(x_lp4, len>>2, opus_val16); + ALLOC(y_lp4, lag>>2, opus_val16); + ALLOC(xcorr, max_pitch>>1, opus_val32); + + /* Downsample by 2 again */ + for (j=0;j>2;j++) + x_lp4[j] = x_lp[2*j]; + for (j=0;j>2;j++) + y_lp4[j] = y[2*j]; + +#ifdef FIXED_POINT + xmax = celt_maxabs16(x_lp4, len>>2); + ymax = celt_maxabs16(y_lp4, lag>>2); + shift = celt_ilog2(MAX16(1, MAX16(xmax, ymax)))-11; + if (shift>0) + { + for (j=0;j>2;j++) + x_lp4[j] = SHR16(x_lp4[j], shift); + for (j=0;j>2;j++) + y_lp4[j] = SHR16(y_lp4[j], shift); + /* Use double the shift for a MAC */ + shift *= 2; + } else { + shift = 0; + } +#endif + + /* Coarse search with 4x decimation */ + + for (i=0;i>2;i++) + { + opus_val32 sum = 0; + for (j=0;j>2;j++) + sum = MAC16_16(sum, x_lp4[j],y_lp4[i+j]); + xcorr[i] = MAX32(-1, sum); +#ifdef FIXED_POINT + maxcorr = MAX32(maxcorr, sum); +#endif + } + find_best_pitch(xcorr, y_lp4, len>>2, max_pitch>>2, best_pitch +#ifdef FIXED_POINT + , 0, maxcorr +#endif + ); + + /* Finer search with 2x decimation */ +#ifdef FIXED_POINT + maxcorr=1; +#endif + for (i=0;i>1;i++) + { + opus_val32 sum=0; + xcorr[i] = 0; + if (abs(i-2*best_pitch[0])>2 && abs(i-2*best_pitch[1])>2) + continue; + for (j=0;j>1;j++) + sum += SHR32(MULT16_16(x_lp[j],y[i+j]), shift); + xcorr[i] = MAX32(-1, sum); +#ifdef FIXED_POINT + maxcorr = MAX32(maxcorr, sum); +#endif + } + find_best_pitch(xcorr, y, len>>1, max_pitch>>1, best_pitch +#ifdef FIXED_POINT + , shift+1, maxcorr +#endif + ); + + /* Refine by pseudo-interpolation */ + if (best_pitch[0]>0 && best_pitch[0]<(max_pitch>>1)-1) + { + opus_val32 a, b, c; + a = xcorr[best_pitch[0]-1]; + b = xcorr[best_pitch[0]]; + c = xcorr[best_pitch[0]+1]; + if ((c-a) > MULT16_32_Q15(QCONST16(.7f,15),b-a)) + offset = 1; + else if ((a-c) > MULT16_32_Q15(QCONST16(.7f,15),b-c)) + offset = -1; + else + offset = 0; + } else { + offset = 0; + } + *pitch = 2*best_pitch[0]-offset; + + RESTORE_STACK; +} + +static const int second_check[16] = {0, 0, 3, 2, 3, 2, 5, 2, 3, 2, 3, 2, 5, 2, 3, 2}; +opus_val16 remove_doubling(opus_val16 *x, int maxperiod, int minperiod, + int N, int *T0_, int prev_period, opus_val16 prev_gain) +{ + int k, i, T, T0; + opus_val16 g, g0; + opus_val16 pg; + opus_val32 xy,xx,yy; + opus_val32 xcorr[3]; + opus_val32 best_xy, best_yy; + int offset; + int minperiod0; + + minperiod0 = minperiod; + maxperiod /= 2; + minperiod /= 2; + *T0_ /= 2; + prev_period /= 2; + N /= 2; + x += maxperiod; + if (*T0_>=maxperiod) + *T0_=maxperiod-1; + + T = T0 = *T0_; + xx=xy=yy=0; + for (i=0;i>1; + t = VSHR32(x2y2, 2*(sh-7)); + g = g0 = VSHR32(MULT16_32_Q15(celt_rsqrt_norm(t), xy),sh+1); + } +#else + g = g0 = xy/celt_sqrt(1+xx*yy); +#endif + /* Look for any pitch at T/k */ + for (k=2;k<=15;k++) + { + int T1, T1b; + opus_val16 g1; + opus_val16 cont=0; + T1 = (2*T0+k)/(2*k); + if (T1 < minperiod) + break; + /* Look for another strong correlation at T1b */ + if (k==2) + { + if (T1+T0>maxperiod) + T1b = T0; + else + T1b = T0+T1; + } else + { + T1b = (2*second_check[k]*T0+k)/(2*k); + } + xy=yy=0; + for (i=0;i>1; + t = VSHR32(x2y2, 2*(sh-7)); + g1 = VSHR32(MULT16_32_Q15(celt_rsqrt_norm(t), xy),sh+1); + } +#else + g1 = xy/celt_sqrt(1+2.f*xx*1.f*yy); +#endif + if (abs(T1-prev_period)<=1) + cont = prev_gain; + else if (abs(T1-prev_period)<=2 && 5*k*k < T0) + cont = HALF32(prev_gain); + else + cont = 0; + if (g1 > QCONST16(.3f,15) + MULT16_16_Q15(QCONST16(.4f,15),g0)-cont) + { + best_xy = xy; + best_yy = yy; + T = T1; + g = g1; + } + } + best_xy = MAX32(0, best_xy); + if (best_yy <= best_xy) + pg = Q15ONE; + else + pg = SHR32(frac_div32(best_xy,best_yy+1),16); + + for (k=0;k<3;k++) + { + int T1 = T+k-1; + xy = 0; + for (i=0;i MULT16_32_Q15(QCONST16(.7f,15),xcorr[1]-xcorr[0])) + offset = 1; + else if ((xcorr[0]-xcorr[2]) > MULT16_32_Q15(QCONST16(.7f,15),xcorr[1]-xcorr[2])) + offset = -1; + else + offset = 0; + if (pg > g) + pg = g; + *T0_ = 2*T+offset; + + if (*T0_ +#include "os_support.h" +#include "arch.h" +#include "mathops.h" +#include "stack_alloc.h" +#include "rate.h" + +#ifdef FIXED_POINT +/* Mean energy in each band quantized in Q6 */ +static const signed char eMeans[25] = { + 103,100, 92, 85, 81, + 77, 72, 70, 78, 75, + 73, 71, 78, 74, 69, + 72, 70, 74, 76, 71, + 60, 60, 60, 60, 60 +}; +#else +/* Mean energy in each band quantized in Q6 and converted back to float */ +static const opus_val16 eMeans[25] = { + 6.437500f, 6.250000f, 5.750000f, 5.312500f, 5.062500f, + 4.812500f, 4.500000f, 4.375000f, 4.875000f, 4.687500f, + 4.562500f, 4.437500f, 4.875000f, 4.625000f, 4.312500f, + 4.500000f, 4.375000f, 4.625000f, 4.750000f, 4.437500f, + 3.750000f, 3.750000f, 3.750000f, 3.750000f, 3.750000f +}; +#endif +/* prediction coefficients: 0.9, 0.8, 0.65, 0.5 */ +#ifdef FIXED_POINT +static const opus_val16 pred_coef[4] = {29440, 26112, 21248, 16384}; +static const opus_val16 beta_coef[4] = {30147, 22282, 12124, 6554}; +static const opus_val16 beta_intra = 4915; +#else +static const opus_val16 pred_coef[4] = {29440/32768., 26112/32768., 21248/32768., 16384/32768.}; +static const opus_val16 beta_coef[4] = {30147/32768., 22282/32768., 12124/32768., 6554/32768.}; +static const opus_val16 beta_intra = 4915/32768.; +#endif + +/*Parameters of the Laplace-like probability models used for the coarse energy. + There is one pair of parameters for each frame size, prediction type + (inter/intra), and band number. + The first number of each pair is the probability of 0, and the second is the + decay rate, both in Q8 precision.*/ +static const unsigned char e_prob_model[4][2][42] = { + /*120 sample frames.*/ + { + /*Inter*/ + { + 72, 127, 65, 129, 66, 128, 65, 128, 64, 128, 62, 128, 64, 128, + 64, 128, 92, 78, 92, 79, 92, 78, 90, 79, 116, 41, 115, 40, + 114, 40, 132, 26, 132, 26, 145, 17, 161, 12, 176, 10, 177, 11 + }, + /*Intra*/ + { + 24, 179, 48, 138, 54, 135, 54, 132, 53, 134, 56, 133, 55, 132, + 55, 132, 61, 114, 70, 96, 74, 88, 75, 88, 87, 74, 89, 66, + 91, 67, 100, 59, 108, 50, 120, 40, 122, 37, 97, 43, 78, 50 + } + }, + /*240 sample frames.*/ + { + /*Inter*/ + { + 83, 78, 84, 81, 88, 75, 86, 74, 87, 71, 90, 73, 93, 74, + 93, 74, 109, 40, 114, 36, 117, 34, 117, 34, 143, 17, 145, 18, + 146, 19, 162, 12, 165, 10, 178, 7, 189, 6, 190, 8, 177, 9 + }, + /*Intra*/ + { + 23, 178, 54, 115, 63, 102, 66, 98, 69, 99, 74, 89, 71, 91, + 73, 91, 78, 89, 86, 80, 92, 66, 93, 64, 102, 59, 103, 60, + 104, 60, 117, 52, 123, 44, 138, 35, 133, 31, 97, 38, 77, 45 + } + }, + /*480 sample frames.*/ + { + /*Inter*/ + { + 61, 90, 93, 60, 105, 42, 107, 41, 110, 45, 116, 38, 113, 38, + 112, 38, 124, 26, 132, 27, 136, 19, 140, 20, 155, 14, 159, 16, + 158, 18, 170, 13, 177, 10, 187, 8, 192, 6, 175, 9, 159, 10 + }, + /*Intra*/ + { + 21, 178, 59, 110, 71, 86, 75, 85, 84, 83, 91, 66, 88, 73, + 87, 72, 92, 75, 98, 72, 105, 58, 107, 54, 115, 52, 114, 55, + 112, 56, 129, 51, 132, 40, 150, 33, 140, 29, 98, 35, 77, 42 + } + }, + /*960 sample frames.*/ + { + /*Inter*/ + { + 42, 121, 96, 66, 108, 43, 111, 40, 117, 44, 123, 32, 120, 36, + 119, 33, 127, 33, 134, 34, 139, 21, 147, 23, 152, 20, 158, 25, + 154, 26, 166, 21, 173, 16, 184, 13, 184, 10, 150, 13, 139, 15 + }, + /*Intra*/ + { + 22, 178, 63, 114, 74, 82, 84, 83, 92, 82, 103, 62, 96, 72, + 96, 67, 101, 73, 107, 72, 113, 55, 118, 52, 125, 52, 118, 52, + 117, 55, 135, 49, 137, 39, 157, 32, 145, 29, 97, 33, 77, 40 + } + } +}; + +static const unsigned char small_energy_icdf[3]={2,1,0}; + +static opus_val32 loss_distortion(const opus_val16 *eBands, opus_val16 *oldEBands, int start, int end, int len, int C) +{ + int c, i; + opus_val32 dist = 0; + c=0; do { + for (i=start;inbEBands]; + oldE = MAX16(-QCONST16(9.f,DB_SHIFT), oldEBands[i+c*m->nbEBands]); +#ifdef FIXED_POINT + f = SHL32(EXTEND32(x),7) - PSHR32(MULT16_16(coef,oldE), 8) - prev[c]; + /* Rounding to nearest integer here is really important! */ + qi = (f+QCONST32(.5f,DB_SHIFT+7))>>(DB_SHIFT+7); + decay_bound = EXTRACT16(MAX32(-QCONST16(28.f,DB_SHIFT), + SUB32((opus_val32)oldEBands[i+c*m->nbEBands],max_decay))); +#else + f = x-coef*oldE-prev[c]; + /* Rounding to nearest integer here is really important! */ + qi = (int)floor(.5f+f); + decay_bound = MAX16(-QCONST16(28.f,DB_SHIFT), oldEBands[i+c*m->nbEBands]) - max_decay; +#endif + /* Prevent the energy from going down too quickly (e.g. for bands + that have just one bin) */ + if (qi < 0 && x < decay_bound) + { + qi += (int)SHR16(SUB16(decay_bound,x), DB_SHIFT); + if (qi > 0) + qi = 0; + } + qi0 = qi; + /* If we don't have enough bits to encode all the energy, just assume + something safe. */ + tell = ec_tell(enc); + bits_left = budget-tell-3*C*(end-i); + if (i!=start && bits_left < 30) + { + if (bits_left < 24) + qi = IMIN(1, qi); + if (bits_left < 16) + qi = IMAX(-1, qi); + } + if (budget-tell >= 15) + { + int pi; + pi = 2*IMIN(i,20); + ec_laplace_encode(enc, &qi, + prob_model[pi]<<7, prob_model[pi+1]<<6); + } + else if(budget-tell >= 2) + { + qi = IMAX(-1, IMIN(qi, 1)); + ec_enc_icdf(enc, 2*qi^-(qi<0), small_energy_icdf, 2); + } + else if(budget-tell >= 1) + { + qi = IMIN(0, qi); + ec_enc_bit_logp(enc, -qi, 1); + } + else + qi = -1; + error[i+c*m->nbEBands] = PSHR32(f,7) - SHL16(qi,DB_SHIFT); + badness += abs(qi0-qi); + q = (opus_val32)SHL32(EXTEND32(qi),DB_SHIFT); + + tmp = PSHR32(MULT16_16(coef,oldE),8) + prev[c] + SHL32(q,7); +#ifdef FIXED_POINT + tmp = MAX32(-QCONST32(28.f, DB_SHIFT+7), tmp); +#endif + oldEBands[i+c*m->nbEBands] = PSHR32(tmp, 7); + prev[c] = prev[c] + SHL32(q,7) - MULT16_16(beta,PSHR32(q,8)); + } while (++c < C); + } + return badness; +} + +void quant_coarse_energy(const CELTMode *m, int start, int end, int effEnd, + const opus_val16 *eBands, opus_val16 *oldEBands, opus_uint32 budget, + opus_val16 *error, ec_enc *enc, int C, int LM, int nbAvailableBytes, + int force_intra, opus_val32 *delayedIntra, int two_pass, int loss_rate) +{ + int intra; + opus_val16 max_decay; + VARDECL(opus_val16, oldEBands_intra); + VARDECL(opus_val16, error_intra); + ec_enc enc_start_state; + opus_uint32 tell; + int badness1=0; + opus_int32 intra_bias; + opus_val32 new_distortion; + SAVE_STACK; + + intra = force_intra || (!two_pass && *delayedIntra>2*C*(end-start) && nbAvailableBytes > (end-start)*C); + intra_bias = (opus_int32)((budget**delayedIntra*loss_rate)/(C*512)); + new_distortion = loss_distortion(eBands, oldEBands, start, effEnd, m->nbEBands, C); + + tell = ec_tell(enc); + if (tell+3 > budget) + two_pass = intra = 0; + + /* Encode the global flags using a simple probability model + (first symbols in the stream) */ + + max_decay = QCONST16(16.f,DB_SHIFT); + if (end-start>10) + { +#ifdef FIXED_POINT + max_decay = MIN32(max_decay, SHL32(EXTEND32(nbAvailableBytes),DB_SHIFT-3)); +#else + max_decay = MIN32(max_decay, .125f*nbAvailableBytes); +#endif + } + enc_start_state = *enc; + + ALLOC(oldEBands_intra, C*m->nbEBands, opus_val16); + ALLOC(error_intra, C*m->nbEBands, opus_val16); + OPUS_COPY(oldEBands_intra, oldEBands, C*m->nbEBands); + + if (two_pass || intra) + { + badness1 = quant_coarse_energy_impl(m, start, end, eBands, oldEBands_intra, budget, + tell, e_prob_model[LM][1], error_intra, enc, C, LM, 1, max_decay); + } + + if (!intra) + { + unsigned char *intra_buf; + ec_enc enc_intra_state; + opus_int32 tell_intra; + opus_uint32 nstart_bytes; + opus_uint32 nintra_bytes; + int badness2; + VARDECL(unsigned char, intra_bits); + + tell_intra = ec_tell_frac(enc); + + enc_intra_state = *enc; + + nstart_bytes = ec_range_bytes(&enc_start_state); + nintra_bytes = ec_range_bytes(&enc_intra_state); + intra_buf = ec_get_buffer(&enc_intra_state) + nstart_bytes; + ALLOC(intra_bits, nintra_bytes-nstart_bytes, unsigned char); + /* Copy bits from intra bit-stream */ + OPUS_COPY(intra_bits, intra_buf, nintra_bytes - nstart_bytes); + + *enc = enc_start_state; + + badness2 = quant_coarse_energy_impl(m, start, end, eBands, oldEBands, budget, + tell, e_prob_model[LM][intra], error, enc, C, LM, 0, max_decay); + + if (two_pass && (badness1 < badness2 || (badness1 == badness2 && ((opus_int32)ec_tell_frac(enc))+intra_bias > tell_intra))) + { + *enc = enc_intra_state; + /* Copy intra bits to bit-stream */ + OPUS_COPY(intra_buf, intra_bits, nintra_bytes - nstart_bytes); + OPUS_COPY(oldEBands, oldEBands_intra, C*m->nbEBands); + OPUS_COPY(error, error_intra, C*m->nbEBands); + intra = 1; + } + } else { + OPUS_COPY(oldEBands, oldEBands_intra, C*m->nbEBands); + OPUS_COPY(error, error_intra, C*m->nbEBands); + } + + if (intra) + *delayedIntra = new_distortion; + else + *delayedIntra = ADD32(MULT16_32_Q15(MULT16_16_Q15(pred_coef[LM], pred_coef[LM]),*delayedIntra), + new_distortion); + + RESTORE_STACK; +} + +void quant_fine_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, opus_val16 *error, int *fine_quant, ec_enc *enc, int C) +{ + int i, c; + + /* Encode finer resolution */ + for (i=start;inbEBands]+QCONST16(.5f,DB_SHIFT))>>(DB_SHIFT-fine_quant[i]); +#else + q2 = (int)floor((error[i+c*m->nbEBands]+.5f)*frac); +#endif + if (q2 > frac-1) + q2 = frac-1; + if (q2<0) + q2 = 0; + ec_enc_bits(enc, q2, fine_quant[i]); +#ifdef FIXED_POINT + offset = SUB16(SHR32(SHL32(EXTEND32(q2),DB_SHIFT)+QCONST16(.5f,DB_SHIFT),fine_quant[i]),QCONST16(.5f,DB_SHIFT)); +#else + offset = (q2+.5f)*(1<<(14-fine_quant[i]))*(1.f/16384) - .5f; +#endif + oldEBands[i+c*m->nbEBands] += offset; + error[i+c*m->nbEBands] -= offset; + /*printf ("%f ", error[i] - offset);*/ + } while (++c < C); + } +} + +void quant_energy_finalise(const CELTMode *m, int start, int end, opus_val16 *oldEBands, opus_val16 *error, int *fine_quant, int *fine_priority, int bits_left, ec_enc *enc, int C) +{ + int i, prio, c; + + /* Use up the remaining bits */ + for (prio=0;prio<2;prio++) + { + for (i=start;i=C ;i++) + { + if (fine_quant[i] >= MAX_FINE_BITS || fine_priority[i]!=prio) + continue; + c=0; + do { + int q2; + opus_val16 offset; + q2 = error[i+c*m->nbEBands]<0 ? 0 : 1; + ec_enc_bits(enc, q2, 1); +#ifdef FIXED_POINT + offset = SHR16(SHL16(q2,DB_SHIFT)-QCONST16(.5f,DB_SHIFT),fine_quant[i]+1); +#else + offset = (q2-.5f)*(1<<(14-fine_quant[i]-1))*(1.f/16384); +#endif + oldEBands[i+c*m->nbEBands] += offset; + bits_left--; + } while (++c < C); + } + } +} + +void unquant_coarse_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int intra, ec_dec *dec, int C, int LM) +{ + const unsigned char *prob_model = e_prob_model[LM][intra]; + int i, c; + opus_val32 prev[2] = {0, 0}; + opus_val16 coef; + opus_val16 beta; + opus_int32 budget; + opus_int32 tell; + + if (intra) + { + coef = 0; + beta = beta_intra; + } else { + beta = beta_coef[LM]; + coef = pred_coef[LM]; + } + + budget = dec->storage*8; + + /* Decode at a fixed coarse resolution */ + for (i=start;i=15) + { + int pi; + pi = 2*IMIN(i,20); + qi = ec_laplace_decode(dec, + prob_model[pi]<<7, prob_model[pi+1]<<6); + } + else if(budget-tell>=2) + { + qi = ec_dec_icdf(dec, small_energy_icdf, 2); + qi = (qi>>1)^-(qi&1); + } + else if(budget-tell>=1) + { + qi = -ec_dec_bit_logp(dec, 1); + } + else + qi = -1; + q = (opus_val32)SHL32(EXTEND32(qi),DB_SHIFT); + + oldEBands[i+c*m->nbEBands] = MAX16(-QCONST16(9.f,DB_SHIFT), oldEBands[i+c*m->nbEBands]); + tmp = PSHR32(MULT16_16(coef,oldEBands[i+c*m->nbEBands]),8) + prev[c] + SHL32(q,7); +#ifdef FIXED_POINT + tmp = MAX32(-QCONST32(28.f, DB_SHIFT+7), tmp); +#endif + oldEBands[i+c*m->nbEBands] = PSHR32(tmp, 7); + prev[c] = prev[c] + SHL32(q,7) - MULT16_16(beta,PSHR32(q,8)); + } while (++c < C); + } +} + +void unquant_fine_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int *fine_quant, ec_dec *dec, int C) +{ + int i, c; + /* Decode finer resolution */ + for (i=start;inbEBands] += offset; + } while (++c < C); + } +} + +void unquant_energy_finalise(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int *fine_quant, int *fine_priority, int bits_left, ec_dec *dec, int C) +{ + int i, prio, c; + + /* Use up the remaining bits */ + for (prio=0;prio<2;prio++) + { + for (i=start;i=C ;i++) + { + if (fine_quant[i] >= MAX_FINE_BITS || fine_priority[i]!=prio) + continue; + c=0; + do { + int q2; + opus_val16 offset; + q2 = ec_dec_bits(dec, 1); +#ifdef FIXED_POINT + offset = SHR16(SHL16(q2,DB_SHIFT)-QCONST16(.5f,DB_SHIFT),fine_quant[i]+1); +#else + offset = (q2-.5f)*(1<<(14-fine_quant[i]-1))*(1.f/16384); +#endif + oldEBands[i+c*m->nbEBands] += offset; + bits_left--; + } while (++c < C); + } + } +} + +void log2Amp(const CELTMode *m, int start, int end, + celt_ener *eBands, const opus_val16 *oldEBands, int C) +{ + int c, i; + c=0; + do { + for (i=0;inbEBands] = 0; + for (;inbEBands], + SHL16((opus_val16)eMeans[i],6)); + eBands[i+c*m->nbEBands] = PSHR32(celt_exp2(lg),4); + } + for (;inbEBands;i++) + eBands[i+c*m->nbEBands] = 0; + } while (++c < C); +} + +void amp2Log2(const CELTMode *m, int effEnd, int end, + celt_ener *bandE, opus_val16 *bandLogE, int C) +{ + int c, i; + c=0; + do { + for (i=0;inbEBands] = + celt_log2(SHL32(bandE[i+c*m->nbEBands],2)) + - SHL16((opus_val16)eMeans[i],6); + for (i=effEnd;inbEBands+i] = -QCONST16(14.f,DB_SHIFT); + } while (++c < C); +} diff --git a/code/opus-1.0.2/celt/quant_bands.h b/code/opus-1.0.2/celt/quant_bands.h new file mode 100644 index 00000000..bec2855c --- /dev/null +++ b/code/opus-1.0.2/celt/quant_bands.h @@ -0,0 +1,60 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (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 QUANT_BANDS +#define QUANT_BANDS + +#include "arch.h" +#include "modes.h" +#include "entenc.h" +#include "entdec.h" +#include "mathops.h" + +void amp2Log2(const CELTMode *m, int effEnd, int end, + celt_ener *bandE, opus_val16 *bandLogE, int C); + +void log2Amp(const CELTMode *m, int start, int end, + celt_ener *eBands, const opus_val16 *oldEBands, int C); + +void quant_coarse_energy(const CELTMode *m, int start, int end, int effEnd, + const opus_val16 *eBands, opus_val16 *oldEBands, opus_uint32 budget, + opus_val16 *error, ec_enc *enc, int C, int LM, + int nbAvailableBytes, int force_intra, opus_val32 *delayedIntra, + int two_pass, int loss_rate); + +void quant_fine_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, opus_val16 *error, int *fine_quant, ec_enc *enc, int C); + +void quant_energy_finalise(const CELTMode *m, int start, int end, opus_val16 *oldEBands, opus_val16 *error, int *fine_quant, int *fine_priority, int bits_left, ec_enc *enc, int C); + +void unquant_coarse_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int intra, ec_dec *dec, int C, int LM); + +void unquant_fine_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int *fine_quant, ec_dec *dec, int C); + +void unquant_energy_finalise(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int *fine_quant, int *fine_priority, int bits_left, ec_dec *dec, int C); + +#endif /* QUANT_BANDS */ diff --git a/code/opus-1.0.2/celt/rate.c b/code/opus-1.0.2/celt/rate.c new file mode 100644 index 00000000..4e96787f --- /dev/null +++ b/code/opus-1.0.2/celt/rate.c @@ -0,0 +1,638 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "modes.h" +#include "cwrs.h" +#include "arch.h" +#include "os_support.h" + +#include "entcode.h" +#include "rate.h" + +static const unsigned char LOG2_FRAC_TABLE[24]={ + 0, + 8,13, + 16,19,21,23, + 24,26,27,28,29,30,31,32, + 32,33,34,34,35,36,36,37,37 +}; + +#ifdef CUSTOM_MODES + +/*Determines if V(N,K) fits in a 32-bit unsigned integer. + N and K are themselves limited to 15 bits.*/ +static int fits_in32(int _n, int _k) +{ + static const opus_int16 maxN[15] = { + 32767, 32767, 32767, 1476, 283, 109, 60, 40, + 29, 24, 20, 18, 16, 14, 13}; + static const opus_int16 maxK[15] = { + 32767, 32767, 32767, 32767, 1172, 238, 95, 53, + 36, 27, 22, 18, 16, 15, 13}; + if (_n>=14) + { + if (_k>=14) + return 0; + else + return _n <= maxN[_k]; + } else { + return _k <= maxK[_n]; + } +} + +void compute_pulse_cache(CELTMode *m, int LM) +{ + int C; + int i; + int j; + int curr=0; + int nbEntries=0; + int entryN[100], entryK[100], entryI[100]; + const opus_int16 *eBands = m->eBands; + PulseCache *cache = &m->cache; + opus_int16 *cindex; + unsigned char *bits; + unsigned char *cap; + + cindex = (opus_int16 *)opus_alloc(sizeof(cache->index[0])*m->nbEBands*(LM+2)); + cache->index = cindex; + + /* Scan for all unique band sizes */ + for (i=0;i<=LM+1;i++) + { + for (j=0;jnbEBands;j++) + { + int k; + int N = (eBands[j+1]-eBands[j])<>1; + cindex[i*m->nbEBands+j] = -1; + /* Find other bands that have the same size */ + for (k=0;k<=i;k++) + { + int n; + for (n=0;nnbEBands && (k!=i || n>1) + { + cindex[i*m->nbEBands+j] = cindex[k*m->nbEBands+n]; + break; + } + } + } + if (cache->index[i*m->nbEBands+j] == -1 && N!=0) + { + int K; + entryN[nbEntries] = N; + K = 0; + while (fits_in32(N,get_pulses(K+1)) && KnbEBands+j] = curr; + entryI[nbEntries] = curr; + + curr += K+1; + nbEntries++; + } + } + } + bits = (unsigned char *)opus_alloc(sizeof(unsigned char)*curr); + cache->bits = bits; + cache->size = curr; + /* Compute the cache for all unique sizes */ + for (i=0;icaps = cap = (unsigned char *)opus_alloc(sizeof(cache->caps[0])*(LM+1)*2*m->nbEBands); + for (i=0;i<=LM;i++) + { + for (C=1;C<=2;C++) + { + for (j=0;jnbEBands;j++) + { + int N0; + int max_bits; + N0 = m->eBands[j+1]-m->eBands[j]; + /* N=1 bands only have a sign bit and fine bits. */ + if (N0<1 are even, including custom modes.*/ + if (N0 > 2) + { + N0>>=1; + LM0--; + } + /* N0=1 bands can't be split down to N<2. */ + else if (N0 <= 1) + { + LM0=IMIN(i,1); + N0<<=LM0; + } + /* Compute the cost for the lowest-level PVQ of a fully split + band. */ + pcache = bits + cindex[(LM0+1)*m->nbEBands+j]; + max_bits = pcache[pcache[0]]+1; + /* Add in the cost of coding regular splits. */ + N = N0; + for(k=0;klogN[j]+((LM0+k)<>1)-QTHETA_OFFSET; + /* The number of qtheta bits we'll allocate if the remainder + is to be max_bits. + The average measured cost for theta is 0.89701 times qb, + approximated here as 459/512. */ + num=459*(opus_int32)((2*N-1)*offset+max_bits); + den=((opus_int32)(2*N-1)<<9)-459; + qb = IMIN((num+(den>>1))/den, 57); + celt_assert(qb >= 0); + max_bits += qb; + N <<= 1; + } + /* Add in the cost of a stereo split, if necessary. */ + if (C==2) + { + max_bits <<= 1; + offset = ((m->logN[j]+(i<>1)-(N==2?QTHETA_OFFSET_TWOPHASE:QTHETA_OFFSET); + ndof = 2*N-1-(N==2); + /* The average measured cost for theta with the step PDF is + 0.95164 times qb, approximated here as 487/512. */ + num = (N==2?512:487)*(opus_int32)(max_bits+ndof*offset); + den = ((opus_int32)ndof<<9)-(N==2?512:487); + qb = IMIN((num+(den>>1))/den, (N==2?64:61)); + celt_assert(qb >= 0); + max_bits += qb; + } + /* Add the fine bits we'll use. */ + /* Compensate for the extra DoF in stereo */ + ndof = C*N + ((C==2 && N>2) ? 1 : 0); + /* Offset the number of fine bits by log2(N)/2 + FINE_OFFSET + compared to their "fair share" of total/N */ + offset = ((m->logN[j] + (i<>1)-FINE_OFFSET; + /* N=2 is the only point that doesn't match the curve */ + if (N==2) + offset += 1<>2; + /* The number of fine bits we'll allocate if the remainder is + to be max_bits. */ + num = max_bits+ndof*offset; + den = (ndof-1)<>1))/den, MAX_FINE_BITS); + celt_assert(qb >= 0); + max_bits += C*qb<eBands[j+1]-m->eBands[j])<= 0); + celt_assert(max_bits < 256); + *cap++ = (unsigned char)max_bits; + } + } + } +} + +#endif /* CUSTOM_MODES */ + +#define ALLOC_STEPS 6 + +static inline int interp_bits2pulses(const CELTMode *m, int start, int end, int skip_start, + const int *bits1, const int *bits2, const int *thresh, const int *cap, opus_int32 total, opus_int32 *_balance, + int skip_rsv, int *intensity, int intensity_rsv, int *dual_stereo, int dual_stereo_rsv, int *bits, + int *ebits, int *fine_priority, int C, int LM, ec_ctx *ec, int encode, int prev) +{ + opus_int32 psum; + int lo, hi; + int i, j; + int logM; + int stereo; + int codedBands=-1; + int alloc_floor; + opus_int32 left, percoeff; + int done; + opus_int32 balance; + SAVE_STACK; + + alloc_floor = C<1; + + logM = LM<>1; + psum = 0; + done = 0; + for (j=end;j-->start;) + { + int tmp = bits1[j] + (mid*(opus_int32)bits2[j]>>ALLOC_STEPS); + if (tmp >= thresh[j] || done) + { + done = 1; + /* Don't allocate more than we can actually use */ + psum += IMIN(tmp, cap[j]); + } else { + if (tmp >= alloc_floor) + psum += alloc_floor; + } + } + if (psum > total) + hi = mid; + else + lo = mid; + } + psum = 0; + /*printf ("interp bisection gave %d\n", lo);*/ + done = 0; + for (j=end;j-->start;) + { + int tmp = bits1[j] + (lo*bits2[j]>>ALLOC_STEPS); + if (tmp < thresh[j] && !done) + { + if (tmp >= alloc_floor) + tmp = alloc_floor; + else + tmp = 0; + } else + done = 1; + /* Don't allocate more than we can actually use */ + tmp = IMIN(tmp, cap[j]); + bits[j] = tmp; + psum += tmp; + } + + /* Decide which bands to skip, working backwards from the end. */ + for (codedBands=end;;codedBands--) + { + int band_width; + int band_bits; + int rem; + j = codedBands-1; + /* Never skip the first band, nor a band that has been boosted by + dynalloc. + In the first case, we'd be coding a bit to signal we're going to waste + all the other bits. + In the second case, we'd be coding a bit to redistribute all the bits + we just signaled should be cocentrated in this band. */ + if (j<=skip_start) + { + /* Give the bit we reserved to end skipping back. */ + total += skip_rsv; + break; + } + /*Figure out how many left-over bits we would be adding to this band. + This can include bits we've stolen back from higher, skipped bands.*/ + left = total-psum; + percoeff = left/(m->eBands[codedBands]-m->eBands[start]); + left -= (m->eBands[codedBands]-m->eBands[start])*percoeff; + rem = IMAX(left-(m->eBands[j]-m->eBands[start]),0); + band_width = m->eBands[codedBands]-m->eBands[j]; + band_bits = (int)(bits[j] + percoeff*band_width + rem); + /*Only code a skip decision if we're above the threshold for this band. + Otherwise it is force-skipped. + This ensures that we have enough bits to code the skip flag.*/ + if (band_bits >= IMAX(thresh[j], alloc_floor+(1< ((j>4) +#endif + { + ec_enc_bit_logp(ec, 1, 1); + break; + } + ec_enc_bit_logp(ec, 0, 1); + } else if (ec_dec_bit_logp(ec, 1)) { + break; + } + /*We used a bit to skip this band.*/ + psum += 1< 0) + intensity_rsv = LOG2_FRAC_TABLE[j-start]; + psum += intensity_rsv; + if (band_bits >= alloc_floor) + { + /*If we have enough for a fine energy bit per channel, use it.*/ + psum += alloc_floor; + bits[j] = alloc_floor; + } else { + /*Otherwise this band gets nothing at all.*/ + bits[j] = 0; + } + } + + celt_assert(codedBands > start); + /* Code the intensity and dual stereo parameters. */ + if (intensity_rsv > 0) + { + if (encode) + { + *intensity = IMIN(*intensity, codedBands); + ec_enc_uint(ec, *intensity-start, codedBands+1-start); + } + else + *intensity = start+ec_dec_uint(ec, codedBands+1-start); + } + else + *intensity = 0; + if (*intensity <= start) + { + total += dual_stereo_rsv; + dual_stereo_rsv = 0; + } + if (dual_stereo_rsv > 0) + { + if (encode) + ec_enc_bit_logp(ec, *dual_stereo, 1); + else + *dual_stereo = ec_dec_bit_logp(ec, 1); + } + else + *dual_stereo = 0; + + /* Allocate the remaining bits */ + left = total-psum; + percoeff = left/(m->eBands[codedBands]-m->eBands[start]); + left -= (m->eBands[codedBands]-m->eBands[start])*percoeff; + for (j=start;jeBands[j+1]-m->eBands[j])); + for (j=start;jeBands[j+1]-m->eBands[j]); + bits[j] += tmp; + left -= tmp; + } + /*for (j=0;j= 0); + N0 = m->eBands[j+1]-m->eBands[j]; + N=N0<1) + { + excess = MAX32(bit-cap[j],0); + bits[j] = bit-excess; + + /* Compensate for the extra DoF in stereo */ + den=(C*N+ ((C==2 && N>2 && !*dual_stereo && j<*intensity) ? 1 : 0)); + + NClogN = den*(m->logN[j] + logM); + + /* Offset for the number of fine bits by log2(N)/2 + FINE_OFFSET + compared to their "fair share" of total/N */ + offset = (NClogN>>1)-den*FINE_OFFSET; + + /* N=2 is the only point that doesn't match the curve */ + if (N==2) + offset += den<>2; + + /* Changing the offset for allocating the second and third + fine energy bit */ + if (bits[j] + offset < den*2<>2; + else if (bits[j] + offset < den*3<>3; + + /* Divide with rounding */ + ebits[j] = IMAX(0, (bits[j] + offset + (den<<(BITRES-1))) / (den< (bits[j]>>BITRES)) + ebits[j] = bits[j] >> stereo >> BITRES; + + /* More than that is useless because that's about as far as PVQ can go */ + ebits[j] = IMIN(ebits[j], MAX_FINE_BITS); + + /* If we rounded down or capped this band, make it a candidate for the + final fine energy pass */ + fine_priority[j] = ebits[j]*(den<= bits[j]+offset; + + /* Remove the allocated fine bits; the rest are assigned to PVQ */ + bits[j] -= C*ebits[j]< 0) + { + int extra_fine; + int extra_bits; + extra_fine = IMIN(excess>>(stereo+BITRES),MAX_FINE_BITS-ebits[j]); + ebits[j] += extra_fine; + extra_bits = extra_fine*C<= excess-balance; + excess -= extra_bits; + } + balance = excess; + + celt_assert(bits[j] >= 0); + celt_assert(ebits[j] >= 0); + } + /* Save any remaining bits over the cap for the rebalancing in + quant_all_bands(). */ + *_balance = balance; + + /* The skipped bands use all their bits for fine energy. */ + for (;j> stereo >> BITRES; + celt_assert(C*ebits[j]<nbEBands; + skip_start = start; + /* Reserve a bit to signal the end of manually skipped bands. */ + skip_rsv = total >= 1<total) + intensity_rsv = 0; + else + { + total -= intensity_rsv; + dual_stereo_rsv = total>=1<eBands[j+1]-m->eBands[j])<>4); + /* Tilt of the allocation curve */ + trim_offset[j] = C*(m->eBands[j+1]-m->eBands[j])*(alloc_trim-5-LM)*(end-j-1) + *(1<<(LM+BITRES))>>6; + /* Giving less resolution to single-coefficient bands because they get + more benefit from having one coarse value per coefficient*/ + if ((m->eBands[j+1]-m->eBands[j])<nbAllocVectors - 1; + do + { + int done = 0; + int psum = 0; + int mid = (lo+hi) >> 1; + for (j=end;j-->start;) + { + int bitsj; + int N = m->eBands[j+1]-m->eBands[j]; + bitsj = C*N*m->allocVectors[mid*len+j]<>2; + if (bitsj > 0) + bitsj = IMAX(0, bitsj + trim_offset[j]); + bitsj += offsets[j]; + if (bitsj >= thresh[j] || done) + { + done = 1; + /* Don't allocate more than we can actually use */ + psum += IMIN(bitsj, cap[j]); + } else { + if (bitsj >= C< total) + hi = mid - 1; + else + lo = mid + 1; + /*printf ("lo = %d, hi = %d\n", lo, hi);*/ + } + while (lo <= hi); + hi = lo--; + /*printf ("interp between %d and %d\n", lo, hi);*/ + for (j=start;jeBands[j+1]-m->eBands[j]; + bits1j = C*N*m->allocVectors[lo*len+j]<>2; + bits2j = hi>=m->nbAllocVectors ? + cap[j] : C*N*m->allocVectors[hi*len+j]<>2; + if (bits1j > 0) + bits1j = IMAX(0, bits1j + trim_offset[j]); + if (bits2j > 0) + bits2j = IMAX(0, bits2j + trim_offset[j]); + if (lo > 0) + bits1j += offsets[j]; + bits2j += offsets[j]; + if (offsets[j]>0) + skip_start = j; + bits2j = IMAX(0,bits2j-bits1j); + bits1[j] = bits1j; + bits2[j] = bits2j; + } + codedBands = interp_bits2pulses(m, start, end, skip_start, bits1, bits2, thresh, cap, + total, balance, skip_rsv, intensity, intensity_rsv, dual_stereo, dual_stereo_rsv, + pulses, ebits, fine_priority, C, LM, ec, encode, prev); + RESTORE_STACK; + return codedBands; +} + diff --git a/code/opus-1.0.2/celt/rate.h b/code/opus-1.0.2/celt/rate.h new file mode 100644 index 00000000..e0d50223 --- /dev/null +++ b/code/opus-1.0.2/celt/rate.h @@ -0,0 +1,101 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (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 RATE_H +#define RATE_H + +#define MAX_PSEUDO 40 +#define LOG_MAX_PSEUDO 6 + +#define MAX_PULSES 128 + +#define MAX_FINE_BITS 8 + +#define FINE_OFFSET 21 +#define QTHETA_OFFSET 4 +#define QTHETA_OFFSET_TWOPHASE 16 + +#include "cwrs.h" +#include "modes.h" + +void compute_pulse_cache(CELTMode *m, int LM); + +static inline int get_pulses(int i) +{ + return i<8 ? i : (8 + (i&7)) << ((i>>3)-1); +} + +static inline int bits2pulses(const CELTMode *m, int band, int LM, int bits) +{ + int i; + int lo, hi; + const unsigned char *cache; + + LM++; + cache = m->cache.bits + m->cache.index[LM*m->nbEBands+band]; + + lo = 0; + hi = cache[0]; + bits--; + for (i=0;i>1; + /* OPT: Make sure this is implemented with a conditional move */ + if ((int)cache[mid] >= bits) + hi = mid; + else + lo = mid; + } + if (bits- (lo == 0 ? -1 : (int)cache[lo]) <= (int)cache[hi]-bits) + return lo; + else + return hi; +} + +static inline int pulses2bits(const CELTMode *m, int band, int LM, int pulses) +{ + const unsigned char *cache; + + LM++; + cache = m->cache.bits + m->cache.index[LM*m->nbEBands+band]; + return pulses == 0 ? 0 : cache[pulses]+1; +} + +/** Compute the pulse allocation, i.e. how many pulses will go in each + * band. + @param m mode + @param offsets Requested increase or decrease in the number of bits for + each band + @param total Number of bands + @param pulses Number of pulses per band (returned) + @return Total number of bits allocated +*/ +int compute_allocation(const CELTMode *m, int start, int end, const int *offsets, const int *cap, int alloc_trim, int *intensity, int *dual_stero, + opus_int32 total, opus_int32 *balance, int *pulses, int *ebits, int *fine_priority, int C, int LM, ec_ctx *ec, int encode, int prev); + +#endif diff --git a/code/opus-1.0.2/celt/stack_alloc.h b/code/opus-1.0.2/celt/stack_alloc.h new file mode 100644 index 00000000..a6f06d22 --- /dev/null +++ b/code/opus-1.0.2/celt/stack_alloc.h @@ -0,0 +1,149 @@ +/* Copyright (C) 2002-2003 Jean-Marc Valin + Copyright (C) 2007-2009 Xiph.Org Foundation */ +/** + @file stack_alloc.h + @brief Temporary memory allocation on stack +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (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 STACK_ALLOC_H +#define STACK_ALLOC_H + +#if (!defined (VAR_ARRAYS) && !defined (USE_ALLOCA) && !defined (NONTHREADSAFE_PSEUDOSTACK)) +#error "Opus requires one of VAR_ARRAYS, USE_ALLOCA, or NONTHREADSAFE_PSEUDOSTACK be defined to select the temporary allocation mode." +#endif + +#ifdef USE_ALLOCA +# ifdef WIN32 +# include +# else +# ifdef HAVE_ALLOCA_H +# include +# else +# include +# endif +# endif +#endif + +/** + * @def ALIGN(stack, size) + * + * Aligns the stack to a 'size' boundary + * + * @param stack Stack + * @param size New size boundary + */ + +/** + * @def PUSH(stack, size, type) + * + * Allocates 'size' elements of type 'type' on the stack + * + * @param stack Stack + * @param size Number of elements + * @param type Type of element + */ + +/** + * @def VARDECL(var) + * + * Declare variable on stack + * + * @param var Variable to declare + */ + +/** + * @def ALLOC(var, size, type) + * + * Allocate 'size' elements of 'type' on stack + * + * @param var Name of variable to allocate + * @param size Number of elements + * @param type Type of element + */ + +#if defined(VAR_ARRAYS) + +#define VARDECL(type, var) +#define ALLOC(var, size, type) type var[size] +#define SAVE_STACK +#define RESTORE_STACK +#define ALLOC_STACK + +#elif defined(USE_ALLOCA) + +#define VARDECL(type, var) type *var + +# ifdef WIN32 +# define ALLOC(var, size, type) var = ((type*)_alloca(sizeof(type)*(size))) +# else +# define ALLOC(var, size, type) var = ((type*)alloca(sizeof(type)*(size))) +# endif + +#define SAVE_STACK +#define RESTORE_STACK +#define ALLOC_STACK + +#else + +#ifdef CELT_C +char *global_stack=0; +#else +extern char *global_stack; +#endif /* CELT_C */ + +#ifdef ENABLE_VALGRIND + +#include + +#ifdef CELT_C +char *global_stack_top=0; +#else +extern char *global_stack_top; +#endif /* CELT_C */ + +#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1)) +#define PUSH(stack, size, type) (VALGRIND_MAKE_MEM_NOACCESS(stack, global_stack_top-stack),ALIGN((stack),sizeof(type)/sizeof(char)),VALGRIND_MAKE_MEM_UNDEFINED(stack, ((size)*sizeof(type)/sizeof(char))),(stack)+=(2*(size)*sizeof(type)/sizeof(char)),(type*)((stack)-(2*(size)*sizeof(type)/sizeof(char)))) +#define RESTORE_STACK ((global_stack = _saved_stack),VALGRIND_MAKE_MEM_NOACCESS(global_stack, global_stack_top-global_stack)) +#define ALLOC_STACK char *_saved_stack; ((global_stack = (global_stack==0) ? ((global_stack_top=opus_alloc_scratch(GLOBAL_STACK_SIZE*2)+(GLOBAL_STACK_SIZE*2))-(GLOBAL_STACK_SIZE*2)) : global_stack),VALGRIND_MAKE_MEM_NOACCESS(global_stack, global_stack_top-global_stack)); _saved_stack = global_stack; + +#else + +#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1)) +#define PUSH(stack, size, type) (ALIGN((stack),sizeof(type)/sizeof(char)),(stack)+=(size)*(sizeof(type)/sizeof(char)),(type*)((stack)-(size)*(sizeof(type)/sizeof(char)))) +#define RESTORE_STACK (global_stack = _saved_stack) +#define ALLOC_STACK char *_saved_stack; (global_stack = (global_stack==0) ? opus_alloc_scratch(GLOBAL_STACK_SIZE) : global_stack); _saved_stack = global_stack; + +#endif /* ENABLE_VALGRIND */ + +#include "os_support.h" +#define VARDECL(type, var) type *var +#define ALLOC(var, size, type) var = PUSH(global_stack, size, type) +#define SAVE_STACK char *_saved_stack = global_stack; + +#endif /* VAR_ARRAYS */ + +#endif /* STACK_ALLOC_H */ diff --git a/code/opus-1.0.2/celt/static_modes_fixed.h b/code/opus-1.0.2/celt/static_modes_fixed.h new file mode 100644 index 00000000..216df9e6 --- /dev/null +++ b/code/opus-1.0.2/celt/static_modes_fixed.h @@ -0,0 +1,595 @@ +/* The contents of this file was automatically generated by dump_modes.c + with arguments: 48000 960 + It contains static definitions for some pre-defined modes. */ +#include "modes.h" +#include "rate.h" + +#ifndef DEF_WINDOW120 +#define DEF_WINDOW120 +static const opus_val16 window120[120] = { +2, 20, 55, 108, 178, +266, 372, 494, 635, 792, +966, 1157, 1365, 1590, 1831, +2089, 2362, 2651, 2956, 3276, +3611, 3961, 4325, 4703, 5094, +5499, 5916, 6346, 6788, 7241, +7705, 8179, 8663, 9156, 9657, +10167, 10684, 11207, 11736, 12271, +12810, 13353, 13899, 14447, 14997, +15547, 16098, 16648, 17197, 17744, +18287, 18827, 19363, 19893, 20418, +20936, 21447, 21950, 22445, 22931, +23407, 23874, 24330, 24774, 25208, +25629, 26039, 26435, 26819, 27190, +27548, 27893, 28224, 28541, 28845, +29135, 29411, 29674, 29924, 30160, +30384, 30594, 30792, 30977, 31151, +31313, 31463, 31602, 31731, 31849, +31958, 32057, 32148, 32229, 32303, +32370, 32429, 32481, 32528, 32568, +32604, 32634, 32661, 32683, 32701, +32717, 32729, 32740, 32748, 32754, +32758, 32762, 32764, 32766, 32767, +32767, 32767, 32767, 32767, 32767, +}; +#endif + +#ifndef DEF_LOGN400 +#define DEF_LOGN400 +static const opus_int16 logN400[21] = { +0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 16, 16, 16, 21, 21, 24, 29, 34, 36, }; +#endif + +#ifndef DEF_PULSE_CACHE50 +#define DEF_PULSE_CACHE50 +static const opus_int16 cache_index50[105] = { +-1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 41, 41, 41, +82, 82, 123, 164, 200, 222, 0, 0, 0, 0, 0, 0, 0, 0, 41, +41, 41, 41, 123, 123, 123, 164, 164, 240, 266, 283, 295, 41, 41, 41, +41, 41, 41, 41, 41, 123, 123, 123, 123, 240, 240, 240, 266, 266, 305, +318, 328, 336, 123, 123, 123, 123, 123, 123, 123, 123, 240, 240, 240, 240, +305, 305, 305, 318, 318, 343, 351, 358, 364, 240, 240, 240, 240, 240, 240, +240, 240, 305, 305, 305, 305, 343, 343, 343, 351, 351, 370, 376, 382, 387, +}; +static const unsigned char cache_bits50[392] = { +40, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, +7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, +7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 40, 15, 23, 28, +31, 34, 36, 38, 39, 41, 42, 43, 44, 45, 46, 47, 47, 49, 50, +51, 52, 53, 54, 55, 55, 57, 58, 59, 60, 61, 62, 63, 63, 65, +66, 67, 68, 69, 70, 71, 71, 40, 20, 33, 41, 48, 53, 57, 61, +64, 66, 69, 71, 73, 75, 76, 78, 80, 82, 85, 87, 89, 91, 92, +94, 96, 98, 101, 103, 105, 107, 108, 110, 112, 114, 117, 119, 121, 123, +124, 126, 128, 40, 23, 39, 51, 60, 67, 73, 79, 83, 87, 91, 94, +97, 100, 102, 105, 107, 111, 115, 118, 121, 124, 126, 129, 131, 135, 139, +142, 145, 148, 150, 153, 155, 159, 163, 166, 169, 172, 174, 177, 179, 35, +28, 49, 65, 78, 89, 99, 107, 114, 120, 126, 132, 136, 141, 145, 149, +153, 159, 165, 171, 176, 180, 185, 189, 192, 199, 205, 211, 216, 220, 225, +229, 232, 239, 245, 251, 21, 33, 58, 79, 97, 112, 125, 137, 148, 157, +166, 174, 182, 189, 195, 201, 207, 217, 227, 235, 243, 251, 17, 35, 63, +86, 106, 123, 139, 152, 165, 177, 187, 197, 206, 214, 222, 230, 237, 250, +25, 31, 55, 75, 91, 105, 117, 128, 138, 146, 154, 161, 168, 174, 180, +185, 190, 200, 208, 215, 222, 229, 235, 240, 245, 255, 16, 36, 65, 89, +110, 128, 144, 159, 173, 185, 196, 207, 217, 226, 234, 242, 250, 11, 41, +74, 103, 128, 151, 172, 191, 209, 225, 241, 255, 9, 43, 79, 110, 138, +163, 186, 207, 227, 246, 12, 39, 71, 99, 123, 144, 164, 182, 198, 214, +228, 241, 253, 9, 44, 81, 113, 142, 168, 192, 214, 235, 255, 7, 49, +90, 127, 160, 191, 220, 247, 6, 51, 95, 134, 170, 203, 234, 7, 47, +87, 123, 155, 184, 212, 237, 6, 52, 97, 137, 174, 208, 240, 5, 57, +106, 151, 192, 231, 5, 59, 111, 158, 202, 243, 5, 55, 103, 147, 187, +224, 5, 60, 113, 161, 206, 248, 4, 65, 122, 175, 224, 4, 67, 127, +182, 234, }; +static const unsigned char cache_caps50[168] = { +224, 224, 224, 224, 224, 224, 224, 224, 160, 160, 160, 160, 185, 185, 185, +178, 178, 168, 134, 61, 37, 224, 224, 224, 224, 224, 224, 224, 224, 240, +240, 240, 240, 207, 207, 207, 198, 198, 183, 144, 66, 40, 160, 160, 160, +160, 160, 160, 160, 160, 185, 185, 185, 185, 193, 193, 193, 183, 183, 172, +138, 64, 38, 240, 240, 240, 240, 240, 240, 240, 240, 207, 207, 207, 207, +204, 204, 204, 193, 193, 180, 143, 66, 40, 185, 185, 185, 185, 185, 185, +185, 185, 193, 193, 193, 193, 193, 193, 193, 183, 183, 172, 138, 65, 39, +207, 207, 207, 207, 207, 207, 207, 207, 204, 204, 204, 204, 201, 201, 201, +188, 188, 176, 141, 66, 40, 193, 193, 193, 193, 193, 193, 193, 193, 193, +193, 193, 193, 194, 194, 194, 184, 184, 173, 139, 65, 39, 204, 204, 204, +204, 204, 204, 204, 204, 201, 201, 201, 201, 198, 198, 198, 187, 187, 175, +140, 66, 40, }; +#endif + +#ifndef FFT_TWIDDLES48000_960 +#define FFT_TWIDDLES48000_960 +static const kiss_twiddle_cpx fft_twiddles48000_960[480] = { +{32767, 0}, {32766, -429}, +{32757, -858}, {32743, -1287}, +{32724, -1715}, {32698, -2143}, +{32667, -2570}, {32631, -2998}, +{32588, -3425}, {32541, -3851}, +{32488, -4277}, {32429, -4701}, +{32364, -5125}, {32295, -5548}, +{32219, -5971}, {32138, -6393}, +{32051, -6813}, {31960, -7231}, +{31863, -7650}, {31760, -8067}, +{31652, -8481}, {31539, -8895}, +{31419, -9306}, {31294, -9716}, +{31165, -10126}, {31030, -10532}, +{30889, -10937}, {30743, -11340}, +{30592, -11741}, {30436, -12141}, +{30274, -12540}, {30107, -12935}, +{29936, -13328}, {29758, -13718}, +{29577, -14107}, {29390, -14493}, +{29197, -14875}, {29000, -15257}, +{28797, -15635}, {28590, -16010}, +{28379, -16384}, {28162, -16753}, +{27940, -17119}, {27714, -17484}, +{27482, -17845}, {27246, -18205}, +{27006, -18560}, {26760, -18911}, +{26510, -19260}, {26257, -19606}, +{25997, -19947}, {25734, -20286}, +{25466, -20621}, {25194, -20952}, +{24918, -21281}, {24637, -21605}, +{24353, -21926}, {24063, -22242}, +{23770, -22555}, {23473, -22865}, +{23171, -23171}, {22866, -23472}, +{22557, -23769}, {22244, -24063}, +{21927, -24352}, {21606, -24636}, +{21282, -24917}, {20954, -25194}, +{20622, -25465}, {20288, -25733}, +{19949, -25997}, {19607, -26255}, +{19261, -26509}, {18914, -26760}, +{18561, -27004}, {18205, -27246}, +{17846, -27481}, {17485, -27713}, +{17122, -27940}, {16755, -28162}, +{16385, -28378}, {16012, -28590}, +{15636, -28797}, {15258, -28999}, +{14878, -29197}, {14494, -29389}, +{14108, -29576}, {13720, -29757}, +{13329, -29934}, {12937, -30107}, +{12540, -30274}, {12142, -30435}, +{11744, -30592}, {11342, -30743}, +{10939, -30889}, {10534, -31030}, +{10127, -31164}, {9718, -31294}, +{9307, -31418}, {8895, -31537}, +{8482, -31652}, {8067, -31759}, +{7650, -31862}, {7233, -31960}, +{6815, -32051}, {6393, -32138}, +{5973, -32219}, {5549, -32294}, +{5127, -32364}, {4703, -32429}, +{4278, -32487}, {3852, -32541}, +{3426, -32588}, {2999, -32630}, +{2572, -32667}, {2144, -32698}, +{1716, -32724}, {1287, -32742}, +{860, -32757}, {430, -32766}, +{0, -32767}, {-429, -32766}, +{-858, -32757}, {-1287, -32743}, +{-1715, -32724}, {-2143, -32698}, +{-2570, -32667}, {-2998, -32631}, +{-3425, -32588}, {-3851, -32541}, +{-4277, -32488}, {-4701, -32429}, +{-5125, -32364}, {-5548, -32295}, +{-5971, -32219}, {-6393, -32138}, +{-6813, -32051}, {-7231, -31960}, +{-7650, -31863}, {-8067, -31760}, +{-8481, -31652}, {-8895, -31539}, +{-9306, -31419}, {-9716, -31294}, +{-10126, -31165}, {-10532, -31030}, +{-10937, -30889}, {-11340, -30743}, +{-11741, -30592}, {-12141, -30436}, +{-12540, -30274}, {-12935, -30107}, +{-13328, -29936}, {-13718, -29758}, +{-14107, -29577}, {-14493, -29390}, +{-14875, -29197}, {-15257, -29000}, +{-15635, -28797}, {-16010, -28590}, +{-16384, -28379}, {-16753, -28162}, +{-17119, -27940}, {-17484, -27714}, +{-17845, -27482}, {-18205, -27246}, +{-18560, -27006}, {-18911, -26760}, +{-19260, -26510}, {-19606, -26257}, +{-19947, -25997}, {-20286, -25734}, +{-20621, -25466}, {-20952, -25194}, +{-21281, -24918}, {-21605, -24637}, +{-21926, -24353}, {-22242, -24063}, +{-22555, -23770}, {-22865, -23473}, +{-23171, -23171}, {-23472, -22866}, +{-23769, -22557}, {-24063, -22244}, +{-24352, -21927}, {-24636, -21606}, +{-24917, -21282}, {-25194, -20954}, +{-25465, -20622}, {-25733, -20288}, +{-25997, -19949}, {-26255, -19607}, +{-26509, -19261}, {-26760, -18914}, +{-27004, -18561}, {-27246, -18205}, +{-27481, -17846}, {-27713, -17485}, +{-27940, -17122}, {-28162, -16755}, +{-28378, -16385}, {-28590, -16012}, +{-28797, -15636}, {-28999, -15258}, +{-29197, -14878}, {-29389, -14494}, +{-29576, -14108}, {-29757, -13720}, +{-29934, -13329}, {-30107, -12937}, +{-30274, -12540}, {-30435, -12142}, +{-30592, -11744}, {-30743, -11342}, +{-30889, -10939}, {-31030, -10534}, +{-31164, -10127}, {-31294, -9718}, +{-31418, -9307}, {-31537, -8895}, +{-31652, -8482}, {-31759, -8067}, +{-31862, -7650}, {-31960, -7233}, +{-32051, -6815}, {-32138, -6393}, +{-32219, -5973}, {-32294, -5549}, +{-32364, -5127}, {-32429, -4703}, +{-32487, -4278}, {-32541, -3852}, +{-32588, -3426}, {-32630, -2999}, +{-32667, -2572}, {-32698, -2144}, +{-32724, -1716}, {-32742, -1287}, +{-32757, -860}, {-32766, -430}, +{-32767, 0}, {-32766, 429}, +{-32757, 858}, {-32743, 1287}, +{-32724, 1715}, {-32698, 2143}, +{-32667, 2570}, {-32631, 2998}, +{-32588, 3425}, {-32541, 3851}, +{-32488, 4277}, {-32429, 4701}, +{-32364, 5125}, {-32295, 5548}, +{-32219, 5971}, {-32138, 6393}, +{-32051, 6813}, {-31960, 7231}, +{-31863, 7650}, {-31760, 8067}, +{-31652, 8481}, {-31539, 8895}, +{-31419, 9306}, {-31294, 9716}, +{-31165, 10126}, {-31030, 10532}, +{-30889, 10937}, {-30743, 11340}, +{-30592, 11741}, {-30436, 12141}, +{-30274, 12540}, {-30107, 12935}, +{-29936, 13328}, {-29758, 13718}, +{-29577, 14107}, {-29390, 14493}, +{-29197, 14875}, {-29000, 15257}, +{-28797, 15635}, {-28590, 16010}, +{-28379, 16384}, {-28162, 16753}, +{-27940, 17119}, {-27714, 17484}, +{-27482, 17845}, {-27246, 18205}, +{-27006, 18560}, {-26760, 18911}, +{-26510, 19260}, {-26257, 19606}, +{-25997, 19947}, {-25734, 20286}, +{-25466, 20621}, {-25194, 20952}, +{-24918, 21281}, {-24637, 21605}, +{-24353, 21926}, {-24063, 22242}, +{-23770, 22555}, {-23473, 22865}, +{-23171, 23171}, {-22866, 23472}, +{-22557, 23769}, {-22244, 24063}, +{-21927, 24352}, {-21606, 24636}, +{-21282, 24917}, {-20954, 25194}, +{-20622, 25465}, {-20288, 25733}, +{-19949, 25997}, {-19607, 26255}, +{-19261, 26509}, {-18914, 26760}, +{-18561, 27004}, {-18205, 27246}, +{-17846, 27481}, {-17485, 27713}, +{-17122, 27940}, {-16755, 28162}, +{-16385, 28378}, {-16012, 28590}, +{-15636, 28797}, {-15258, 28999}, +{-14878, 29197}, {-14494, 29389}, +{-14108, 29576}, {-13720, 29757}, +{-13329, 29934}, {-12937, 30107}, +{-12540, 30274}, {-12142, 30435}, +{-11744, 30592}, {-11342, 30743}, +{-10939, 30889}, {-10534, 31030}, +{-10127, 31164}, {-9718, 31294}, +{-9307, 31418}, {-8895, 31537}, +{-8482, 31652}, {-8067, 31759}, +{-7650, 31862}, {-7233, 31960}, +{-6815, 32051}, {-6393, 32138}, +{-5973, 32219}, {-5549, 32294}, +{-5127, 32364}, {-4703, 32429}, +{-4278, 32487}, {-3852, 32541}, +{-3426, 32588}, {-2999, 32630}, +{-2572, 32667}, {-2144, 32698}, +{-1716, 32724}, {-1287, 32742}, +{-860, 32757}, {-430, 32766}, +{0, 32767}, {429, 32766}, +{858, 32757}, {1287, 32743}, +{1715, 32724}, {2143, 32698}, +{2570, 32667}, {2998, 32631}, +{3425, 32588}, {3851, 32541}, +{4277, 32488}, {4701, 32429}, +{5125, 32364}, {5548, 32295}, +{5971, 32219}, {6393, 32138}, +{6813, 32051}, {7231, 31960}, +{7650, 31863}, {8067, 31760}, +{8481, 31652}, {8895, 31539}, +{9306, 31419}, {9716, 31294}, +{10126, 31165}, {10532, 31030}, +{10937, 30889}, {11340, 30743}, +{11741, 30592}, {12141, 30436}, +{12540, 30274}, {12935, 30107}, +{13328, 29936}, {13718, 29758}, +{14107, 29577}, {14493, 29390}, +{14875, 29197}, {15257, 29000}, +{15635, 28797}, {16010, 28590}, +{16384, 28379}, {16753, 28162}, +{17119, 27940}, {17484, 27714}, +{17845, 27482}, {18205, 27246}, +{18560, 27006}, {18911, 26760}, +{19260, 26510}, {19606, 26257}, +{19947, 25997}, {20286, 25734}, +{20621, 25466}, {20952, 25194}, +{21281, 24918}, {21605, 24637}, +{21926, 24353}, {22242, 24063}, +{22555, 23770}, {22865, 23473}, +{23171, 23171}, {23472, 22866}, +{23769, 22557}, {24063, 22244}, +{24352, 21927}, {24636, 21606}, +{24917, 21282}, {25194, 20954}, +{25465, 20622}, {25733, 20288}, +{25997, 19949}, {26255, 19607}, +{26509, 19261}, {26760, 18914}, +{27004, 18561}, {27246, 18205}, +{27481, 17846}, {27713, 17485}, +{27940, 17122}, {28162, 16755}, +{28378, 16385}, {28590, 16012}, +{28797, 15636}, {28999, 15258}, +{29197, 14878}, {29389, 14494}, +{29576, 14108}, {29757, 13720}, +{29934, 13329}, {30107, 12937}, +{30274, 12540}, {30435, 12142}, +{30592, 11744}, {30743, 11342}, +{30889, 10939}, {31030, 10534}, +{31164, 10127}, {31294, 9718}, +{31418, 9307}, {31537, 8895}, +{31652, 8482}, {31759, 8067}, +{31862, 7650}, {31960, 7233}, +{32051, 6815}, {32138, 6393}, +{32219, 5973}, {32294, 5549}, +{32364, 5127}, {32429, 4703}, +{32487, 4278}, {32541, 3852}, +{32588, 3426}, {32630, 2999}, +{32667, 2572}, {32698, 2144}, +{32724, 1716}, {32742, 1287}, +{32757, 860}, {32766, 430}, +}; +#ifndef FFT_BITREV480 +#define FFT_BITREV480 +static const opus_int16 fft_bitrev480[480] = { +0, 120, 240, 360, 30, 150, 270, 390, 60, 180, 300, 420, 90, 210, 330, +450, 15, 135, 255, 375, 45, 165, 285, 405, 75, 195, 315, 435, 105, 225, +345, 465, 5, 125, 245, 365, 35, 155, 275, 395, 65, 185, 305, 425, 95, +215, 335, 455, 20, 140, 260, 380, 50, 170, 290, 410, 80, 200, 320, 440, +110, 230, 350, 470, 10, 130, 250, 370, 40, 160, 280, 400, 70, 190, 310, +430, 100, 220, 340, 460, 25, 145, 265, 385, 55, 175, 295, 415, 85, 205, +325, 445, 115, 235, 355, 475, 1, 121, 241, 361, 31, 151, 271, 391, 61, +181, 301, 421, 91, 211, 331, 451, 16, 136, 256, 376, 46, 166, 286, 406, +76, 196, 316, 436, 106, 226, 346, 466, 6, 126, 246, 366, 36, 156, 276, +396, 66, 186, 306, 426, 96, 216, 336, 456, 21, 141, 261, 381, 51, 171, +291, 411, 81, 201, 321, 441, 111, 231, 351, 471, 11, 131, 251, 371, 41, +161, 281, 401, 71, 191, 311, 431, 101, 221, 341, 461, 26, 146, 266, 386, +56, 176, 296, 416, 86, 206, 326, 446, 116, 236, 356, 476, 2, 122, 242, +362, 32, 152, 272, 392, 62, 182, 302, 422, 92, 212, 332, 452, 17, 137, +257, 377, 47, 167, 287, 407, 77, 197, 317, 437, 107, 227, 347, 467, 7, +127, 247, 367, 37, 157, 277, 397, 67, 187, 307, 427, 97, 217, 337, 457, +22, 142, 262, 382, 52, 172, 292, 412, 82, 202, 322, 442, 112, 232, 352, +472, 12, 132, 252, 372, 42, 162, 282, 402, 72, 192, 312, 432, 102, 222, +342, 462, 27, 147, 267, 387, 57, 177, 297, 417, 87, 207, 327, 447, 117, +237, 357, 477, 3, 123, 243, 363, 33, 153, 273, 393, 63, 183, 303, 423, +93, 213, 333, 453, 18, 138, 258, 378, 48, 168, 288, 408, 78, 198, 318, +438, 108, 228, 348, 468, 8, 128, 248, 368, 38, 158, 278, 398, 68, 188, +308, 428, 98, 218, 338, 458, 23, 143, 263, 383, 53, 173, 293, 413, 83, +203, 323, 443, 113, 233, 353, 473, 13, 133, 253, 373, 43, 163, 283, 403, +73, 193, 313, 433, 103, 223, 343, 463, 28, 148, 268, 388, 58, 178, 298, +418, 88, 208, 328, 448, 118, 238, 358, 478, 4, 124, 244, 364, 34, 154, +274, 394, 64, 184, 304, 424, 94, 214, 334, 454, 19, 139, 259, 379, 49, +169, 289, 409, 79, 199, 319, 439, 109, 229, 349, 469, 9, 129, 249, 369, +39, 159, 279, 399, 69, 189, 309, 429, 99, 219, 339, 459, 24, 144, 264, +384, 54, 174, 294, 414, 84, 204, 324, 444, 114, 234, 354, 474, 14, 134, +254, 374, 44, 164, 284, 404, 74, 194, 314, 434, 104, 224, 344, 464, 29, +149, 269, 389, 59, 179, 299, 419, 89, 209, 329, 449, 119, 239, 359, 479, +}; +#endif + +#ifndef FFT_BITREV240 +#define FFT_BITREV240 +static const opus_int16 fft_bitrev240[240] = { +0, 60, 120, 180, 15, 75, 135, 195, 30, 90, 150, 210, 45, 105, 165, +225, 5, 65, 125, 185, 20, 80, 140, 200, 35, 95, 155, 215, 50, 110, +170, 230, 10, 70, 130, 190, 25, 85, 145, 205, 40, 100, 160, 220, 55, +115, 175, 235, 1, 61, 121, 181, 16, 76, 136, 196, 31, 91, 151, 211, +46, 106, 166, 226, 6, 66, 126, 186, 21, 81, 141, 201, 36, 96, 156, +216, 51, 111, 171, 231, 11, 71, 131, 191, 26, 86, 146, 206, 41, 101, +161, 221, 56, 116, 176, 236, 2, 62, 122, 182, 17, 77, 137, 197, 32, +92, 152, 212, 47, 107, 167, 227, 7, 67, 127, 187, 22, 82, 142, 202, +37, 97, 157, 217, 52, 112, 172, 232, 12, 72, 132, 192, 27, 87, 147, +207, 42, 102, 162, 222, 57, 117, 177, 237, 3, 63, 123, 183, 18, 78, +138, 198, 33, 93, 153, 213, 48, 108, 168, 228, 8, 68, 128, 188, 23, +83, 143, 203, 38, 98, 158, 218, 53, 113, 173, 233, 13, 73, 133, 193, +28, 88, 148, 208, 43, 103, 163, 223, 58, 118, 178, 238, 4, 64, 124, +184, 19, 79, 139, 199, 34, 94, 154, 214, 49, 109, 169, 229, 9, 69, +129, 189, 24, 84, 144, 204, 39, 99, 159, 219, 54, 114, 174, 234, 14, +74, 134, 194, 29, 89, 149, 209, 44, 104, 164, 224, 59, 119, 179, 239, +}; +#endif + +#ifndef FFT_BITREV120 +#define FFT_BITREV120 +static const opus_int16 fft_bitrev120[120] = { +0, 30, 60, 90, 15, 45, 75, 105, 5, 35, 65, 95, 20, 50, 80, +110, 10, 40, 70, 100, 25, 55, 85, 115, 1, 31, 61, 91, 16, 46, +76, 106, 6, 36, 66, 96, 21, 51, 81, 111, 11, 41, 71, 101, 26, +56, 86, 116, 2, 32, 62, 92, 17, 47, 77, 107, 7, 37, 67, 97, +22, 52, 82, 112, 12, 42, 72, 102, 27, 57, 87, 117, 3, 33, 63, +93, 18, 48, 78, 108, 8, 38, 68, 98, 23, 53, 83, 113, 13, 43, +73, 103, 28, 58, 88, 118, 4, 34, 64, 94, 19, 49, 79, 109, 9, +39, 69, 99, 24, 54, 84, 114, 14, 44, 74, 104, 29, 59, 89, 119, +}; +#endif + +#ifndef FFT_BITREV60 +#define FFT_BITREV60 +static const opus_int16 fft_bitrev60[60] = { +0, 15, 30, 45, 5, 20, 35, 50, 10, 25, 40, 55, 1, 16, 31, +46, 6, 21, 36, 51, 11, 26, 41, 56, 2, 17, 32, 47, 7, 22, +37, 52, 12, 27, 42, 57, 3, 18, 33, 48, 8, 23, 38, 53, 13, +28, 43, 58, 4, 19, 34, 49, 9, 24, 39, 54, 14, 29, 44, 59, +}; +#endif + +#ifndef FFT_STATE48000_960_0 +#define FFT_STATE48000_960_0 +static const kiss_fft_state fft_state48000_960_0 = { +480, /* nfft */ +-1, /* shift */ +{4, 120, 4, 30, 2, 15, 3, 5, 5, 1, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev480, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +}; +#endif + +#ifndef FFT_STATE48000_960_1 +#define FFT_STATE48000_960_1 +static const kiss_fft_state fft_state48000_960_1 = { +240, /* nfft */ +1, /* shift */ +{4, 60, 4, 15, 3, 5, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev240, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +}; +#endif + +#ifndef FFT_STATE48000_960_2 +#define FFT_STATE48000_960_2 +static const kiss_fft_state fft_state48000_960_2 = { +120, /* nfft */ +2, /* shift */ +{4, 30, 2, 15, 3, 5, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev120, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +}; +#endif + +#ifndef FFT_STATE48000_960_3 +#define FFT_STATE48000_960_3 +static const kiss_fft_state fft_state48000_960_3 = { +60, /* nfft */ +3, /* shift */ +{4, 15, 3, 5, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev60, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +}; +#endif + +#endif + +#ifndef MDCT_TWIDDLES960 +#define MDCT_TWIDDLES960 +static const opus_val16 mdct_twiddles960[481] = { +32767, 32767, 32767, 32767, 32766, +32763, 32762, 32759, 32757, 32753, +32751, 32747, 32743, 32738, 32733, +32729, 32724, 32717, 32711, 32705, +32698, 32690, 32683, 32676, 32667, +32658, 32650, 32640, 32631, 32620, +32610, 32599, 32588, 32577, 32566, +32554, 32541, 32528, 32515, 32502, +32487, 32474, 32459, 32444, 32429, +32413, 32397, 32381, 32364, 32348, +32331, 32313, 32294, 32277, 32257, +32239, 32219, 32200, 32180, 32159, +32138, 32118, 32096, 32074, 32051, +32029, 32006, 31984, 31960, 31936, +31912, 31888, 31863, 31837, 31812, +31786, 31760, 31734, 31707, 31679, +31652, 31624, 31596, 31567, 31539, +31508, 31479, 31450, 31419, 31388, +31357, 31326, 31294, 31262, 31230, +31198, 31164, 31131, 31097, 31063, +31030, 30994, 30959, 30924, 30889, +30853, 30816, 30779, 30743, 30705, +30668, 30629, 30592, 30553, 30515, +30475, 30435, 30396, 30356, 30315, +30274, 30233, 30191, 30149, 30107, +30065, 30022, 29979, 29936, 29891, +29847, 29803, 29758, 29713, 29668, +29622, 29577, 29529, 29483, 29436, +29390, 29341, 29293, 29246, 29197, +29148, 29098, 29050, 29000, 28949, +28899, 28848, 28797, 28746, 28694, +28642, 28590, 28537, 28485, 28432, +28378, 28324, 28271, 28217, 28162, +28106, 28051, 27995, 27940, 27884, +27827, 27770, 27713, 27657, 27598, +27540, 27481, 27423, 27365, 27305, +27246, 27187, 27126, 27066, 27006, +26945, 26883, 26822, 26760, 26698, +26636, 26574, 26510, 26448, 26383, +26320, 26257, 26191, 26127, 26062, +25997, 25931, 25866, 25800, 25734, +25667, 25601, 25533, 25466, 25398, +25330, 25262, 25194, 25125, 25056, +24987, 24917, 24848, 24778, 24707, +24636, 24566, 24495, 24424, 24352, +24280, 24208, 24135, 24063, 23990, +23917, 23842, 23769, 23695, 23622, +23546, 23472, 23398, 23322, 23246, +23171, 23095, 23018, 22942, 22866, +22788, 22711, 22634, 22557, 22478, +22400, 22322, 22244, 22165, 22085, +22006, 21927, 21846, 21766, 21687, +21606, 21524, 21443, 21363, 21282, +21199, 21118, 21035, 20954, 20870, +20788, 20705, 20621, 20538, 20455, +20371, 20286, 20202, 20118, 20034, +19947, 19863, 19777, 19692, 19606, +19520, 19434, 19347, 19260, 19174, +19088, 18999, 18911, 18825, 18737, +18648, 18560, 18472, 18384, 18294, +18205, 18116, 18025, 17936, 17846, +17757, 17666, 17576, 17485, 17395, +17303, 17212, 17122, 17030, 16937, +16846, 16755, 16662, 16569, 16477, +16385, 16291, 16198, 16105, 16012, +15917, 15824, 15730, 15636, 15541, +15447, 15352, 15257, 15162, 15067, +14973, 14875, 14781, 14685, 14589, +14493, 14396, 14300, 14204, 14107, +14010, 13914, 13815, 13718, 13621, +13524, 13425, 13328, 13230, 13133, +13033, 12935, 12836, 12738, 12638, +12540, 12441, 12341, 12241, 12142, +12044, 11943, 11843, 11744, 11643, +11542, 11442, 11342, 11241, 11139, +11039, 10939, 10836, 10736, 10635, +10534, 10431, 10330, 10228, 10127, +10024, 9921, 9820, 9718, 9614, +9512, 9410, 9306, 9204, 9101, +8998, 8895, 8791, 8689, 8585, +8481, 8377, 8274, 8171, 8067, +7962, 7858, 7753, 7650, 7545, +7441, 7336, 7231, 7129, 7023, +6917, 6813, 6709, 6604, 6498, +6393, 6288, 6182, 6077, 5973, +5867, 5760, 5656, 5549, 5445, +5339, 5232, 5127, 5022, 4914, +4809, 4703, 4596, 4490, 4384, +4278, 4171, 4065, 3958, 3852, +3745, 3640, 3532, 3426, 3318, +3212, 3106, 2998, 2891, 2786, +2679, 2570, 2465, 2358, 2251, +2143, 2037, 1929, 1823, 1715, +1609, 1501, 1393, 1287, 1180, +1073, 964, 858, 751, 644, +535, 429, 322, 214, 107, +0, }; +#endif + +static const CELTMode mode48000_960_120 = { +48000, /* Fs */ +120, /* overlap */ +21, /* nbEBands */ +21, /* effEBands */ +{27853, 0, 4096, 8192, }, /* preemph */ +eband5ms, /* eBands */ +3, /* maxLM */ +8, /* nbShortMdcts */ +120, /* shortMdctSize */ +11, /* nbAllocVectors */ +band_allocation, /* allocVectors */ +logN400, /* logN */ +window120, /* window */ +{1920, 3, {&fft_state48000_960_0, &fft_state48000_960_1, &fft_state48000_960_2, &fft_state48000_960_3, }, mdct_twiddles960}, /* mdct */ +{392, cache_index50, cache_bits50, cache_caps50}, /* cache */ +}; + +/* List of all the available modes */ +#define TOTAL_MODES 1 +static const CELTMode * const static_mode_list[TOTAL_MODES] = { +&mode48000_960_120, +}; diff --git a/code/opus-1.0.2/celt/static_modes_float.h b/code/opus-1.0.2/celt/static_modes_float.h new file mode 100644 index 00000000..5d7e7b8e --- /dev/null +++ b/code/opus-1.0.2/celt/static_modes_float.h @@ -0,0 +1,599 @@ +/* The contents of this file was automatically generated by dump_modes.c + with arguments: 48000 960 + It contains static definitions for some pre-defined modes. */ +#include "modes.h" +#include "rate.h" + +#ifndef DEF_WINDOW120 +#define DEF_WINDOW120 +static const opus_val16 window120[120] = { +6.7286966e-05f, 0.00060551348f, 0.0016815970f, 0.0032947962f, 0.0054439943f, +0.0081276923f, 0.011344001f, 0.015090633f, 0.019364886f, 0.024163635f, +0.029483315f, 0.035319905f, 0.041668911f, 0.048525347f, 0.055883718f, +0.063737999f, 0.072081616f, 0.080907428f, 0.090207705f, 0.099974111f, +0.11019769f, 0.12086883f, 0.13197729f, 0.14351214f, 0.15546177f, +0.16781389f, 0.18055550f, 0.19367290f, 0.20715171f, 0.22097682f, +0.23513243f, 0.24960208f, 0.26436860f, 0.27941419f, 0.29472040f, +0.31026818f, 0.32603788f, 0.34200931f, 0.35816177f, 0.37447407f, +0.39092462f, 0.40749142f, 0.42415215f, 0.44088423f, 0.45766484f, +0.47447104f, 0.49127978f, 0.50806798f, 0.52481261f, 0.54149077f, +0.55807973f, 0.57455701f, 0.59090049f, 0.60708841f, 0.62309951f, +0.63891306f, 0.65450896f, 0.66986776f, 0.68497077f, 0.69980010f, +0.71433873f, 0.72857055f, 0.74248043f, 0.75605424f, 0.76927895f, +0.78214257f, 0.79463430f, 0.80674445f, 0.81846456f, 0.82978733f, +0.84070669f, 0.85121779f, 0.86131698f, 0.87100183f, 0.88027111f, +0.88912479f, 0.89756398f, 0.90559094f, 0.91320904f, 0.92042270f, +0.92723738f, 0.93365955f, 0.93969656f, 0.94535671f, 0.95064907f, +0.95558353f, 0.96017067f, 0.96442171f, 0.96834849f, 0.97196334f, +0.97527906f, 0.97830883f, 0.98106616f, 0.98356480f, 0.98581869f, +0.98784191f, 0.98964856f, 0.99125274f, 0.99266849f, 0.99390969f, +0.99499004f, 0.99592297f, 0.99672162f, 0.99739874f, 0.99796667f, +0.99843728f, 0.99882195f, 0.99913147f, 0.99937606f, 0.99956527f, +0.99970802f, 0.99981248f, 0.99988613f, 0.99993565f, 0.99996697f, +0.99998518f, 0.99999457f, 0.99999859f, 0.99999982f, 1.0000000f, +}; +#endif + +#ifndef DEF_LOGN400 +#define DEF_LOGN400 +static const opus_int16 logN400[21] = { +0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 16, 16, 16, 21, 21, 24, 29, 34, 36, }; +#endif + +#ifndef DEF_PULSE_CACHE50 +#define DEF_PULSE_CACHE50 +static const opus_int16 cache_index50[105] = { +-1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 41, 41, 41, +82, 82, 123, 164, 200, 222, 0, 0, 0, 0, 0, 0, 0, 0, 41, +41, 41, 41, 123, 123, 123, 164, 164, 240, 266, 283, 295, 41, 41, 41, +41, 41, 41, 41, 41, 123, 123, 123, 123, 240, 240, 240, 266, 266, 305, +318, 328, 336, 123, 123, 123, 123, 123, 123, 123, 123, 240, 240, 240, 240, +305, 305, 305, 318, 318, 343, 351, 358, 364, 240, 240, 240, 240, 240, 240, +240, 240, 305, 305, 305, 305, 343, 343, 343, 351, 351, 370, 376, 382, 387, +}; +static const unsigned char cache_bits50[392] = { +40, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, +7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, +7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 40, 15, 23, 28, +31, 34, 36, 38, 39, 41, 42, 43, 44, 45, 46, 47, 47, 49, 50, +51, 52, 53, 54, 55, 55, 57, 58, 59, 60, 61, 62, 63, 63, 65, +66, 67, 68, 69, 70, 71, 71, 40, 20, 33, 41, 48, 53, 57, 61, +64, 66, 69, 71, 73, 75, 76, 78, 80, 82, 85, 87, 89, 91, 92, +94, 96, 98, 101, 103, 105, 107, 108, 110, 112, 114, 117, 119, 121, 123, +124, 126, 128, 40, 23, 39, 51, 60, 67, 73, 79, 83, 87, 91, 94, +97, 100, 102, 105, 107, 111, 115, 118, 121, 124, 126, 129, 131, 135, 139, +142, 145, 148, 150, 153, 155, 159, 163, 166, 169, 172, 174, 177, 179, 35, +28, 49, 65, 78, 89, 99, 107, 114, 120, 126, 132, 136, 141, 145, 149, +153, 159, 165, 171, 176, 180, 185, 189, 192, 199, 205, 211, 216, 220, 225, +229, 232, 239, 245, 251, 21, 33, 58, 79, 97, 112, 125, 137, 148, 157, +166, 174, 182, 189, 195, 201, 207, 217, 227, 235, 243, 251, 17, 35, 63, +86, 106, 123, 139, 152, 165, 177, 187, 197, 206, 214, 222, 230, 237, 250, +25, 31, 55, 75, 91, 105, 117, 128, 138, 146, 154, 161, 168, 174, 180, +185, 190, 200, 208, 215, 222, 229, 235, 240, 245, 255, 16, 36, 65, 89, +110, 128, 144, 159, 173, 185, 196, 207, 217, 226, 234, 242, 250, 11, 41, +74, 103, 128, 151, 172, 191, 209, 225, 241, 255, 9, 43, 79, 110, 138, +163, 186, 207, 227, 246, 12, 39, 71, 99, 123, 144, 164, 182, 198, 214, +228, 241, 253, 9, 44, 81, 113, 142, 168, 192, 214, 235, 255, 7, 49, +90, 127, 160, 191, 220, 247, 6, 51, 95, 134, 170, 203, 234, 7, 47, +87, 123, 155, 184, 212, 237, 6, 52, 97, 137, 174, 208, 240, 5, 57, +106, 151, 192, 231, 5, 59, 111, 158, 202, 243, 5, 55, 103, 147, 187, +224, 5, 60, 113, 161, 206, 248, 4, 65, 122, 175, 224, 4, 67, 127, +182, 234, }; +static const unsigned char cache_caps50[168] = { +224, 224, 224, 224, 224, 224, 224, 224, 160, 160, 160, 160, 185, 185, 185, +178, 178, 168, 134, 61, 37, 224, 224, 224, 224, 224, 224, 224, 224, 240, +240, 240, 240, 207, 207, 207, 198, 198, 183, 144, 66, 40, 160, 160, 160, +160, 160, 160, 160, 160, 185, 185, 185, 185, 193, 193, 193, 183, 183, 172, +138, 64, 38, 240, 240, 240, 240, 240, 240, 240, 240, 207, 207, 207, 207, +204, 204, 204, 193, 193, 180, 143, 66, 40, 185, 185, 185, 185, 185, 185, +185, 185, 193, 193, 193, 193, 193, 193, 193, 183, 183, 172, 138, 65, 39, +207, 207, 207, 207, 207, 207, 207, 207, 204, 204, 204, 204, 201, 201, 201, +188, 188, 176, 141, 66, 40, 193, 193, 193, 193, 193, 193, 193, 193, 193, +193, 193, 193, 194, 194, 194, 184, 184, 173, 139, 65, 39, 204, 204, 204, +204, 204, 204, 204, 204, 201, 201, 201, 201, 198, 198, 198, 187, 187, 175, +140, 66, 40, }; +#endif + +#ifndef FFT_TWIDDLES48000_960 +#define FFT_TWIDDLES48000_960 +static const kiss_twiddle_cpx fft_twiddles48000_960[480] = { +{1.0000000f, -0.0000000f}, {0.99991433f, -0.013089596f}, +{0.99965732f, -0.026176948f}, {0.99922904f, -0.039259816f}, +{0.99862953f, -0.052335956f}, {0.99785892f, -0.065403129f}, +{0.99691733f, -0.078459096f}, {0.99580493f, -0.091501619f}, +{0.99452190f, -0.10452846f}, {0.99306846f, -0.11753740f}, +{0.99144486f, -0.13052619f}, {0.98965139f, -0.14349262f}, +{0.98768834f, -0.15643447f}, {0.98555606f, -0.16934950f}, +{0.98325491f, -0.18223553f}, {0.98078528f, -0.19509032f}, +{0.97814760f, -0.20791169f}, {0.97534232f, -0.22069744f}, +{0.97236992f, -0.23344536f}, {0.96923091f, -0.24615329f}, +{0.96592583f, -0.25881905f}, {0.96245524f, -0.27144045f}, +{0.95881973f, -0.28401534f}, {0.95501994f, -0.29654157f}, +{0.95105652f, -0.30901699f}, {0.94693013f, -0.32143947f}, +{0.94264149f, -0.33380686f}, {0.93819134f, -0.34611706f}, +{0.93358043f, -0.35836795f}, {0.92880955f, -0.37055744f}, +{0.92387953f, -0.38268343f}, {0.91879121f, -0.39474386f}, +{0.91354546f, -0.40673664f}, {0.90814317f, -0.41865974f}, +{0.90258528f, -0.43051110f}, {0.89687274f, -0.44228869f}, +{0.89100652f, -0.45399050f}, {0.88498764f, -0.46561452f}, +{0.87881711f, -0.47715876f}, {0.87249601f, -0.48862124f}, +{0.86602540f, -0.50000000f}, {0.85940641f, -0.51129309f}, +{0.85264016f, -0.52249856f}, {0.84572782f, -0.53361452f}, +{0.83867057f, -0.54463904f}, {0.83146961f, -0.55557023f}, +{0.82412619f, -0.56640624f}, {0.81664156f, -0.57714519f}, +{0.80901699f, -0.58778525f}, {0.80125381f, -0.59832460f}, +{0.79335334f, -0.60876143f}, {0.78531693f, -0.61909395f}, +{0.77714596f, -0.62932039f}, {0.76884183f, -0.63943900f}, +{0.76040597f, -0.64944805f}, {0.75183981f, -0.65934582f}, +{0.74314483f, -0.66913061f}, {0.73432251f, -0.67880075f}, +{0.72537437f, -0.68835458f}, {0.71630194f, -0.69779046f}, +{0.70710678f, -0.70710678f}, {0.69779046f, -0.71630194f}, +{0.68835458f, -0.72537437f}, {0.67880075f, -0.73432251f}, +{0.66913061f, -0.74314483f}, {0.65934582f, -0.75183981f}, +{0.64944805f, -0.76040597f}, {0.63943900f, -0.76884183f}, +{0.62932039f, -0.77714596f}, {0.61909395f, -0.78531693f}, +{0.60876143f, -0.79335334f}, {0.59832460f, -0.80125381f}, +{0.58778525f, -0.80901699f}, {0.57714519f, -0.81664156f}, +{0.56640624f, -0.82412619f}, {0.55557023f, -0.83146961f}, +{0.54463904f, -0.83867057f}, {0.53361452f, -0.84572782f}, +{0.52249856f, -0.85264016f}, {0.51129309f, -0.85940641f}, +{0.50000000f, -0.86602540f}, {0.48862124f, -0.87249601f}, +{0.47715876f, -0.87881711f}, {0.46561452f, -0.88498764f}, +{0.45399050f, -0.89100652f}, {0.44228869f, -0.89687274f}, +{0.43051110f, -0.90258528f}, {0.41865974f, -0.90814317f}, +{0.40673664f, -0.91354546f}, {0.39474386f, -0.91879121f}, +{0.38268343f, -0.92387953f}, {0.37055744f, -0.92880955f}, +{0.35836795f, -0.93358043f}, {0.34611706f, -0.93819134f}, +{0.33380686f, -0.94264149f}, {0.32143947f, -0.94693013f}, +{0.30901699f, -0.95105652f}, {0.29654157f, -0.95501994f}, +{0.28401534f, -0.95881973f}, {0.27144045f, -0.96245524f}, +{0.25881905f, -0.96592583f}, {0.24615329f, -0.96923091f}, +{0.23344536f, -0.97236992f}, {0.22069744f, -0.97534232f}, +{0.20791169f, -0.97814760f}, {0.19509032f, -0.98078528f}, +{0.18223553f, -0.98325491f}, {0.16934950f, -0.98555606f}, +{0.15643447f, -0.98768834f}, {0.14349262f, -0.98965139f}, +{0.13052619f, -0.99144486f}, {0.11753740f, -0.99306846f}, +{0.10452846f, -0.99452190f}, {0.091501619f, -0.99580493f}, +{0.078459096f, -0.99691733f}, {0.065403129f, -0.99785892f}, +{0.052335956f, -0.99862953f}, {0.039259816f, -0.99922904f}, +{0.026176948f, -0.99965732f}, {0.013089596f, -0.99991433f}, +{6.1230318e-17f, -1.0000000f}, {-0.013089596f, -0.99991433f}, +{-0.026176948f, -0.99965732f}, {-0.039259816f, -0.99922904f}, +{-0.052335956f, -0.99862953f}, {-0.065403129f, -0.99785892f}, +{-0.078459096f, -0.99691733f}, {-0.091501619f, -0.99580493f}, +{-0.10452846f, -0.99452190f}, {-0.11753740f, -0.99306846f}, +{-0.13052619f, -0.99144486f}, {-0.14349262f, -0.98965139f}, +{-0.15643447f, -0.98768834f}, {-0.16934950f, -0.98555606f}, +{-0.18223553f, -0.98325491f}, {-0.19509032f, -0.98078528f}, +{-0.20791169f, -0.97814760f}, {-0.22069744f, -0.97534232f}, +{-0.23344536f, -0.97236992f}, {-0.24615329f, -0.96923091f}, +{-0.25881905f, -0.96592583f}, {-0.27144045f, -0.96245524f}, +{-0.28401534f, -0.95881973f}, {-0.29654157f, -0.95501994f}, +{-0.30901699f, -0.95105652f}, {-0.32143947f, -0.94693013f}, +{-0.33380686f, -0.94264149f}, {-0.34611706f, -0.93819134f}, +{-0.35836795f, -0.93358043f}, {-0.37055744f, -0.92880955f}, +{-0.38268343f, -0.92387953f}, {-0.39474386f, -0.91879121f}, +{-0.40673664f, -0.91354546f}, {-0.41865974f, -0.90814317f}, +{-0.43051110f, -0.90258528f}, {-0.44228869f, -0.89687274f}, +{-0.45399050f, -0.89100652f}, {-0.46561452f, -0.88498764f}, +{-0.47715876f, -0.87881711f}, {-0.48862124f, -0.87249601f}, +{-0.50000000f, -0.86602540f}, {-0.51129309f, -0.85940641f}, +{-0.52249856f, -0.85264016f}, {-0.53361452f, -0.84572782f}, +{-0.54463904f, -0.83867057f}, {-0.55557023f, -0.83146961f}, +{-0.56640624f, -0.82412619f}, {-0.57714519f, -0.81664156f}, +{-0.58778525f, -0.80901699f}, {-0.59832460f, -0.80125381f}, +{-0.60876143f, -0.79335334f}, {-0.61909395f, -0.78531693f}, +{-0.62932039f, -0.77714596f}, {-0.63943900f, -0.76884183f}, +{-0.64944805f, -0.76040597f}, {-0.65934582f, -0.75183981f}, +{-0.66913061f, -0.74314483f}, {-0.67880075f, -0.73432251f}, +{-0.68835458f, -0.72537437f}, {-0.69779046f, -0.71630194f}, +{-0.70710678f, -0.70710678f}, {-0.71630194f, -0.69779046f}, +{-0.72537437f, -0.68835458f}, {-0.73432251f, -0.67880075f}, +{-0.74314483f, -0.66913061f}, {-0.75183981f, -0.65934582f}, +{-0.76040597f, -0.64944805f}, {-0.76884183f, -0.63943900f}, +{-0.77714596f, -0.62932039f}, {-0.78531693f, -0.61909395f}, +{-0.79335334f, -0.60876143f}, {-0.80125381f, -0.59832460f}, +{-0.80901699f, -0.58778525f}, {-0.81664156f, -0.57714519f}, +{-0.82412619f, -0.56640624f}, {-0.83146961f, -0.55557023f}, +{-0.83867057f, -0.54463904f}, {-0.84572782f, -0.53361452f}, +{-0.85264016f, -0.52249856f}, {-0.85940641f, -0.51129309f}, +{-0.86602540f, -0.50000000f}, {-0.87249601f, -0.48862124f}, +{-0.87881711f, -0.47715876f}, {-0.88498764f, -0.46561452f}, +{-0.89100652f, -0.45399050f}, {-0.89687274f, -0.44228869f}, +{-0.90258528f, -0.43051110f}, {-0.90814317f, -0.41865974f}, +{-0.91354546f, -0.40673664f}, {-0.91879121f, -0.39474386f}, +{-0.92387953f, -0.38268343f}, {-0.92880955f, -0.37055744f}, +{-0.93358043f, -0.35836795f}, {-0.93819134f, -0.34611706f}, +{-0.94264149f, -0.33380686f}, {-0.94693013f, -0.32143947f}, +{-0.95105652f, -0.30901699f}, {-0.95501994f, -0.29654157f}, +{-0.95881973f, -0.28401534f}, {-0.96245524f, -0.27144045f}, +{-0.96592583f, -0.25881905f}, {-0.96923091f, -0.24615329f}, +{-0.97236992f, -0.23344536f}, {-0.97534232f, -0.22069744f}, +{-0.97814760f, -0.20791169f}, {-0.98078528f, -0.19509032f}, +{-0.98325491f, -0.18223553f}, {-0.98555606f, -0.16934950f}, +{-0.98768834f, -0.15643447f}, {-0.98965139f, -0.14349262f}, +{-0.99144486f, -0.13052619f}, {-0.99306846f, -0.11753740f}, +{-0.99452190f, -0.10452846f}, {-0.99580493f, -0.091501619f}, +{-0.99691733f, -0.078459096f}, {-0.99785892f, -0.065403129f}, +{-0.99862953f, -0.052335956f}, {-0.99922904f, -0.039259816f}, +{-0.99965732f, -0.026176948f}, {-0.99991433f, -0.013089596f}, +{-1.0000000f, -1.2246064e-16f}, {-0.99991433f, 0.013089596f}, +{-0.99965732f, 0.026176948f}, {-0.99922904f, 0.039259816f}, +{-0.99862953f, 0.052335956f}, {-0.99785892f, 0.065403129f}, +{-0.99691733f, 0.078459096f}, {-0.99580493f, 0.091501619f}, +{-0.99452190f, 0.10452846f}, {-0.99306846f, 0.11753740f}, +{-0.99144486f, 0.13052619f}, {-0.98965139f, 0.14349262f}, +{-0.98768834f, 0.15643447f}, {-0.98555606f, 0.16934950f}, +{-0.98325491f, 0.18223553f}, {-0.98078528f, 0.19509032f}, +{-0.97814760f, 0.20791169f}, {-0.97534232f, 0.22069744f}, +{-0.97236992f, 0.23344536f}, {-0.96923091f, 0.24615329f}, +{-0.96592583f, 0.25881905f}, {-0.96245524f, 0.27144045f}, +{-0.95881973f, 0.28401534f}, {-0.95501994f, 0.29654157f}, +{-0.95105652f, 0.30901699f}, {-0.94693013f, 0.32143947f}, +{-0.94264149f, 0.33380686f}, {-0.93819134f, 0.34611706f}, +{-0.93358043f, 0.35836795f}, {-0.92880955f, 0.37055744f}, +{-0.92387953f, 0.38268343f}, {-0.91879121f, 0.39474386f}, +{-0.91354546f, 0.40673664f}, {-0.90814317f, 0.41865974f}, +{-0.90258528f, 0.43051110f}, {-0.89687274f, 0.44228869f}, +{-0.89100652f, 0.45399050f}, {-0.88498764f, 0.46561452f}, +{-0.87881711f, 0.47715876f}, {-0.87249601f, 0.48862124f}, +{-0.86602540f, 0.50000000f}, {-0.85940641f, 0.51129309f}, +{-0.85264016f, 0.52249856f}, {-0.84572782f, 0.53361452f}, +{-0.83867057f, 0.54463904f}, {-0.83146961f, 0.55557023f}, +{-0.82412619f, 0.56640624f}, {-0.81664156f, 0.57714519f}, +{-0.80901699f, 0.58778525f}, {-0.80125381f, 0.59832460f}, +{-0.79335334f, 0.60876143f}, {-0.78531693f, 0.61909395f}, +{-0.77714596f, 0.62932039f}, {-0.76884183f, 0.63943900f}, +{-0.76040597f, 0.64944805f}, {-0.75183981f, 0.65934582f}, +{-0.74314483f, 0.66913061f}, {-0.73432251f, 0.67880075f}, +{-0.72537437f, 0.68835458f}, {-0.71630194f, 0.69779046f}, +{-0.70710678f, 0.70710678f}, {-0.69779046f, 0.71630194f}, +{-0.68835458f, 0.72537437f}, {-0.67880075f, 0.73432251f}, +{-0.66913061f, 0.74314483f}, {-0.65934582f, 0.75183981f}, +{-0.64944805f, 0.76040597f}, {-0.63943900f, 0.76884183f}, +{-0.62932039f, 0.77714596f}, {-0.61909395f, 0.78531693f}, +{-0.60876143f, 0.79335334f}, {-0.59832460f, 0.80125381f}, +{-0.58778525f, 0.80901699f}, {-0.57714519f, 0.81664156f}, +{-0.56640624f, 0.82412619f}, {-0.55557023f, 0.83146961f}, +{-0.54463904f, 0.83867057f}, {-0.53361452f, 0.84572782f}, +{-0.52249856f, 0.85264016f}, {-0.51129309f, 0.85940641f}, +{-0.50000000f, 0.86602540f}, {-0.48862124f, 0.87249601f}, +{-0.47715876f, 0.87881711f}, {-0.46561452f, 0.88498764f}, +{-0.45399050f, 0.89100652f}, {-0.44228869f, 0.89687274f}, +{-0.43051110f, 0.90258528f}, {-0.41865974f, 0.90814317f}, +{-0.40673664f, 0.91354546f}, {-0.39474386f, 0.91879121f}, +{-0.38268343f, 0.92387953f}, {-0.37055744f, 0.92880955f}, +{-0.35836795f, 0.93358043f}, {-0.34611706f, 0.93819134f}, +{-0.33380686f, 0.94264149f}, {-0.32143947f, 0.94693013f}, +{-0.30901699f, 0.95105652f}, {-0.29654157f, 0.95501994f}, +{-0.28401534f, 0.95881973f}, {-0.27144045f, 0.96245524f}, +{-0.25881905f, 0.96592583f}, {-0.24615329f, 0.96923091f}, +{-0.23344536f, 0.97236992f}, {-0.22069744f, 0.97534232f}, +{-0.20791169f, 0.97814760f}, {-0.19509032f, 0.98078528f}, +{-0.18223553f, 0.98325491f}, {-0.16934950f, 0.98555606f}, +{-0.15643447f, 0.98768834f}, {-0.14349262f, 0.98965139f}, +{-0.13052619f, 0.99144486f}, {-0.11753740f, 0.99306846f}, +{-0.10452846f, 0.99452190f}, {-0.091501619f, 0.99580493f}, +{-0.078459096f, 0.99691733f}, {-0.065403129f, 0.99785892f}, +{-0.052335956f, 0.99862953f}, {-0.039259816f, 0.99922904f}, +{-0.026176948f, 0.99965732f}, {-0.013089596f, 0.99991433f}, +{-1.8369095e-16f, 1.0000000f}, {0.013089596f, 0.99991433f}, +{0.026176948f, 0.99965732f}, {0.039259816f, 0.99922904f}, +{0.052335956f, 0.99862953f}, {0.065403129f, 0.99785892f}, +{0.078459096f, 0.99691733f}, {0.091501619f, 0.99580493f}, +{0.10452846f, 0.99452190f}, {0.11753740f, 0.99306846f}, +{0.13052619f, 0.99144486f}, {0.14349262f, 0.98965139f}, +{0.15643447f, 0.98768834f}, {0.16934950f, 0.98555606f}, +{0.18223553f, 0.98325491f}, {0.19509032f, 0.98078528f}, +{0.20791169f, 0.97814760f}, {0.22069744f, 0.97534232f}, +{0.23344536f, 0.97236992f}, {0.24615329f, 0.96923091f}, +{0.25881905f, 0.96592583f}, {0.27144045f, 0.96245524f}, +{0.28401534f, 0.95881973f}, {0.29654157f, 0.95501994f}, +{0.30901699f, 0.95105652f}, {0.32143947f, 0.94693013f}, +{0.33380686f, 0.94264149f}, {0.34611706f, 0.93819134f}, +{0.35836795f, 0.93358043f}, {0.37055744f, 0.92880955f}, +{0.38268343f, 0.92387953f}, {0.39474386f, 0.91879121f}, +{0.40673664f, 0.91354546f}, {0.41865974f, 0.90814317f}, +{0.43051110f, 0.90258528f}, {0.44228869f, 0.89687274f}, +{0.45399050f, 0.89100652f}, {0.46561452f, 0.88498764f}, +{0.47715876f, 0.87881711f}, {0.48862124f, 0.87249601f}, +{0.50000000f, 0.86602540f}, {0.51129309f, 0.85940641f}, +{0.52249856f, 0.85264016f}, {0.53361452f, 0.84572782f}, +{0.54463904f, 0.83867057f}, {0.55557023f, 0.83146961f}, +{0.56640624f, 0.82412619f}, {0.57714519f, 0.81664156f}, +{0.58778525f, 0.80901699f}, {0.59832460f, 0.80125381f}, +{0.60876143f, 0.79335334f}, {0.61909395f, 0.78531693f}, +{0.62932039f, 0.77714596f}, {0.63943900f, 0.76884183f}, +{0.64944805f, 0.76040597f}, {0.65934582f, 0.75183981f}, +{0.66913061f, 0.74314483f}, {0.67880075f, 0.73432251f}, +{0.68835458f, 0.72537437f}, {0.69779046f, 0.71630194f}, +{0.70710678f, 0.70710678f}, {0.71630194f, 0.69779046f}, +{0.72537437f, 0.68835458f}, {0.73432251f, 0.67880075f}, +{0.74314483f, 0.66913061f}, {0.75183981f, 0.65934582f}, +{0.76040597f, 0.64944805f}, {0.76884183f, 0.63943900f}, +{0.77714596f, 0.62932039f}, {0.78531693f, 0.61909395f}, +{0.79335334f, 0.60876143f}, {0.80125381f, 0.59832460f}, +{0.80901699f, 0.58778525f}, {0.81664156f, 0.57714519f}, +{0.82412619f, 0.56640624f}, {0.83146961f, 0.55557023f}, +{0.83867057f, 0.54463904f}, {0.84572782f, 0.53361452f}, +{0.85264016f, 0.52249856f}, {0.85940641f, 0.51129309f}, +{0.86602540f, 0.50000000f}, {0.87249601f, 0.48862124f}, +{0.87881711f, 0.47715876f}, {0.88498764f, 0.46561452f}, +{0.89100652f, 0.45399050f}, {0.89687274f, 0.44228869f}, +{0.90258528f, 0.43051110f}, {0.90814317f, 0.41865974f}, +{0.91354546f, 0.40673664f}, {0.91879121f, 0.39474386f}, +{0.92387953f, 0.38268343f}, {0.92880955f, 0.37055744f}, +{0.93358043f, 0.35836795f}, {0.93819134f, 0.34611706f}, +{0.94264149f, 0.33380686f}, {0.94693013f, 0.32143947f}, +{0.95105652f, 0.30901699f}, {0.95501994f, 0.29654157f}, +{0.95881973f, 0.28401534f}, {0.96245524f, 0.27144045f}, +{0.96592583f, 0.25881905f}, {0.96923091f, 0.24615329f}, +{0.97236992f, 0.23344536f}, {0.97534232f, 0.22069744f}, +{0.97814760f, 0.20791169f}, {0.98078528f, 0.19509032f}, +{0.98325491f, 0.18223553f}, {0.98555606f, 0.16934950f}, +{0.98768834f, 0.15643447f}, {0.98965139f, 0.14349262f}, +{0.99144486f, 0.13052619f}, {0.99306846f, 0.11753740f}, +{0.99452190f, 0.10452846f}, {0.99580493f, 0.091501619f}, +{0.99691733f, 0.078459096f}, {0.99785892f, 0.065403129f}, +{0.99862953f, 0.052335956f}, {0.99922904f, 0.039259816f}, +{0.99965732f, 0.026176948f}, {0.99991433f, 0.013089596f}, +}; +#ifndef FFT_BITREV480 +#define FFT_BITREV480 +static const opus_int16 fft_bitrev480[480] = { +0, 120, 240, 360, 30, 150, 270, 390, 60, 180, 300, 420, 90, 210, 330, +450, 15, 135, 255, 375, 45, 165, 285, 405, 75, 195, 315, 435, 105, 225, +345, 465, 5, 125, 245, 365, 35, 155, 275, 395, 65, 185, 305, 425, 95, +215, 335, 455, 20, 140, 260, 380, 50, 170, 290, 410, 80, 200, 320, 440, +110, 230, 350, 470, 10, 130, 250, 370, 40, 160, 280, 400, 70, 190, 310, +430, 100, 220, 340, 460, 25, 145, 265, 385, 55, 175, 295, 415, 85, 205, +325, 445, 115, 235, 355, 475, 1, 121, 241, 361, 31, 151, 271, 391, 61, +181, 301, 421, 91, 211, 331, 451, 16, 136, 256, 376, 46, 166, 286, 406, +76, 196, 316, 436, 106, 226, 346, 466, 6, 126, 246, 366, 36, 156, 276, +396, 66, 186, 306, 426, 96, 216, 336, 456, 21, 141, 261, 381, 51, 171, +291, 411, 81, 201, 321, 441, 111, 231, 351, 471, 11, 131, 251, 371, 41, +161, 281, 401, 71, 191, 311, 431, 101, 221, 341, 461, 26, 146, 266, 386, +56, 176, 296, 416, 86, 206, 326, 446, 116, 236, 356, 476, 2, 122, 242, +362, 32, 152, 272, 392, 62, 182, 302, 422, 92, 212, 332, 452, 17, 137, +257, 377, 47, 167, 287, 407, 77, 197, 317, 437, 107, 227, 347, 467, 7, +127, 247, 367, 37, 157, 277, 397, 67, 187, 307, 427, 97, 217, 337, 457, +22, 142, 262, 382, 52, 172, 292, 412, 82, 202, 322, 442, 112, 232, 352, +472, 12, 132, 252, 372, 42, 162, 282, 402, 72, 192, 312, 432, 102, 222, +342, 462, 27, 147, 267, 387, 57, 177, 297, 417, 87, 207, 327, 447, 117, +237, 357, 477, 3, 123, 243, 363, 33, 153, 273, 393, 63, 183, 303, 423, +93, 213, 333, 453, 18, 138, 258, 378, 48, 168, 288, 408, 78, 198, 318, +438, 108, 228, 348, 468, 8, 128, 248, 368, 38, 158, 278, 398, 68, 188, +308, 428, 98, 218, 338, 458, 23, 143, 263, 383, 53, 173, 293, 413, 83, +203, 323, 443, 113, 233, 353, 473, 13, 133, 253, 373, 43, 163, 283, 403, +73, 193, 313, 433, 103, 223, 343, 463, 28, 148, 268, 388, 58, 178, 298, +418, 88, 208, 328, 448, 118, 238, 358, 478, 4, 124, 244, 364, 34, 154, +274, 394, 64, 184, 304, 424, 94, 214, 334, 454, 19, 139, 259, 379, 49, +169, 289, 409, 79, 199, 319, 439, 109, 229, 349, 469, 9, 129, 249, 369, +39, 159, 279, 399, 69, 189, 309, 429, 99, 219, 339, 459, 24, 144, 264, +384, 54, 174, 294, 414, 84, 204, 324, 444, 114, 234, 354, 474, 14, 134, +254, 374, 44, 164, 284, 404, 74, 194, 314, 434, 104, 224, 344, 464, 29, +149, 269, 389, 59, 179, 299, 419, 89, 209, 329, 449, 119, 239, 359, 479, +}; +#endif + +#ifndef FFT_BITREV240 +#define FFT_BITREV240 +static const opus_int16 fft_bitrev240[240] = { +0, 60, 120, 180, 15, 75, 135, 195, 30, 90, 150, 210, 45, 105, 165, +225, 5, 65, 125, 185, 20, 80, 140, 200, 35, 95, 155, 215, 50, 110, +170, 230, 10, 70, 130, 190, 25, 85, 145, 205, 40, 100, 160, 220, 55, +115, 175, 235, 1, 61, 121, 181, 16, 76, 136, 196, 31, 91, 151, 211, +46, 106, 166, 226, 6, 66, 126, 186, 21, 81, 141, 201, 36, 96, 156, +216, 51, 111, 171, 231, 11, 71, 131, 191, 26, 86, 146, 206, 41, 101, +161, 221, 56, 116, 176, 236, 2, 62, 122, 182, 17, 77, 137, 197, 32, +92, 152, 212, 47, 107, 167, 227, 7, 67, 127, 187, 22, 82, 142, 202, +37, 97, 157, 217, 52, 112, 172, 232, 12, 72, 132, 192, 27, 87, 147, +207, 42, 102, 162, 222, 57, 117, 177, 237, 3, 63, 123, 183, 18, 78, +138, 198, 33, 93, 153, 213, 48, 108, 168, 228, 8, 68, 128, 188, 23, +83, 143, 203, 38, 98, 158, 218, 53, 113, 173, 233, 13, 73, 133, 193, +28, 88, 148, 208, 43, 103, 163, 223, 58, 118, 178, 238, 4, 64, 124, +184, 19, 79, 139, 199, 34, 94, 154, 214, 49, 109, 169, 229, 9, 69, +129, 189, 24, 84, 144, 204, 39, 99, 159, 219, 54, 114, 174, 234, 14, +74, 134, 194, 29, 89, 149, 209, 44, 104, 164, 224, 59, 119, 179, 239, +}; +#endif + +#ifndef FFT_BITREV120 +#define FFT_BITREV120 +static const opus_int16 fft_bitrev120[120] = { +0, 30, 60, 90, 15, 45, 75, 105, 5, 35, 65, 95, 20, 50, 80, +110, 10, 40, 70, 100, 25, 55, 85, 115, 1, 31, 61, 91, 16, 46, +76, 106, 6, 36, 66, 96, 21, 51, 81, 111, 11, 41, 71, 101, 26, +56, 86, 116, 2, 32, 62, 92, 17, 47, 77, 107, 7, 37, 67, 97, +22, 52, 82, 112, 12, 42, 72, 102, 27, 57, 87, 117, 3, 33, 63, +93, 18, 48, 78, 108, 8, 38, 68, 98, 23, 53, 83, 113, 13, 43, +73, 103, 28, 58, 88, 118, 4, 34, 64, 94, 19, 49, 79, 109, 9, +39, 69, 99, 24, 54, 84, 114, 14, 44, 74, 104, 29, 59, 89, 119, +}; +#endif + +#ifndef FFT_BITREV60 +#define FFT_BITREV60 +static const opus_int16 fft_bitrev60[60] = { +0, 15, 30, 45, 5, 20, 35, 50, 10, 25, 40, 55, 1, 16, 31, +46, 6, 21, 36, 51, 11, 26, 41, 56, 2, 17, 32, 47, 7, 22, +37, 52, 12, 27, 42, 57, 3, 18, 33, 48, 8, 23, 38, 53, 13, +28, 43, 58, 4, 19, 34, 49, 9, 24, 39, 54, 14, 29, 44, 59, +}; +#endif + +#ifndef FFT_STATE48000_960_0 +#define FFT_STATE48000_960_0 +static const kiss_fft_state fft_state48000_960_0 = { +480, /* nfft */ +0.002083333f, /* scale */ +-1, /* shift */ +{4, 120, 4, 30, 2, 15, 3, 5, 5, 1, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev480, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +}; +#endif + +#ifndef FFT_STATE48000_960_1 +#define FFT_STATE48000_960_1 +static const kiss_fft_state fft_state48000_960_1 = { +240, /* nfft */ +0.004166667f, /* scale */ +1, /* shift */ +{4, 60, 4, 15, 3, 5, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev240, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +}; +#endif + +#ifndef FFT_STATE48000_960_2 +#define FFT_STATE48000_960_2 +static const kiss_fft_state fft_state48000_960_2 = { +120, /* nfft */ +0.008333333f, /* scale */ +2, /* shift */ +{4, 30, 2, 15, 3, 5, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev120, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +}; +#endif + +#ifndef FFT_STATE48000_960_3 +#define FFT_STATE48000_960_3 +static const kiss_fft_state fft_state48000_960_3 = { +60, /* nfft */ +0.016666667f, /* scale */ +3, /* shift */ +{4, 15, 3, 5, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev60, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +}; +#endif + +#endif + +#ifndef MDCT_TWIDDLES960 +#define MDCT_TWIDDLES960 +static const opus_val16 mdct_twiddles960[481] = { +1.0000000f, 0.99999465f, 0.99997858f, 0.99995181f, 0.99991433f, +0.99986614f, 0.99980724f, 0.99973764f, 0.99965732f, 0.99956631f, +0.99946459f, 0.99935216f, 0.99922904f, 0.99909521f, 0.99895068f, +0.99879546f, 0.99862953f, 0.99845292f, 0.99826561f, 0.99806761f, +0.99785892f, 0.99763955f, 0.99740949f, 0.99716875f, 0.99691733f, +0.99665524f, 0.99638247f, 0.99609903f, 0.99580493f, 0.99550016f, +0.99518473f, 0.99485864f, 0.99452190f, 0.99417450f, 0.99381646f, +0.99344778f, 0.99306846f, 0.99267850f, 0.99227791f, 0.99186670f, +0.99144486f, 0.99101241f, 0.99056934f, 0.99011566f, 0.98965139f, +0.98917651f, 0.98869104f, 0.98819498f, 0.98768834f, 0.98717112f, +0.98664333f, 0.98610497f, 0.98555606f, 0.98499659f, 0.98442657f, +0.98384600f, 0.98325491f, 0.98265328f, 0.98204113f, 0.98141846f, +0.98078528f, 0.98014159f, 0.97948742f, 0.97882275f, 0.97814760f, +0.97746197f, 0.97676588f, 0.97605933f, 0.97534232f, 0.97461487f, +0.97387698f, 0.97312866f, 0.97236992f, 0.97160077f, 0.97082121f, +0.97003125f, 0.96923091f, 0.96842019f, 0.96759909f, 0.96676764f, +0.96592582f, 0.96507367f, 0.96421118f, 0.96333837f, 0.96245523f, +0.96156180f, 0.96065806f, 0.95974403f, 0.95881973f, 0.95788517f, +0.95694034f, 0.95598526f, 0.95501995f, 0.95404440f, 0.95305864f, +0.95206267f, 0.95105651f, 0.95004016f, 0.94901364f, 0.94797697f, +0.94693013f, 0.94587315f, 0.94480604f, 0.94372882f, 0.94264149f, +0.94154406f, 0.94043656f, 0.93931897f, 0.93819133f, 0.93705365f, +0.93590592f, 0.93474818f, 0.93358042f, 0.93240268f, 0.93121493f, +0.93001722f, 0.92880955f, 0.92759193f, 0.92636438f, 0.92512690f, +0.92387953f, 0.92262225f, 0.92135509f, 0.92007809f, 0.91879121f, +0.91749449f, 0.91618795f, 0.91487161f, 0.91354545f, 0.91220952f, +0.91086382f, 0.90950836f, 0.90814316f, 0.90676824f, 0.90538363f, +0.90398929f, 0.90258528f, 0.90117161f, 0.89974828f, 0.89831532f, +0.89687273f, 0.89542055f, 0.89395877f, 0.89248742f, 0.89100652f, +0.88951606f, 0.88801610f, 0.88650661f, 0.88498764f, 0.88345918f, +0.88192125f, 0.88037390f, 0.87881711f, 0.87725090f, 0.87567531f, +0.87409035f, 0.87249599f, 0.87089232f, 0.86927933f, 0.86765699f, +0.86602540f, 0.86438453f, 0.86273437f, 0.86107503f, 0.85940641f, +0.85772862f, 0.85604161f, 0.85434547f, 0.85264014f, 0.85092572f, +0.84920218f, 0.84746955f, 0.84572781f, 0.84397704f, 0.84221721f, +0.84044838f, 0.83867056f, 0.83688375f, 0.83508799f, 0.83328325f, +0.83146961f, 0.82964704f, 0.82781562f, 0.82597530f, 0.82412620f, +0.82226820f, 0.82040144f, 0.81852589f, 0.81664154f, 0.81474847f, +0.81284665f, 0.81093620f, 0.80901698f, 0.80708914f, 0.80515262f, +0.80320752f, 0.80125378f, 0.79929149f, 0.79732067f, 0.79534125f, +0.79335335f, 0.79135691f, 0.78935204f, 0.78733867f, 0.78531691f, +0.78328674f, 0.78124818f, 0.77920122f, 0.77714595f, 0.77508232f, +0.77301043f, 0.77093026f, 0.76884183f, 0.76674517f, 0.76464026f, +0.76252720f, 0.76040593f, 0.75827656f, 0.75613907f, 0.75399349f, +0.75183978f, 0.74967807f, 0.74750833f, 0.74533054f, 0.74314481f, +0.74095112f, 0.73874950f, 0.73653993f, 0.73432251f, 0.73209718f, +0.72986405f, 0.72762307f, 0.72537438f, 0.72311787f, 0.72085359f, +0.71858162f, 0.71630192f, 0.71401459f, 0.71171956f, 0.70941701f, +0.70710677f, 0.70478900f, 0.70246363f, 0.70013079f, 0.69779041f, +0.69544260f, 0.69308738f, 0.69072466f, 0.68835458f, 0.68597709f, +0.68359229f, 0.68120013f, 0.67880072f, 0.67639404f, 0.67398011f, +0.67155892f, 0.66913059f, 0.66669509f, 0.66425240f, 0.66180265f, +0.65934581f, 0.65688191f, 0.65441092f, 0.65193298f, 0.64944801f, +0.64695613f, 0.64445727f, 0.64195160f, 0.63943902f, 0.63691954f, +0.63439328f, 0.63186019f, 0.62932037f, 0.62677377f, 0.62422055f, +0.62166055f, 0.61909394f, 0.61652065f, 0.61394081f, 0.61135435f, +0.60876139f, 0.60616195f, 0.60355593f, 0.60094349f, 0.59832457f, +0.59569929f, 0.59306758f, 0.59042957f, 0.58778523f, 0.58513460f, +0.58247766f, 0.57981452f, 0.57714518f, 0.57446961f, 0.57178793f, +0.56910013f, 0.56640624f, 0.56370623f, 0.56100023f, 0.55828818f, +0.55557020f, 0.55284627f, 0.55011641f, 0.54738067f, 0.54463901f, +0.54189157f, 0.53913828f, 0.53637921f, 0.53361450f, 0.53084398f, +0.52806787f, 0.52528601f, 0.52249852f, 0.51970543f, 0.51690688f, +0.51410279f, 0.51129310f, 0.50847793f, 0.50565732f, 0.50283139f, +0.49999997f, 0.49716321f, 0.49432122f, 0.49147383f, 0.48862118f, +0.48576340f, 0.48290042f, 0.48003216f, 0.47715876f, 0.47428025f, +0.47139677f, 0.46850813f, 0.46561448f, 0.46271584f, 0.45981235f, +0.45690383f, 0.45399042f, 0.45107214f, 0.44814915f, 0.44522124f, +0.44228868f, 0.43935137f, 0.43640926f, 0.43346247f, 0.43051104f, +0.42755511f, 0.42459449f, 0.42162932f, 0.41865964f, 0.41568558f, +0.41270697f, 0.40972393f, 0.40673661f, 0.40374494f, 0.40074884f, +0.39774844f, 0.39474390f, 0.39173501f, 0.38872193f, 0.38570469f, +0.38268343f, 0.37965796f, 0.37662842f, 0.37359496f, 0.37055739f, +0.36751585f, 0.36447038f, 0.36142122f, 0.35836797f, 0.35531089f, +0.35225000f, 0.34918544f, 0.34611704f, 0.34304493f, 0.33996926f, +0.33688983f, 0.33380680f, 0.33072019f, 0.32763015f, 0.32453650f, +0.32143936f, 0.31833890f, 0.31523503f, 0.31212767f, 0.30901696f, +0.30590306f, 0.30278577f, 0.29966524f, 0.29654150f, 0.29341470f, +0.29028464f, 0.28715147f, 0.28401522f, 0.28087605f, 0.27773376f, +0.27458861f, 0.27144052f, 0.26828940f, 0.26513541f, 0.26197859f, +0.25881907f, 0.25565666f, 0.25249152f, 0.24932367f, 0.24615327f, +0.24298012f, 0.23980436f, 0.23662604f, 0.23344530f, 0.23026206f, +0.22707623f, 0.22388809f, 0.22069744f, 0.21750443f, 0.21430908f, +0.21111156f, 0.20791165f, 0.20470953f, 0.20150520f, 0.19829884f, +0.19509024f, 0.19187955f, 0.18866692f, 0.18545227f, 0.18223552f, +0.17901681f, 0.17579631f, 0.17257380f, 0.16934945f, 0.16612328f, +0.16289546f, 0.15966577f, 0.15643437f, 0.15320141f, 0.14996669f, +0.14673037f, 0.14349260f, 0.14025329f, 0.13701235f, 0.13376995f, +0.13052612f, 0.12728101f, 0.12403442f, 0.12078650f, 0.11753740f, +0.11428693f, 0.11103523f, 0.10778234f, 0.10452842f, 0.10127326f, +0.098017137f, 0.094759842f, 0.091501652f, 0.088242363f, 0.084982129f, +0.081721103f, 0.078459084f, 0.075196224f, 0.071932560f, 0.068668243f, +0.065403073f, 0.062137201f, 0.058870665f, 0.055603617f, 0.052335974f, +0.049067651f, 0.045798921f, 0.042529582f, 0.039259788f, 0.035989573f, +0.032719092f, 0.029448142f, 0.026176876f, 0.022905329f, 0.019633657f, +0.016361655f, 0.013089478f, 0.0098171604f, 0.0065449764f, 0.0032724839f, +-4.3711390e-08f, }; +#endif + +static const CELTMode mode48000_960_120 = { +48000, /* Fs */ +120, /* overlap */ +21, /* nbEBands */ +21, /* effEBands */ +{0.85000610f, 0.0000000f, 1.0000000f, 1.0000000f, }, /* preemph */ +eband5ms, /* eBands */ +3, /* maxLM */ +8, /* nbShortMdcts */ +120, /* shortMdctSize */ +11, /* nbAllocVectors */ +band_allocation, /* allocVectors */ +logN400, /* logN */ +window120, /* window */ +{1920, 3, {&fft_state48000_960_0, &fft_state48000_960_1, &fft_state48000_960_2, &fft_state48000_960_3, }, mdct_twiddles960}, /* mdct */ +{392, cache_index50, cache_bits50, cache_caps50}, /* cache */ +}; + +/* List of all the available modes */ +#define TOTAL_MODES 1 +static const CELTMode * const static_mode_list[TOTAL_MODES] = { +&mode48000_960_120, +}; diff --git a/code/opus-1.0.2/celt/vq.c b/code/opus-1.0.2/celt/vq.c new file mode 100644 index 00000000..98a0f36c --- /dev/null +++ b/code/opus-1.0.2/celt/vq.c @@ -0,0 +1,415 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "mathops.h" +#include "cwrs.h" +#include "vq.h" +#include "arch.h" +#include "os_support.h" +#include "bands.h" +#include "rate.h" + +static void exp_rotation1(celt_norm *X, int len, int stride, opus_val16 c, opus_val16 s) +{ + int i; + celt_norm *Xptr; + Xptr = X; + for (i=0;i=0;i--) + { + celt_norm x1, x2; + x1 = Xptr[0]; + x2 = Xptr[stride]; + Xptr[stride] = EXTRACT16(SHR32(MULT16_16(c,x2) + MULT16_16(s,x1), 15)); + *Xptr-- = EXTRACT16(SHR32(MULT16_16(c,x1) - MULT16_16(s,x2), 15)); + } +} + +static void exp_rotation(celt_norm *X, int len, int dir, int stride, int K, int spread) +{ + static const int SPREAD_FACTOR[3]={15,10,5}; + int i; + opus_val16 c, s; + opus_val16 gain, theta; + int stride2=0; + int factor; + + if (2*K>=len || spread==SPREAD_NONE) + return; + factor = SPREAD_FACTOR[spread-1]; + + gain = celt_div((opus_val32)MULT16_16(Q15_ONE,len),(opus_val32)(len+factor*K)); + theta = HALF16(MULT16_16_Q15(gain,gain)); + + c = celt_cos_norm(EXTEND32(theta)); + s = celt_cos_norm(EXTEND32(SUB16(Q15ONE,theta))); /* sin(theta) */ + + if (len>=8*stride) + { + stride2 = 1; + /* This is just a simple (equivalent) way of computing sqrt(len/stride) with rounding. + It's basically incrementing long as (stride2+0.5)^2 < len/stride. */ + while ((stride2*stride2+stride2)*stride + (stride>>2) < len) + stride2++; + } + /*NOTE: As a minor optimization, we could be passing around log2(B), not B, for both this and for + extract_collapse_mask().*/ + len /= stride; + for (i=0;i>1; +#endif + t = VSHR32(Ryy, 2*(k-7)); + g = MULT16_16_P15(celt_rsqrt_norm(t),gain); + + i=0; + do + X[i] = EXTRACT16(PSHR32(MULT16_16(g, iy[i]), k+1)); + while (++i < N); +} + +static unsigned extract_collapse_mask(int *iy, int N, int B) +{ + unsigned collapse_mask; + int N0; + int i; + if (B<=1) + return 1; + /*NOTE: As a minor optimization, we could be passing around log2(B), not B, for both this and for + exp_rotation().*/ + N0 = N/B; + collapse_mask = 0; + i=0; do { + int j; + j=0; do { + collapse_mask |= (iy[i*N0+j]!=0)<0, "alg_quant() needs at least one pulse"); + celt_assert2(N>1, "alg_quant() needs at least two dimensions"); + + ALLOC(y, N, celt_norm); + ALLOC(iy, N, int); + ALLOC(signx, N, opus_val16); + + exp_rotation(X, N, 1, B, K, spread); + + /* Get rid of the sign */ + sum = 0; + j=0; do { + if (X[j]>0) + signx[j]=1; + else { + signx[j]=-1; + X[j]=-X[j]; + } + iy[j] = 0; + y[j] = 0; + } while (++j (N>>1)) + { + opus_val16 rcp; + j=0; do { + sum += X[j]; + } while (++j EPSILON && sum < 64)) +#endif + { + X[0] = QCONST16(1.f,14); + j=1; do + X[j]=0; + while (++j=1, "Allocated too many pulses in the quick pass"); + + /* This should never happen, but just in case it does (e.g. on silence) + we fill the first bin with pulses. */ +#ifdef FIXED_POINT_DEBUG + celt_assert2(pulsesLeft<=N+3, "Not enough pulses in the quick pass"); +#endif + if (pulsesLeft > N+3) + { + opus_val16 tmp = (opus_val16)pulsesLeft; + yy = MAC16_16(yy, tmp, tmp); + yy = MAC16_16(yy, tmp, y[0]); + iy[0] += pulsesLeft; + pulsesLeft=0; + } + + s = 1; + for (i=0;i= best_num/best_den, but that way + we can do it without any division */ + /* OPT: Make sure to use conditional moves here */ + if (MULT16_16(best_den, Rxy) > MULT16_16(Ryy, best_num)) + { + best_den = Ryy; + best_num = Rxy; + best_id = j; + } + } while (++j0, "alg_unquant() needs at least one pulse"); + celt_assert2(N>1, "alg_unquant() needs at least two dimensions"); + ALLOC(iy, N, int); + decode_pulses(iy, N, K, dec); + Ryy = 0; + i=0; + do { + Ryy = MAC16_16(Ryy, iy[i], iy[i]); + } while (++i < N); + normalise_residual(iy, X, N, Ryy, gain); + exp_rotation(X, N, -1, B, K, spread); + collapse_mask = extract_collapse_mask(iy, N, B); + RESTORE_STACK; + return collapse_mask; +} + +void renormalise_vector(celt_norm *X, int N, opus_val16 gain) +{ + int i; +#ifdef FIXED_POINT + int k; +#endif + opus_val32 E = EPSILON; + opus_val16 g; + opus_val32 t; + celt_norm *xptr = X; + for (i=0;i>1; +#endif + t = VSHR32(E, 2*(k-7)); + g = MULT16_16_P15(celt_rsqrt_norm(t),gain); + + xptr = X; + for (i=0;i + *
  1. audio_frame is the audio data in opus_int16 (or float for opus_encode_float())
  2. + *
  3. frame_size is the duration of the frame in samples (per channel)
  4. + *
  5. packet is the byte array to which the compressed data is written
  6. + *
  7. max_packet is the maximum number of bytes that can be written in the packet (4000 bytes is recommended). + * Do not use max_packet to control VBR target bitrate, instead use the #OPUS_SET_BITRATE CTL.
  8. + * + * + * opus_encode() and opus_encode_float() return the number of bytes actually written to the packet. + * The return value can be negative, which indicates that an error has occurred. If the return value + * is 1 byte, then the packet does not need to be transmitted (DTX). + * + * Once the encoder state if no longer needed, it can be destroyed with + * + * @code + * opus_encoder_destroy(enc); + * @endcode + * + * If the encoder was created with opus_encoder_init() rather than opus_encoder_create(), + * then no action is required aside from potentially freeing the memory that was manually + * allocated for it (calling free(enc) for the example above) + * + */ + +/** Opus encoder state. + * This contains the complete state of an Opus encoder. + * It is position independent and can be freely copied. + * @see opus_encoder_create,opus_encoder_init + */ +typedef struct OpusEncoder OpusEncoder; + +/** Gets the size of an OpusEncoder structure. + * @param[in] channels int: Number of channels. + * This must be 1 or 2. + * @returns The size in bytes. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_encoder_get_size(int channels); + +/** + */ + +/** Allocates and initializes an encoder state. + * There are three coding modes: + * + * @ref OPUS_APPLICATION_VOIP gives best quality at a given bitrate for voice + * signals. It enhances the input signal by high-pass filtering and + * emphasizing formants and harmonics. Optionally it includes in-band + * forward error correction to protect against packet loss. Use this + * mode for typical VoIP applications. Because of the enhancement, + * even at high bitrates the output may sound different from the input. + * + * @ref OPUS_APPLICATION_AUDIO gives best quality at a given bitrate for most + * non-voice signals like music. Use this mode for music and mixed + * (music/voice) content, broadcast, and applications requiring less + * than 15 ms of coding delay. + * + * @ref OPUS_APPLICATION_RESTRICTED_LOWDELAY configures low-delay mode that + * disables the speech-optimized mode in exchange for slightly reduced delay. + * This mode can only be set on an newly initialized or freshly reset encoder + * because it changes the codec delay. + * + * This is useful when the caller knows that the speech-optimized modes will not be needed (use with caution). + * @param [in] Fs opus_int32: Sampling rate of input signal (Hz) + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param [in] channels int: Number of channels (1 or 2) in input signal + * @param [in] application int: Coding mode (@ref OPUS_APPLICATION_VOIP/@ref OPUS_APPLICATION_AUDIO/@ref OPUS_APPLICATION_RESTRICTED_LOWDELAY) + * @param [out] error int*: @ref opus_errorcodes + * @note Regardless of the sampling rate and number channels selected, the Opus encoder + * can switch to a lower audio bandwidth or number of channels if the bitrate + * selected is too low. This also means that it is safe to always use 48 kHz stereo input + * and let the encoder optimize the encoding. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusEncoder *opus_encoder_create( + opus_int32 Fs, + int channels, + int application, + int *error +); + +/** Initializes a previously allocated encoder state + * The memory pointed to by st must be at least the size returned by opus_encoder_get_size(). + * This is intended for applications which use their own allocator instead of malloc. + * @see opus_encoder_create(),opus_encoder_get_size() + * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL. + * @param [in] st OpusEncoder*: Encoder state + * @param [in] Fs opus_int32: Sampling rate of input signal (Hz) + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param [in] channels int: Number of channels (1 or 2) in input signal + * @param [in] application int: Coding mode (OPUS_APPLICATION_VOIP/OPUS_APPLICATION_AUDIO/OPUS_APPLICATION_RESTRICTED_LOWDELAY) + * @retval #OPUS_OK Success or @ref opus_errorcodes + */ +OPUS_EXPORT int opus_encoder_init( + OpusEncoder *st, + opus_int32 Fs, + int channels, + int application +) OPUS_ARG_NONNULL(1); + +/** Encodes an Opus frame. + * @param [in] st OpusEncoder*: Encoder state + * @param [in] pcm opus_int16*: Input signal (interleaved if 2 channels). length is frame_size*channels*sizeof(opus_int16) + * @param [in] frame_size int: Number of samples per channel in the + * input signal. + * This must be an Opus frame size for + * the encoder's sampling rate. + * For example, at 48 kHz the permitted + * values are 120, 240, 480, 960, 1920, + * and 2880. + * Passing in a duration of less than + * 10 ms (480 samples at 48 kHz) will + * prevent the encoder from using the LPC + * or hybrid modes. + * @param [out] data unsigned char*: Output payload. + * This must contain storage for at + * least \a max_data_bytes. + * @param [in] max_data_bytes opus_int32: Size of the allocated + * memory for the output + * payload. This may be + * used to impose an upper limit on + * the instant bitrate, but should + * not be used as the only bitrate + * control. Use #OPUS_SET_BITRATE to + * control the bitrate. + * @returns The length of the encoded packet (in bytes) on success or a + * negative error code (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_encode( + OpusEncoder *st, + const opus_int16 *pcm, + int frame_size, + unsigned char *data, + opus_int32 max_data_bytes +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); + +/** Encodes an Opus frame from floating point input. + * @param [in] st OpusEncoder*: Encoder state + * @param [in] pcm float*: Input in float format (interleaved if 2 channels), with a normal range of +/-1.0. + * Samples with a range beyond +/-1.0 are supported but will + * be clipped by decoders using the integer API and should + * only be used if it is known that the far end supports + * extended dynamic range. + * length is frame_size*channels*sizeof(float) + * @param [in] frame_size int: Number of samples per channel in the + * input signal. + * This must be an Opus frame size for + * the encoder's sampling rate. + * For example, at 48 kHz the permitted + * values are 120, 240, 480, 960, 1920, + * and 2880. + * Passing in a duration of less than + * 10 ms (480 samples at 48 kHz) will + * prevent the encoder from using the LPC + * or hybrid modes. + * @param [out] data unsigned char*: Output payload. + * This must contain storage for at + * least \a max_data_bytes. + * @param [in] max_data_bytes opus_int32: Size of the allocated + * memory for the output + * payload. This may be + * used to impose an upper limit on + * the instant bitrate, but should + * not be used as the only bitrate + * control. Use #OPUS_SET_BITRATE to + * control the bitrate. + * @returns The length of the encoded packet (in bytes) on success or a + * negative error code (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_encode_float( + OpusEncoder *st, + const float *pcm, + int frame_size, + unsigned char *data, + opus_int32 max_data_bytes +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); + +/** Frees an OpusEncoder allocated by opus_encoder_create(). + * @param[in] st OpusEncoder*: State to be freed. + */ +OPUS_EXPORT void opus_encoder_destroy(OpusEncoder *st); + +/** Perform a CTL function on an Opus encoder. + * + * Generally the request and subsequent arguments are generated + * by a convenience macro. + * @param st OpusEncoder*: Encoder state. + * @param request This and all remaining parameters should be replaced by one + * of the convenience macros in @ref opus_genericctls or + * @ref opus_encoderctls. + * @see opus_genericctls + * @see opus_encoderctls + */ +OPUS_EXPORT int opus_encoder_ctl(OpusEncoder *st, int request, ...) OPUS_ARG_NONNULL(1); +/**@}*/ + +/** @defgroup opus_decoder Opus Decoder + * @{ + * + * @brief This page describes the process and functions used to decode Opus. + * + * The decoding process also starts with creating a decoder + * state. This can be done with: + * @code + * int error; + * OpusDecoder *dec; + * dec = opus_decoder_create(Fs, channels, &error); + * @endcode + * where + * @li Fs is the sampling rate and must be 8000, 12000, 16000, 24000, or 48000 + * @li channels is the number of channels (1 or 2) + * @li error will hold the error code in case of failure (or #OPUS_OK on success) + * @li the return value is a newly created decoder state to be used for decoding + * + * While opus_decoder_create() allocates memory for the state, it's also possible + * to initialize pre-allocated memory: + * @code + * int size; + * int error; + * OpusDecoder *dec; + * size = opus_decoder_get_size(channels); + * dec = malloc(size); + * error = opus_decoder_init(dec, Fs, channels); + * @endcode + * where opus_decoder_get_size() returns the required size for the decoder state. Note that + * future versions of this code may change the size, so no assuptions should be made about it. + * + * The decoder state is always continuous in memory and only a shallow copy is sufficient + * to copy it (e.g. memcpy()) + * + * To decode a frame, opus_decode() or opus_decode_float() must be called with a packet of compressed audio data: + * @code + * frame_size = opus_decode(dec, packet, len, decoded, max_size, 0); + * @endcode + * where + * + * @li packet is the byte array containing the compressed data + * @li len is the exact number of bytes contained in the packet + * @li decoded is the decoded audio data in opus_int16 (or float for opus_decode_float()) + * @li max_size is the max duration of the frame in samples (per channel) that can fit into the decoded_frame array + * + * opus_decode() and opus_decode_float() return the number of samples (per channel) decoded from the packet. + * If that value is negative, then an error has occurred. This can occur if the packet is corrupted or if the audio + * buffer is too small to hold the decoded audio. + * + * Opus is a stateful codec with overlapping blocks and as a result Opus + * packets are not coded independently of each other. Packets must be + * passed into the decoder serially and in the correct order for a correct + * decode. Lost packets can be replaced with loss concealment by calling + * the decoder with a null pointer and zero length for the missing packet. + * + * A single codec state may only be accessed from a single thread at + * a time and any required locking must be performed by the caller. Separate + * streams must be decoded with separate decoder states and can be decoded + * in parallel unless the library was compiled with NONTHREADSAFE_PSEUDOSTACK + * defined. + * + */ + +/** Opus decoder state. + * This contains the complete state of an Opus decoder. + * It is position independent and can be freely copied. + * @see opus_decoder_create,opus_decoder_init + */ +typedef struct OpusDecoder OpusDecoder; + +/** Gets the size of an OpusDecoder structure. + * @param [in] channels int: Number of channels. + * This must be 1 or 2. + * @returns The size in bytes. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decoder_get_size(int channels); + +/** Allocates and initializes a decoder state. + * @param [in] Fs opus_int32: Sample rate to decode at (Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param [in] channels int: Number of channels (1 or 2) to decode + * @param [out] error int*: #OPUS_OK Success or @ref opus_errorcodes + * + * Internally Opus stores data at 48000 Hz, so that should be the default + * value for Fs. However, the decoder can efficiently decode to buffers + * at 8, 12, 16, and 24 kHz so if for some reason the caller cannot use + * data at the full sample rate, or knows the compressed data doesn't + * use the full frequency range, it can request decoding at a reduced + * rate. Likewise, the decoder is capable of filling in either mono or + * interleaved stereo pcm buffers, at the caller's request. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusDecoder *opus_decoder_create( + opus_int32 Fs, + int channels, + int *error +); + +/** Initializes a previously allocated decoder state. + * The state must be at least the size returned by opus_decoder_get_size(). + * This is intended for applications which use their own allocator instead of malloc. @see opus_decoder_create,opus_decoder_get_size + * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL. + * @param [in] st OpusDecoder*: Decoder state. + * @param [in] Fs opus_int32: Sampling rate to decode to (Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param [in] channels int: Number of channels (1 or 2) to decode + * @retval #OPUS_OK Success or @ref opus_errorcodes + */ +OPUS_EXPORT int opus_decoder_init( + OpusDecoder *st, + opus_int32 Fs, + int channels +) OPUS_ARG_NONNULL(1); + +/** Decode an Opus packet. + * @param [in] st OpusDecoder*: Decoder state + * @param [in] data char*: Input payload. Use a NULL pointer to indicate packet loss + * @param [in] len opus_int32: Number of bytes in payload* + * @param [out] pcm opus_int16*: Output signal (interleaved if 2 channels). length + * is frame_size*channels*sizeof(opus_int16) + * @param [in] frame_size Number of samples per channel of available space in \a pcm. + * If this is less than the maximum packet duration (120ms; 5760 for 48kHz), this function will + * not be capable of decoding some packets. In the case of PLC (data==NULL) or FEC (decode_fec=1), + * then frame_size needs to be exactly the duration of audio that is missing, otherwise the + * decoder will not be in the optimal state to decode the next incoming packet. For the PLC and + * FEC cases, frame_size must be a multiple of 2.5 ms. + * @param [in] decode_fec int: Flag (0 or 1) to request that any in-band forward error correction data be + * decoded. If no such data is available, the frame is decoded as if it were lost. + * @returns Number of decoded samples or @ref opus_errorcodes + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decode( + OpusDecoder *st, + const unsigned char *data, + opus_int32 len, + opus_int16 *pcm, + int frame_size, + int decode_fec +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + +/** Decode an Opus packet with floating point output. + * @param [in] st OpusDecoder*: Decoder state + * @param [in] data char*: Input payload. Use a NULL pointer to indicate packet loss + * @param [in] len opus_int32: Number of bytes in payload + * @param [out] pcm float*: Output signal (interleaved if 2 channels). length + * is frame_size*channels*sizeof(float) + * @param [in] frame_size Number of samples per channel of available space in \a pcm. + * If this is less than the maximum packet duration (120ms; 5760 for 48kHz), this function will + * not be capable of decoding some packets. In the case of PLC (data==NULL) or FEC (decode_fec=1), + * then frame_size needs to be exactly the duration of audio that is missing, otherwise the + * decoder will not be in the optimal state to decode the next incoming packet. For the PLC and + * FEC cases, frame_size must be a multiple of 2.5 ms. + * @param [in] decode_fec int: Flag (0 or 1) to request that any in-band forward error correction data be + * decoded. If no such data is available the frame is decoded as if it were lost. + * @returns Number of decoded samples or @ref opus_errorcodes + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decode_float( + OpusDecoder *st, + const unsigned char *data, + opus_int32 len, + float *pcm, + int frame_size, + int decode_fec +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + +/** Perform a CTL function on an Opus decoder. + * + * Generally the request and subsequent arguments are generated + * by a convenience macro. + * @param st OpusDecoder*: Decoder state. + * @param request This and all remaining parameters should be replaced by one + * of the convenience macros in @ref opus_genericctls or + * @ref opus_decoderctls. + * @see opus_genericctls + * @see opus_decoderctls + */ +OPUS_EXPORT int opus_decoder_ctl(OpusDecoder *st, int request, ...) OPUS_ARG_NONNULL(1); + +/** Frees an OpusDecoder allocated by opus_decoder_create(). + * @param[in] st OpusDecoder*: State to be freed. + */ +OPUS_EXPORT void opus_decoder_destroy(OpusDecoder *st); + +/** Parse an opus packet into one or more frames. + * Opus_decode will perform this operation internally so most applications do + * not need to use this function. + * This function does not copy the frames, the returned pointers are pointers into + * the input packet. + * @param [in] data char*: Opus packet to be parsed + * @param [in] len opus_int32: size of data + * @param [out] out_toc char*: TOC pointer + * @param [out] frames char*[48] encapsulated frames + * @param [out] size short[48] sizes of the encapsulated frames + * @param [out] payload_offset int*: returns the position of the payload within the packet (in bytes) + * @returns number of frames + */ +OPUS_EXPORT int opus_packet_parse( + const unsigned char *data, + opus_int32 len, + unsigned char *out_toc, + const unsigned char *frames[48], + short size[48], + int *payload_offset +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + +/** Gets the bandwidth of an Opus packet. + * @param [in] data char*: Opus packet + * @retval OPUS_BANDWIDTH_NARROWBAND Narrowband (4kHz bandpass) + * @retval OPUS_BANDWIDTH_MEDIUMBAND Mediumband (6kHz bandpass) + * @retval OPUS_BANDWIDTH_WIDEBAND Wideband (8kHz bandpass) + * @retval OPUS_BANDWIDTH_SUPERWIDEBAND Superwideband (12kHz bandpass) + * @retval OPUS_BANDWIDTH_FULLBAND Fullband (20kHz bandpass) + * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_bandwidth(const unsigned char *data) OPUS_ARG_NONNULL(1); + +/** Gets the number of samples per frame from an Opus packet. + * @param [in] data char*: Opus packet. + * This must contain at least one byte of + * data. + * @param [in] Fs opus_int32: Sampling rate in Hz. + * This must be a multiple of 400, or + * inaccurate results will be returned. + * @returns Number of samples per frame. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_samples_per_frame(const unsigned char *data, opus_int32 Fs) OPUS_ARG_NONNULL(1); + +/** Gets the number of channels from an Opus packet. + * @param [in] data char*: Opus packet + * @returns Number of channels + * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_channels(const unsigned char *data) OPUS_ARG_NONNULL(1); + +/** Gets the number of frames in an Opus packet. + * @param [in] packet char*: Opus packet + * @param [in] len opus_int32: Length of packet + * @returns Number of frames + * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_frames(const unsigned char packet[], opus_int32 len) OPUS_ARG_NONNULL(1); + +/** Gets the number of samples of an Opus packet. + * @param [in] packet char*: Opus packet + * @param [in] len opus_int32: Length of packet + * @param [in] Fs opus_int32: Sampling rate in Hz. + * This must be a multiple of 400, or + * inaccurate results will be returned. + * @returns Number of samples + * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_samples(const unsigned char packet[], opus_int32 len, opus_int32 Fs) OPUS_ARG_NONNULL(1); + +/** Gets the number of samples of an Opus packet. + * @param [in] dec OpusDecoder*: Decoder state + * @param [in] packet char*: Opus packet + * @param [in] len opus_int32: Length of packet + * @returns Number of samples + * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decoder_get_nb_samples(const OpusDecoder *dec, const unsigned char packet[], opus_int32 len) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2); +/**@}*/ + +/** @defgroup opus_repacketizer Repacketizer + * @{ + * + * The repacketizer can be used to merge multiple Opus packets into a single + * packet or alternatively to split Opus packets that have previously been + * merged. Splitting valid Opus packets is always guaranteed to succeed, + * whereas merging valid packets only succeeds if all frames have the same + * mode, bandwidth, and frame size, and when the total duration of the merged + * packet is no more than 120 ms. + * The repacketizer currently only operates on elementary Opus + * streams. It will not manipualte multistream packets successfully, except in + * the degenerate case where they consist of data from a single stream. + * + * The repacketizing process starts with creating a repacketizer state, either + * by calling opus_repacketizer_create() or by allocating the memory yourself, + * e.g., + * @code + * OpusRepacketizer *rp; + * rp = (OpusRepacketizer*)malloc(opus_repacketizer_get_size()); + * if (rp != NULL) + * opus_repacketizer_init(rp); + * @endcode + * + * Then the application should submit packets with opus_repacketizer_cat(), + * extract new packets with opus_repacketizer_out() or + * opus_repacketizer_out_range(), and then reset the state for the next set of + * input packets via opus_repacketizer_init(). + * + * For example, to split a sequence of packets into individual frames: + * @code + * unsigned char *data; + * int len; + * while (get_next_packet(&data, &len)) + * { + * unsigned char out[1276]; + * opus_int32 out_len; + * int nb_frames; + * int err; + * int i; + * err = opus_repacketizer_cat(rp, data, len); + * if (err != OPUS_OK) + * { + * release_packet(data); + * return err; + * } + * nb_frames = opus_repacketizer_get_nb_frames(rp); + * for (i = 0; i < nb_frames; i++) + * { + * out_len = opus_repacketizer_out_range(rp, i, i+1, out, sizeof(out)); + * if (out_len < 0) + * { + * release_packet(data); + * return (int)out_len; + * } + * output_next_packet(out, out_len); + * } + * opus_repacketizer_init(rp); + * release_packet(data); + * } + * @endcode + * + * Alternatively, to combine a sequence of frames into packets that each + * contain up to TARGET_DURATION_MS milliseconds of data: + * @code + * // The maximum number of packets with duration TARGET_DURATION_MS occurs + * // when the frame size is 2.5 ms, for a total of (TARGET_DURATION_MS*2/5) + * // packets. + * unsigned char *data[(TARGET_DURATION_MS*2/5)+1]; + * opus_int32 len[(TARGET_DURATION_MS*2/5)+1]; + * int nb_packets; + * unsigned char out[1277*(TARGET_DURATION_MS*2/2)]; + * opus_int32 out_len; + * int prev_toc; + * nb_packets = 0; + * while (get_next_packet(data+nb_packets, len+nb_packets)) + * { + * int nb_frames; + * int err; + * nb_frames = opus_packet_get_nb_frames(data[nb_packets], len[nb_packets]); + * if (nb_frames < 1) + * { + * release_packets(data, nb_packets+1); + * return nb_frames; + * } + * nb_frames += opus_repacketizer_get_nb_frames(rp); + * // If adding the next packet would exceed our target, or it has an + * // incompatible TOC sequence, output the packets we already have before + * // submitting it. + * // N.B., The nb_packets > 0 check ensures we've submitted at least one + * // packet since the last call to opus_repacketizer_init(). Otherwise a + * // single packet longer than TARGET_DURATION_MS would cause us to try to + * // output an (invalid) empty packet. It also ensures that prev_toc has + * // been set to a valid value. Additionally, len[nb_packets] > 0 is + * // guaranteed by the call to opus_packet_get_nb_frames() above, so the + * // reference to data[nb_packets][0] should be valid. + * if (nb_packets > 0 && ( + * ((prev_toc & 0xFC) != (data[nb_packets][0] & 0xFC)) || + * opus_packet_get_samples_per_frame(data[nb_packets], 48000)*nb_frames > + * TARGET_DURATION_MS*48)) + * { + * out_len = opus_repacketizer_out(rp, out, sizeof(out)); + * if (out_len < 0) + * { + * release_packets(data, nb_packets+1); + * return (int)out_len; + * } + * output_next_packet(out, out_len); + * opus_repacketizer_init(rp); + * release_packets(data, nb_packets); + * data[0] = data[nb_packets]; + * len[0] = len[nb_packets]; + * nb_packets = 0; + * } + * err = opus_repacketizer_cat(rp, data[nb_packets], len[nb_packets]); + * if (err != OPUS_OK) + * { + * release_packets(data, nb_packets+1); + * return err; + * } + * prev_toc = data[nb_packets][0]; + * nb_packets++; + * } + * // Output the final, partial packet. + * if (nb_packets > 0) + * { + * out_len = opus_repacketizer_out(rp, out, sizeof(out)); + * release_packets(data, nb_packets); + * if (out_len < 0) + * return (int)out_len; + * output_next_packet(out, out_len); + * } + * @endcode + * + * An alternate way of merging packets is to simply call opus_repacketizer_cat() + * unconditionally until it fails. At that point, the merged packet can be + * obtained with opus_repacketizer_out() and the input packet for which + * opus_repacketizer_cat() needs to be re-added to a newly reinitialized + * repacketizer state. + */ + +typedef struct OpusRepacketizer OpusRepacketizer; + +/** Gets the size of an OpusRepacketizer structure. + * @returns The size in bytes. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_repacketizer_get_size(void); + +/** (Re)initializes a previously allocated repacketizer state. + * The state must be at least the size returned by opus_repacketizer_get_size(). + * This can be used for applications which use their own allocator instead of + * malloc(). + * It must also be called to reset the queue of packets waiting to be + * repacketized, which is necessary if the maximum packet duration of 120 ms + * is reached or if you wish to submit packets with a different Opus + * configuration (coding mode, audio bandwidth, frame size, or channel count). + * Failure to do so will prevent a new packet from being added with + * opus_repacketizer_cat(). + * @see opus_repacketizer_create + * @see opus_repacketizer_get_size + * @see opus_repacketizer_cat + * @param rp OpusRepacketizer*: The repacketizer state to + * (re)initialize. + * @returns A pointer to the same repacketizer state that was passed in. + */ +OPUS_EXPORT OpusRepacketizer *opus_repacketizer_init(OpusRepacketizer *rp) OPUS_ARG_NONNULL(1); + +/** Allocates memory and initializes the new repacketizer with + * opus_repacketizer_init(). + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusRepacketizer *opus_repacketizer_create(void); + +/** Frees an OpusRepacketizer allocated by + * opus_repacketizer_create(). + * @param[in] rp OpusRepacketizer*: State to be freed. + */ +OPUS_EXPORT void opus_repacketizer_destroy(OpusRepacketizer *rp); + +/** Add a packet to the current repacketizer state. + * This packet must match the configuration of any packets already submitted + * for repacketization since the last call to opus_repacketizer_init(). + * This means that it must have the same coding mode, audio bandwidth, frame + * size, and channel count. + * This can be checked in advance by examining the top 6 bits of the first + * byte of the packet, and ensuring they match the top 6 bits of the first + * byte of any previously submitted packet. + * The total duration of audio in the repacketizer state also must not exceed + * 120 ms, the maximum duration of a single packet, after adding this packet. + * + * The contents of the current repacketizer state can be extracted into new + * packets using opus_repacketizer_out() or opus_repacketizer_out_range(). + * + * In order to add a packet with a different configuration or to add more + * audio beyond 120 ms, you must clear the repacketizer state by calling + * opus_repacketizer_init(). + * If a packet is too large to add to the current repacketizer state, no part + * of it is added, even if it contains multiple frames, some of which might + * fit. + * If you wish to be able to add parts of such packets, you should first use + * another repacketizer to split the packet into pieces and add them + * individually. + * @see opus_repacketizer_out_range + * @see opus_repacketizer_out + * @see opus_repacketizer_init + * @param rp OpusRepacketizer*: The repacketizer state to which to + * add the packet. + * @param[in] data const unsigned char*: The packet data. + * The application must ensure + * this pointer remains valid + * until the next call to + * opus_repacketizer_init() or + * opus_repacketizer_destroy(). + * @param len opus_int32: The number of bytes in the packet data. + * @returns An error code indicating whether or not the operation succeeded. + * @retval #OPUS_OK The packet's contents have been added to the repacketizer + * state. + * @retval #OPUS_INVALID_PACKET The packet did not have a valid TOC sequence, + * the packet's TOC sequence was not compatible + * with previously submitted packets (because + * the coding mode, audio bandwidth, frame size, + * or channel count did not match), or adding + * this packet would increase the total amount of + * audio stored in the repacketizer state to more + * than 120 ms. + */ +OPUS_EXPORT int opus_repacketizer_cat(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2); + + +/** Construct a new packet from data previously submitted to the repacketizer + * state via opus_repacketizer_cat(). + * @param rp OpusRepacketizer*: The repacketizer state from which to + * construct the new packet. + * @param begin int: The index of the first frame in the current + * repacketizer state to include in the output. + * @param end int: One past the index of the last frame in the + * current repacketizer state to include in the + * output. + * @param[out] data const unsigned char*: The buffer in which to + * store the output packet. + * @param maxlen opus_int32: The maximum number of bytes to store in + * the output buffer. In order to guarantee + * success, this should be at least + * 1276 for a single frame, + * or for multiple frames, + * 1277*(end-begin). + * However, 1*(end-begin) plus + * the size of all packet data submitted to + * the repacketizer since the last call to + * opus_repacketizer_init() or + * opus_repacketizer_create() is also + * sufficient, and possibly much smaller. + * @returns The total size of the output packet on success, or an error code + * on failure. + * @retval #OPUS_BAD_ARG [begin,end) was an invalid range of + * frames (begin < 0, begin >= end, or end > + * opus_repacketizer_get_nb_frames()). + * @retval #OPUS_BUFFER_TOO_SMALL \a maxlen was insufficient to contain the + * complete output packet. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_repacketizer_out_range(OpusRepacketizer *rp, int begin, int end, unsigned char *data, opus_int32 maxlen) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + +/** Return the total number of frames contained in packet data submitted to + * the repacketizer state so far via opus_repacketizer_cat() since the last + * call to opus_repacketizer_init() or opus_repacketizer_create(). + * This defines the valid range of packets that can be extracted with + * opus_repacketizer_out_range() or opus_repacketizer_out(). + * @param rp OpusRepacketizer*: The repacketizer state containing the + * frames. + * @returns The total number of frames contained in the packet data submitted + * to the repacketizer state. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_repacketizer_get_nb_frames(OpusRepacketizer *rp) OPUS_ARG_NONNULL(1); + +/** Construct a new packet from data previously submitted to the repacketizer + * state via opus_repacketizer_cat(). + * This is a convenience routine that returns all the data submitted so far + * in a single packet. + * It is equivalent to calling + * @code + * opus_repacketizer_out_range(rp, 0, opus_repacketizer_get_nb_frames(rp), + * data, maxlen) + * @endcode + * @param rp OpusRepacketizer*: The repacketizer state from which to + * construct the new packet. + * @param[out] data const unsigned char*: The buffer in which to + * store the output packet. + * @param maxlen opus_int32: The maximum number of bytes to store in + * the output buffer. In order to guarantee + * success, this should be at least + * 1277*opus_repacketizer_get_nb_frames(rp). + * However, + * 1*opus_repacketizer_get_nb_frames(rp) + * plus the size of all packet data + * submitted to the repacketizer since the + * last call to opus_repacketizer_init() or + * opus_repacketizer_create() is also + * sufficient, and possibly much smaller. + * @returns The total size of the output packet on success, or an error code + * on failure. + * @retval #OPUS_BUFFER_TOO_SMALL \a maxlen was insufficient to contain the + * complete output packet. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_repacketizer_out(OpusRepacketizer *rp, unsigned char *data, opus_int32 maxlen) OPUS_ARG_NONNULL(1); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* OPUS_H */ diff --git a/code/opus-1.0.2/include/opus_custom.h b/code/opus-1.0.2/include/opus_custom.h new file mode 100644 index 00000000..e7861d6f --- /dev/null +++ b/code/opus-1.0.2/include/opus_custom.h @@ -0,0 +1,329 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2008-2012 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (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 opus_custom.h + @brief Opus-Custom reference implementation API + */ + +#ifndef OPUS_CUSTOM_H +#define OPUS_CUSTOM_H + +#include "opus_defines.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef CUSTOM_MODES +#define OPUS_CUSTOM_EXPORT OPUS_EXPORT +#define OPUS_CUSTOM_EXPORT_STATIC OPUS_EXPORT +#else +#define OPUS_CUSTOM_EXPORT +#ifdef CELT_C +#define OPUS_CUSTOM_EXPORT_STATIC static inline +#else +#define OPUS_CUSTOM_EXPORT_STATIC +#endif +#endif + +/** @defgroup opus_custom Opus Custom + * @{ + * Opus Custom is an optional part of the Opus specification and + * reference implementation which uses a distinct API from the regular + * API and supports frame sizes that are not normally supported.\ Use + * of Opus Custom is discouraged for all but very special applications + * for which a frame size different from 2.5, 5, 10, or 20 ms is needed + * (for either complexity or latency reasons) and where interoperability + * is less important. + * + * In addition to the interoperability limitations the use of Opus custom + * disables a substantial chunk of the codec and generally lowers the + * quality available at a given bitrate. Normally when an application needs + * a different frame size from the codec it should buffer to match the + * sizes but this adds a small amount of delay which may be important + * in some very low latency applications. Some transports (especially + * constant rate RF transports) may also work best with frames of + * particular durations. + * + * Libopus only supports custom modes if they are enabled at compile time. + * + * The Opus Custom API is similar to the regular API but the + * @ref opus_encoder_create and @ref opus_decoder_create calls take + * an additional mode parameter which is a structure produced by + * a call to @ref opus_custom_mode_create. Both the encoder and decoder + * must create a mode using the same sample rate (fs) and frame size + * (frame size) so these parameters must either be signaled out of band + * or fixed in a particular implementation. + * + * Similar to regular Opus the custom modes support on the fly frame size + * switching, but the sizes available depend on the particular frame size in + * use. For some initial frame sizes on a single on the fly size is available. + */ + +/** Contains the state of an encoder. One encoder state is needed + for each stream. It is initialized once at the beginning of the + stream. Do *not* re-initialize the state for every frame. + @brief Encoder state + */ +typedef struct OpusCustomEncoder OpusCustomEncoder; + +/** State of the decoder. One decoder state is needed for each stream. + It is initialized once at the beginning of the stream. Do *not* + re-initialize the state for every frame. + @brief Decoder state + */ +typedef struct OpusCustomDecoder OpusCustomDecoder; + +/** The mode contains all the information necessary to create an + encoder. Both the encoder and decoder need to be initialized + with exactly the same mode, otherwise the output will be + corrupted. + @brief Mode configuration + */ +typedef struct OpusCustomMode OpusCustomMode; + +/** Creates a new mode struct. This will be passed to an encoder or + * decoder. The mode MUST NOT BE DESTROYED until the encoders and + * decoders that use it are destroyed as well. + * @param [in] Fs int: Sampling rate (8000 to 96000 Hz) + * @param [in] frame_size int: Number of samples (per channel) to encode in each + * packet (64 - 1024, prime factorization must contain zero or more 2s, 3s, or 5s and no other primes) + * @param [out] error int*: Returned error code (if NULL, no error will be returned) + * @return A newly created mode + */ +OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomMode *opus_custom_mode_create(opus_int32 Fs, int frame_size, int *error); + +/** Destroys a mode struct. Only call this after all encoders and + * decoders using this mode are destroyed as well. + * @param [in] mode OpusCustomMode*: Mode to be freed. + */ +OPUS_CUSTOM_EXPORT void opus_custom_mode_destroy(OpusCustomMode *mode); + +/* Encoder */ +/** Gets the size of an OpusCustomEncoder structure. + * @param [in] mode OpusCustomMode *: Mode configuration + * @param [in] channels int: Number of channels + * @returns size + */ +OPUS_CUSTOM_EXPORT_STATIC OPUS_WARN_UNUSED_RESULT int opus_custom_encoder_get_size( + const OpusCustomMode *mode, + int channels +) OPUS_ARG_NONNULL(1); + +/** Creates a new encoder state. Each stream needs its own encoder + * state (can't be shared across simultaneous streams). + * @param [in] mode OpusCustomMode*: Contains all the information about the characteristics of + * the stream (must be the same characteristics as used for the + * decoder) + * @param [in] channels int: Number of channels + * @param [out] error int*: Returns an error code + * @return Newly created encoder state. +*/ +OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomEncoder *opus_custom_encoder_create( + const OpusCustomMode *mode, + int channels, + int *error +) OPUS_ARG_NONNULL(1); + +/** Initializes a previously allocated encoder state + * The memory pointed to by st must be the size returned by opus_custom_encoder_get_size. + * This is intended for applications which use their own allocator instead of malloc. + * @see opus_custom_encoder_create(),opus_custom_encoder_get_size() + * To reset a previously initialized state use the OPUS_RESET_STATE CTL. + * @param [in] st OpusCustomEncoder*: Encoder state + * @param [in] mode OpusCustomMode *: Contains all the information about the characteristics of + * the stream (must be the same characteristics as used for the + * decoder) + * @param [in] channels int: Number of channels + * @return OPUS_OK Success or @ref opus_errorcodes + */ +OPUS_CUSTOM_EXPORT_STATIC int opus_custom_encoder_init( + OpusCustomEncoder *st, + const OpusCustomMode *mode, + int channels +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2); + +/** Destroys a an encoder state. + * @param[in] st OpusCustomEncoder*: State to be freed. + */ +OPUS_CUSTOM_EXPORT void opus_custom_encoder_destroy(OpusCustomEncoder *st); + +/** Encodes a frame of audio. + * @param [in] st OpusCustomEncoder*: Encoder state + * @param [in] pcm float*: PCM audio in float format, with a normal range of +/-1.0. + * Samples with a range beyond +/-1.0 are supported but will + * be clipped by decoders using the integer API and should + * only be used if it is known that the far end supports + * extended dynamic range. There must be exactly + * frame_size samples per channel. + * @param [in] frame_size int: Number of samples per frame of input signal + * @param [out] compressed char *: The compressed data is written here. This may not alias pcm and must be at least maxCompressedBytes long. + * @param [in] maxCompressedBytes int: Maximum number of bytes to use for compressing the frame + * (can change from one frame to another) + * @return Number of bytes written to "compressed". + * If negative, an error has occurred (see error codes). It is IMPORTANT that + * the length returned be somehow transmitted to the decoder. Otherwise, no + * decoding is possible. + */ +OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_encode_float( + OpusCustomEncoder *st, + const float *pcm, + int frame_size, + unsigned char *compressed, + int maxCompressedBytes +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); + +/** Encodes a frame of audio. + * @param [in] st OpusCustomEncoder*: Encoder state + * @param [in] pcm opus_int16*: PCM audio in signed 16-bit format (native endian). + * There must be exactly frame_size samples per channel. + * @param [in] frame_size int: Number of samples per frame of input signal + * @param [out] compressed char *: The compressed data is written here. This may not alias pcm and must be at least maxCompressedBytes long. + * @param [in] maxCompressedBytes int: Maximum number of bytes to use for compressing the frame + * (can change from one frame to another) + * @return Number of bytes written to "compressed". + * If negative, an error has occurred (see error codes). It is IMPORTANT that + * the length returned be somehow transmitted to the decoder. Otherwise, no + * decoding is possible. + */ +OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_encode( + OpusCustomEncoder *st, + const opus_int16 *pcm, + int frame_size, + unsigned char *compressed, + int maxCompressedBytes +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); + +/** Perform a CTL function on an Opus custom encoder. + * + * Generally the request and subsequent arguments are generated + * by a convenience macro. + * @see opus_encoderctls + */ +OPUS_CUSTOM_EXPORT int opus_custom_encoder_ctl(OpusCustomEncoder * OPUS_RESTRICT st, int request, ...) OPUS_ARG_NONNULL(1); + +/* Decoder */ + +/** Gets the size of an OpusCustomDecoder structure. + * @param [in] mode OpusCustomMode *: Mode configuration + * @param [in] channels int: Number of channels + * @returns size + */ +OPUS_CUSTOM_EXPORT_STATIC OPUS_WARN_UNUSED_RESULT int opus_custom_decoder_get_size( + const OpusCustomMode *mode, + int channels +) OPUS_ARG_NONNULL(1); + +/** Creates a new decoder state. Each stream needs its own decoder state (can't + * be shared across simultaneous streams). + * @param [in] mode OpusCustomMode: Contains all the information about the characteristics of the + * stream (must be the same characteristics as used for the encoder) + * @param [in] channels int: Number of channels + * @param [out] error int*: Returns an error code + * @return Newly created decoder state. + */ +OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomDecoder *opus_custom_decoder_create( + const OpusCustomMode *mode, + int channels, + int *error +) OPUS_ARG_NONNULL(1); + +/** Initializes a previously allocated decoder state + * The memory pointed to by st must be the size returned by opus_custom_decoder_get_size. + * This is intended for applications which use their own allocator instead of malloc. + * @see opus_custom_decoder_create(),opus_custom_decoder_get_size() + * To reset a previously initialized state use the OPUS_RESET_STATE CTL. + * @param [in] st OpusCustomDecoder*: Decoder state + * @param [in] mode OpusCustomMode *: Contains all the information about the characteristics of + * the stream (must be the same characteristics as used for the + * encoder) + * @param [in] channels int: Number of channels + * @return OPUS_OK Success or @ref opus_errorcodes + */ +OPUS_CUSTOM_EXPORT_STATIC int opus_custom_decoder_init( + OpusCustomDecoder *st, + const OpusCustomMode *mode, + int channels +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2); + +/** Destroys a an decoder state. + * @param[in] st OpusCustomDecoder*: State to be freed. + */ +OPUS_CUSTOM_EXPORT void opus_custom_decoder_destroy(OpusCustomDecoder *st); + +/** Decode an opus custom frame with floating point output + * @param [in] st OpusCustomDecoder*: Decoder state + * @param [in] data char*: Input payload. Use a NULL pointer to indicate packet loss + * @param [in] len int: Number of bytes in payload + * @param [out] pcm float*: Output signal (interleaved if 2 channels). length + * is frame_size*channels*sizeof(float) + * @param [in] frame_size Number of samples per channel of available space in *pcm. + * @returns Number of decoded samples or @ref opus_errorcodes + */ +OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_decode_float( + OpusCustomDecoder *st, + const unsigned char *data, + int len, + float *pcm, + int frame_size +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + +/** Decode an opus custom frame + * @param [in] st OpusCustomDecoder*: Decoder state + * @param [in] data char*: Input payload. Use a NULL pointer to indicate packet loss + * @param [in] len int: Number of bytes in payload + * @param [out] pcm opus_int16*: Output signal (interleaved if 2 channels). length + * is frame_size*channels*sizeof(opus_int16) + * @param [in] frame_size Number of samples per channel of available space in *pcm. + * @returns Number of decoded samples or @ref opus_errorcodes + */ +OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_decode( + OpusCustomDecoder *st, + const unsigned char *data, + int len, + opus_int16 *pcm, + int frame_size +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + +/** Perform a CTL function on an Opus custom decoder. + * + * Generally the request and subsequent arguments are generated + * by a convenience macro. + * @see opus_genericctls + */ +OPUS_CUSTOM_EXPORT int opus_custom_decoder_ctl(OpusCustomDecoder * OPUS_RESTRICT st, int request, ...) OPUS_ARG_NONNULL(1); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* OPUS_CUSTOM_H */ diff --git a/code/opus-1.0.2/include/opus_defines.h b/code/opus-1.0.2/include/opus_defines.h new file mode 100644 index 00000000..cdde061a --- /dev/null +++ b/code/opus-1.0.2/include/opus_defines.h @@ -0,0 +1,655 @@ +/* Copyright (c) 2010-2011 Xiph.Org Foundation, Skype Limited + Written by Jean-Marc Valin and Koen Vos */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (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 opus_defines.h + * @brief Opus reference implementation constants + */ + +#ifndef OPUS_DEFINES_H +#define OPUS_DEFINES_H + +#include "opus_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @defgroup opus_errorcodes Error codes + * @{ + */ +/** No error @hideinitializer*/ +#define OPUS_OK 0 +/** One or more invalid/out of range arguments @hideinitializer*/ +#define OPUS_BAD_ARG -1 +/** The mode struct passed is invalid @hideinitializer*/ +#define OPUS_BUFFER_TOO_SMALL -2 +/** An internal error was detected @hideinitializer*/ +#define OPUS_INTERNAL_ERROR -3 +/** The compressed data passed is corrupted @hideinitializer*/ +#define OPUS_INVALID_PACKET -4 +/** Invalid/unsupported request number @hideinitializer*/ +#define OPUS_UNIMPLEMENTED -5 +/** An encoder or decoder structure is invalid or already freed @hideinitializer*/ +#define OPUS_INVALID_STATE -6 +/** Memory allocation has failed @hideinitializer*/ +#define OPUS_ALLOC_FAIL -7 +/**@}*/ + +/** @cond OPUS_INTERNAL_DOC */ +/**Export control for opus functions */ + +#ifndef OPUS_EXPORT +# if defined(__GNUC__) && defined(OPUS_BUILD) +# define OPUS_EXPORT __attribute__ ((visibility ("default"))) +# elif defined(WIN32) && !defined(__MINGW32__) +# ifdef OPUS_BUILD +# define OPUS_EXPORT __declspec(dllexport) +# else +# define OPUS_EXPORT +# endif +# else +# define OPUS_EXPORT +# endif +#endif + +# if !defined(OPUS_GNUC_PREREQ) +# if defined(__GNUC__)&&defined(__GNUC_MINOR__) +# define OPUS_GNUC_PREREQ(_maj,_min) \ + ((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min)) +# else +# define OPUS_GNUC_PREREQ(_maj,_min) 0 +# endif +# endif + +#if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) ) +# if OPUS_GNUC_PREREQ(3,0) +# define OPUS_RESTRICT __restrict__ +# elif (defined(_MSC_VER) && _MSC_VER >= 1400) +# define OPUS_RESTRICT __restrict +# else +# define OPUS_RESTRICT +# endif +#else +# define OPUS_RESTRICT restrict +#endif + +/**Warning attributes for opus functions + * NONNULL is not used in OPUS_BUILD to avoid the compiler optimizing out + * some paranoid null checks. */ +#if defined(__GNUC__) && OPUS_GNUC_PREREQ(3, 4) +# define OPUS_WARN_UNUSED_RESULT __attribute__ ((__warn_unused_result__)) +#else +# define OPUS_WARN_UNUSED_RESULT +#endif +#if !defined(OPUS_BUILD) && defined(__GNUC__) && OPUS_GNUC_PREREQ(3, 4) +# define OPUS_ARG_NONNULL(_x) __attribute__ ((__nonnull__(_x))) +#else +# define OPUS_ARG_NONNULL(_x) +#endif + +/** These are the actual Encoder CTL ID numbers. + * They should not be used directly by applications. + * In general, SETs should be even and GETs should be odd.*/ +#define OPUS_SET_APPLICATION_REQUEST 4000 +#define OPUS_GET_APPLICATION_REQUEST 4001 +#define OPUS_SET_BITRATE_REQUEST 4002 +#define OPUS_GET_BITRATE_REQUEST 4003 +#define OPUS_SET_MAX_BANDWIDTH_REQUEST 4004 +#define OPUS_GET_MAX_BANDWIDTH_REQUEST 4005 +#define OPUS_SET_VBR_REQUEST 4006 +#define OPUS_GET_VBR_REQUEST 4007 +#define OPUS_SET_BANDWIDTH_REQUEST 4008 +#define OPUS_GET_BANDWIDTH_REQUEST 4009 +#define OPUS_SET_COMPLEXITY_REQUEST 4010 +#define OPUS_GET_COMPLEXITY_REQUEST 4011 +#define OPUS_SET_INBAND_FEC_REQUEST 4012 +#define OPUS_GET_INBAND_FEC_REQUEST 4013 +#define OPUS_SET_PACKET_LOSS_PERC_REQUEST 4014 +#define OPUS_GET_PACKET_LOSS_PERC_REQUEST 4015 +#define OPUS_SET_DTX_REQUEST 4016 +#define OPUS_GET_DTX_REQUEST 4017 +#define OPUS_SET_VBR_CONSTRAINT_REQUEST 4020 +#define OPUS_GET_VBR_CONSTRAINT_REQUEST 4021 +#define OPUS_SET_FORCE_CHANNELS_REQUEST 4022 +#define OPUS_GET_FORCE_CHANNELS_REQUEST 4023 +#define OPUS_SET_SIGNAL_REQUEST 4024 +#define OPUS_GET_SIGNAL_REQUEST 4025 +#define OPUS_GET_LOOKAHEAD_REQUEST 4027 +/* #define OPUS_RESET_STATE 4028 */ +#define OPUS_GET_SAMPLE_RATE_REQUEST 4029 +#define OPUS_GET_FINAL_RANGE_REQUEST 4031 +#define OPUS_GET_PITCH_REQUEST 4033 +#define OPUS_SET_GAIN_REQUEST 4034 +#define OPUS_GET_GAIN_REQUEST 4045 /* Should have been 4035 */ +#define OPUS_SET_LSB_DEPTH_REQUEST 4036 +#define OPUS_GET_LSB_DEPTH_REQUEST 4037 + +#define OPUS_GET_LAST_PACKET_DURATION_REQUEST 4039 + +/* Don't use 4045, it's already taken by OPUS_GET_GAIN_REQUEST */ + +/* Macros to trigger compilation errors when the wrong types are provided to a CTL */ +#define __opus_check_int(x) (((void)((x) == (opus_int32)0)), (opus_int32)(x)) +#define __opus_check_int_ptr(ptr) ((ptr) + ((ptr) - (opus_int32*)(ptr))) +#define __opus_check_uint_ptr(ptr) ((ptr) + ((ptr) - (opus_uint32*)(ptr))) +/** @endcond */ + +/** @defgroup opus_ctlvalues Pre-defined values for CTL interface + * @see opus_genericctls, opus_encoderctls + * @{ + */ +/* Values for the various encoder CTLs */ +#define OPUS_AUTO -1000 /**opus_int32: Allowed values: 0-10, inclusive. + * + * @hideinitializer */ +#define OPUS_SET_COMPLEXITY(x) OPUS_SET_COMPLEXITY_REQUEST, __opus_check_int(x) +/** Gets the encoder's complexity configuration. + * @see OPUS_SET_COMPLEXITY + * @param[out] x opus_int32 *: Returns a value in the range 0-10, + * inclusive. + * @hideinitializer */ +#define OPUS_GET_COMPLEXITY(x) OPUS_GET_COMPLEXITY_REQUEST, __opus_check_int_ptr(x) + +/** Configures the bitrate in the encoder. + * Rates from 500 to 512000 bits per second are meaningful, as well as the + * special values #OPUS_AUTO and #OPUS_BITRATE_MAX. + * The value #OPUS_BITRATE_MAX can be used to cause the codec to use as much + * rate as it can, which is useful for controlling the rate by adjusting the + * output buffer size. + * @see OPUS_GET_BITRATE + * @param[in] x opus_int32: Bitrate in bits per second. The default + * is determined based on the number of + * channels and the input sampling rate. + * @hideinitializer */ +#define OPUS_SET_BITRATE(x) OPUS_SET_BITRATE_REQUEST, __opus_check_int(x) +/** Gets the encoder's bitrate configuration. + * @see OPUS_SET_BITRATE + * @param[out] x opus_int32 *: Returns the bitrate in bits per second. + * The default is determined based on the + * number of channels and the input + * sampling rate. + * @hideinitializer */ +#define OPUS_GET_BITRATE(x) OPUS_GET_BITRATE_REQUEST, __opus_check_int_ptr(x) + +/** Enables or disables variable bitrate (VBR) in the encoder. + * The configured bitrate may not be met exactly because frames must + * be an integer number of bytes in length. + * @warning Only the MDCT mode of Opus can provide hard CBR behavior. + * @see OPUS_GET_VBR + * @see OPUS_SET_VBR_CONSTRAINT + * @param[in] x opus_int32: Allowed values: + *
    + *
    0
    Hard CBR. For LPC/hybrid modes at very low bit-rate, this can + * cause noticeable quality degradation.
    + *
    1
    VBR (default). The exact type of VBR is controlled by + * #OPUS_SET_VBR_CONSTRAINT.
    + *
    + * @hideinitializer */ +#define OPUS_SET_VBR(x) OPUS_SET_VBR_REQUEST, __opus_check_int(x) +/** Determine if variable bitrate (VBR) is enabled in the encoder. + * @see OPUS_SET_VBR + * @see OPUS_GET_VBR_CONSTRAINT + * @param[out] x opus_int32 *: Returns one of the following values: + *
    + *
    0
    Hard CBR.
    + *
    1
    VBR (default). The exact type of VBR may be retrieved via + * #OPUS_GET_VBR_CONSTRAINT.
    + *
    + * @hideinitializer */ +#define OPUS_GET_VBR(x) OPUS_GET_VBR_REQUEST, __opus_check_int_ptr(x) + +/** Enables or disables constrained VBR in the encoder. + * This setting is ignored when the encoder is in CBR mode. + * @warning Only the MDCT mode of Opus currently heeds the constraint. + * Speech mode ignores it completely, hybrid mode may fail to obey it + * if the LPC layer uses more bitrate than the constraint would have + * permitted. + * @see OPUS_GET_VBR_CONSTRAINT + * @see OPUS_SET_VBR + * @param[in] x opus_int32: Allowed values: + *
    + *
    0
    Unconstrained VBR.
    + *
    1
    Constrained VBR (default). This creates a maximum of one + * frame of buffering delay assuming a transport with a + * serialization speed of the nominal bitrate.
    + *
    + * @hideinitializer */ +#define OPUS_SET_VBR_CONSTRAINT(x) OPUS_SET_VBR_CONSTRAINT_REQUEST, __opus_check_int(x) +/** Determine if constrained VBR is enabled in the encoder. + * @see OPUS_SET_VBR_CONSTRAINT + * @see OPUS_GET_VBR + * @param[out] x opus_int32 *: Returns one of the following values: + *
    + *
    0
    Unconstrained VBR.
    + *
    1
    Constrained VBR (default).
    + *
    + * @hideinitializer */ +#define OPUS_GET_VBR_CONSTRAINT(x) OPUS_GET_VBR_CONSTRAINT_REQUEST, __opus_check_int_ptr(x) + +/** Configures mono/stereo forcing in the encoder. + * This can force the encoder to produce packets encoded as either mono or + * stereo, regardless of the format of the input audio. This is useful when + * the caller knows that the input signal is currently a mono source embedded + * in a stereo stream. + * @see OPUS_GET_FORCE_CHANNELS + * @param[in] x opus_int32: Allowed values: + *
    + *
    #OPUS_AUTO
    Not forced (default)
    + *
    1
    Forced mono
    + *
    2
    Forced stereo
    + *
    + * @hideinitializer */ +#define OPUS_SET_FORCE_CHANNELS(x) OPUS_SET_FORCE_CHANNELS_REQUEST, __opus_check_int(x) +/** Gets the encoder's forced channel configuration. + * @see OPUS_SET_FORCE_CHANNELS + * @param[out] x opus_int32 *: + *
    + *
    #OPUS_AUTO
    Not forced (default)
    + *
    1
    Forced mono
    + *
    2
    Forced stereo
    + *
    + * @hideinitializer */ +#define OPUS_GET_FORCE_CHANNELS(x) OPUS_GET_FORCE_CHANNELS_REQUEST, __opus_check_int_ptr(x) + +/** Configures the maximum bandpass that the encoder will select automatically. + * Applications should normally use this instead of #OPUS_SET_BANDWIDTH + * (leaving that set to the default, #OPUS_AUTO). This allows the + * application to set an upper bound based on the type of input it is + * providing, but still gives the encoder the freedom to reduce the bandpass + * when the bitrate becomes too low, for better overall quality. + * @see OPUS_GET_MAX_BANDWIDTH + * @param[in] x opus_int32: Allowed values: + *
    + *
    OPUS_BANDWIDTH_NARROWBAND
    4 kHz passband
    + *
    OPUS_BANDWIDTH_MEDIUMBAND
    6 kHz passband
    + *
    OPUS_BANDWIDTH_WIDEBAND
    8 kHz passband
    + *
    OPUS_BANDWIDTH_SUPERWIDEBAND
    12 kHz passband
    + *
    OPUS_BANDWIDTH_FULLBAND
    20 kHz passband (default)
    + *
    + * @hideinitializer */ +#define OPUS_SET_MAX_BANDWIDTH(x) OPUS_SET_MAX_BANDWIDTH_REQUEST, __opus_check_int(x) + +/** Gets the encoder's configured maximum allowed bandpass. + * @see OPUS_SET_MAX_BANDWIDTH + * @param[out] x opus_int32 *: Allowed values: + *
    + *
    #OPUS_BANDWIDTH_NARROWBAND
    4 kHz passband
    + *
    #OPUS_BANDWIDTH_MEDIUMBAND
    6 kHz passband
    + *
    #OPUS_BANDWIDTH_WIDEBAND
    8 kHz passband
    + *
    #OPUS_BANDWIDTH_SUPERWIDEBAND
    12 kHz passband
    + *
    #OPUS_BANDWIDTH_FULLBAND
    20 kHz passband (default)
    + *
    + * @hideinitializer */ +#define OPUS_GET_MAX_BANDWIDTH(x) OPUS_GET_MAX_BANDWIDTH_REQUEST, __opus_check_int_ptr(x) + +/** Sets the encoder's bandpass to a specific value. + * This prevents the encoder from automatically selecting the bandpass based + * on the available bitrate. If an application knows the bandpass of the input + * audio it is providing, it should normally use #OPUS_SET_MAX_BANDWIDTH + * instead, which still gives the encoder the freedom to reduce the bandpass + * when the bitrate becomes too low, for better overall quality. + * @see OPUS_GET_BANDWIDTH + * @param[in] x opus_int32: Allowed values: + *
    + *
    #OPUS_AUTO
    (default)
    + *
    #OPUS_BANDWIDTH_NARROWBAND
    4 kHz passband
    + *
    #OPUS_BANDWIDTH_MEDIUMBAND
    6 kHz passband
    + *
    #OPUS_BANDWIDTH_WIDEBAND
    8 kHz passband
    + *
    #OPUS_BANDWIDTH_SUPERWIDEBAND
    12 kHz passband
    + *
    #OPUS_BANDWIDTH_FULLBAND
    20 kHz passband
    + *
    + * @hideinitializer */ +#define OPUS_SET_BANDWIDTH(x) OPUS_SET_BANDWIDTH_REQUEST, __opus_check_int(x) + +/** Configures the type of signal being encoded. + * This is a hint which helps the encoder's mode selection. + * @see OPUS_GET_SIGNAL + * @param[in] x opus_int32: Allowed values: + *
    + *
    #OPUS_AUTO
    (default)
    + *
    #OPUS_SIGNAL_VOICE
    Bias thresholds towards choosing LPC or Hybrid modes.
    + *
    #OPUS_SIGNAL_MUSIC
    Bias thresholds towards choosing MDCT modes.
    + *
    + * @hideinitializer */ +#define OPUS_SET_SIGNAL(x) OPUS_SET_SIGNAL_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured signal type. + * @see OPUS_SET_SIGNAL + * @param[out] x opus_int32 *: Returns one of the following values: + *
    + *
    #OPUS_AUTO
    (default)
    + *
    #OPUS_SIGNAL_VOICE
    Bias thresholds towards choosing LPC or Hybrid modes.
    + *
    #OPUS_SIGNAL_MUSIC
    Bias thresholds towards choosing MDCT modes.
    + *
    + * @hideinitializer */ +#define OPUS_GET_SIGNAL(x) OPUS_GET_SIGNAL_REQUEST, __opus_check_int_ptr(x) + + +/** Configures the encoder's intended application. + * The initial value is a mandatory argument to the encoder_create function. + * @see OPUS_GET_APPLICATION + * @param[in] x opus_int32: Returns one of the following values: + *
    + *
    #OPUS_APPLICATION_VOIP
    + *
    Process signal for improved speech intelligibility.
    + *
    #OPUS_APPLICATION_AUDIO
    + *
    Favor faithfulness to the original input.
    + *
    #OPUS_APPLICATION_RESTRICTED_LOWDELAY
    + *
    Configure the minimum possible coding delay by disabling certain modes + * of operation.
    + *
    + * @hideinitializer */ +#define OPUS_SET_APPLICATION(x) OPUS_SET_APPLICATION_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured application. + * @see OPUS_SET_APPLICATION + * @param[out] x opus_int32 *: Returns one of the following values: + *
    + *
    #OPUS_APPLICATION_VOIP
    + *
    Process signal for improved speech intelligibility.
    + *
    #OPUS_APPLICATION_AUDIO
    + *
    Favor faithfulness to the original input.
    + *
    #OPUS_APPLICATION_RESTRICTED_LOWDELAY
    + *
    Configure the minimum possible coding delay by disabling certain modes + * of operation.
    + *
    + * @hideinitializer */ +#define OPUS_GET_APPLICATION(x) OPUS_GET_APPLICATION_REQUEST, __opus_check_int_ptr(x) + +/** Gets the sampling rate the encoder or decoder was initialized with. + * This simply returns the Fs value passed to opus_encoder_init() + * or opus_decoder_init(). + * @param[out] x opus_int32 *: Sampling rate of encoder or decoder. + * @hideinitializer + */ +#define OPUS_GET_SAMPLE_RATE(x) OPUS_GET_SAMPLE_RATE_REQUEST, __opus_check_int_ptr(x) + +/** Gets the total samples of delay added by the entire codec. + * This can be queried by the encoder and then the provided number of samples can be + * skipped on from the start of the decoder's output to provide time aligned input + * and output. From the perspective of a decoding application the real data begins this many + * samples late. + * + * The decoder contribution to this delay is identical for all decoders, but the + * encoder portion of the delay may vary from implementation to implementation, + * version to version, or even depend on the encoder's initial configuration. + * Applications needing delay compensation should call this CTL rather than + * hard-coding a value. + * @param[out] x opus_int32 *: Number of lookahead samples + * @hideinitializer */ +#define OPUS_GET_LOOKAHEAD(x) OPUS_GET_LOOKAHEAD_REQUEST, __opus_check_int_ptr(x) + +/** Configures the encoder's use of inband forward error correction (FEC). + * @note This is only applicable to the LPC layer + * @see OPUS_GET_INBAND_FEC + * @param[in] x opus_int32: Allowed values: + *
    + *
    0
    Disable inband FEC (default).
    + *
    1
    Enable inband FEC.
    + *
    + * @hideinitializer */ +#define OPUS_SET_INBAND_FEC(x) OPUS_SET_INBAND_FEC_REQUEST, __opus_check_int(x) +/** Gets encoder's configured use of inband forward error correction. + * @see OPUS_SET_INBAND_FEC + * @param[out] x opus_int32 *: Returns one of the following values: + *
    + *
    0
    Inband FEC disabled (default).
    + *
    1
    Inband FEC enabled.
    + *
    + * @hideinitializer */ +#define OPUS_GET_INBAND_FEC(x) OPUS_GET_INBAND_FEC_REQUEST, __opus_check_int_ptr(x) + +/** Configures the encoder's expected packet loss percentage. + * Higher values with trigger progressively more loss resistant behavior in the encoder + * at the expense of quality at a given bitrate in the lossless case, but greater quality + * under loss. + * @see OPUS_GET_PACKET_LOSS_PERC + * @param[in] x opus_int32: Loss percentage in the range 0-100, inclusive (default: 0). + * @hideinitializer */ +#define OPUS_SET_PACKET_LOSS_PERC(x) OPUS_SET_PACKET_LOSS_PERC_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured packet loss percentage. + * @see OPUS_SET_PACKET_LOSS_PERC + * @param[out] x opus_int32 *: Returns the configured loss percentage + * in the range 0-100, inclusive (default: 0). + * @hideinitializer */ +#define OPUS_GET_PACKET_LOSS_PERC(x) OPUS_GET_PACKET_LOSS_PERC_REQUEST, __opus_check_int_ptr(x) + +/** Configures the encoder's use of discontinuous transmission (DTX). + * @note This is only applicable to the LPC layer + * @see OPUS_GET_DTX + * @param[in] x opus_int32: Allowed values: + *
    + *
    0
    Disable DTX (default).
    + *
    1
    Enabled DTX.
    + *
    + * @hideinitializer */ +#define OPUS_SET_DTX(x) OPUS_SET_DTX_REQUEST, __opus_check_int(x) +/** Gets encoder's configured use of discontinuous transmission. + * @see OPUS_SET_DTX + * @param[out] x opus_int32 *: Returns one of the following values: + *
    + *
    0
    DTX disabled (default).
    + *
    1
    DTX enabled.
    + *
    + * @hideinitializer */ +#define OPUS_GET_DTX(x) OPUS_GET_DTX_REQUEST, __opus_check_int_ptr(x) +/** Configures the depth of signal being encoded. + * This is a hint which helps the encoder identify silence and near-silence. + * @see OPUS_GET_LSB_DEPTH + * @param[in] x opus_int32: Input precision in bits, between 8 and 24 + * (default: 24). + * @hideinitializer */ +#define OPUS_SET_LSB_DEPTH(x) OPUS_SET_LSB_DEPTH_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured signal depth. + * @see OPUS_SET_LSB_DEPTH + * @param[out] x opus_int32 *: Input precision in bits, between 8 and + * 24 (default: 24). + * @hideinitializer */ +#define OPUS_GET_LSB_DEPTH(x) OPUS_GET_LSB_DEPTH_REQUEST, __opus_check_int_ptr(x) + +/** Gets the duration (in samples) of the last packet successfully decoded or concealed. + * @param[out] x opus_int32 *: Number of samples (at current sampling rate). + * @hideinitializer */ +#define OPUS_GET_LAST_PACKET_DURATION(x) OPUS_GET_LAST_PACKET_DURATION_REQUEST, __opus_check_int_ptr(x) +/**@}*/ + +/** @defgroup opus_genericctls Generic CTLs + * + * These macros are used with the \c opus_decoder_ctl and + * \c opus_encoder_ctl calls to generate a particular + * request. + * + * When called on an \c OpusDecoder they apply to that + * particular decoder instance. When called on an + * \c OpusEncoder they apply to the corresponding setting + * on that encoder instance, if present. + * + * Some usage examples: + * + * @code + * int ret; + * opus_int32 pitch; + * ret = opus_decoder_ctl(dec_ctx, OPUS_GET_PITCH(&pitch)); + * if (ret == OPUS_OK) return ret; + * + * opus_encoder_ctl(enc_ctx, OPUS_RESET_STATE); + * opus_decoder_ctl(dec_ctx, OPUS_RESET_STATE); + * + * opus_int32 enc_bw, dec_bw; + * opus_encoder_ctl(enc_ctx, OPUS_GET_BANDWIDTH(&enc_bw)); + * opus_decoder_ctl(dec_ctx, OPUS_GET_BANDWIDTH(&dec_bw)); + * if (enc_bw != dec_bw) { + * printf("packet bandwidth mismatch!\n"); + * } + * @endcode + * + * @see opus_encoder, opus_decoder_ctl, opus_encoder_ctl, opus_decoderctls, opus_encoderctls + * @{ + */ + +/** Resets the codec state to be equivalent to a freshly initialized state. + * This should be called when switching streams in order to prevent + * the back to back decoding from giving different results from + * one at a time decoding. + * @hideinitializer */ +#define OPUS_RESET_STATE 4028 + +/** Gets the final state of the codec's entropy coder. + * This is used for testing purposes, + * The encoder and decoder state should be identical after coding a payload + * (assuming no data corruption or software bugs) + * + * @param[out] x opus_uint32 *: Entropy coder state + * + * @hideinitializer */ +#define OPUS_GET_FINAL_RANGE(x) OPUS_GET_FINAL_RANGE_REQUEST, __opus_check_uint_ptr(x) + +/** Gets the pitch of the last decoded frame, if available. + * This can be used for any post-processing algorithm requiring the use of pitch, + * e.g. time stretching/shortening. If the last frame was not voiced, or if the + * pitch was not coded in the frame, then zero is returned. + * + * This CTL is only implemented for decoder instances. + * + * @param[out] x opus_int32 *: pitch period at 48 kHz (or 0 if not available) + * + * @hideinitializer */ +#define OPUS_GET_PITCH(x) OPUS_GET_PITCH_REQUEST, __opus_check_int_ptr(x) + +/** Gets the encoder's configured bandpass or the decoder's last bandpass. + * @see OPUS_SET_BANDWIDTH + * @param[out] x opus_int32 *: Returns one of the following values: + *
    + *
    #OPUS_AUTO
    (default)
    + *
    #OPUS_BANDWIDTH_NARROWBAND
    4 kHz passband
    + *
    #OPUS_BANDWIDTH_MEDIUMBAND
    6 kHz passband
    + *
    #OPUS_BANDWIDTH_WIDEBAND
    8 kHz passband
    + *
    #OPUS_BANDWIDTH_SUPERWIDEBAND
    12 kHz passband
    + *
    #OPUS_BANDWIDTH_FULLBAND
    20 kHz passband
    + *
    + * @hideinitializer */ +#define OPUS_GET_BANDWIDTH(x) OPUS_GET_BANDWIDTH_REQUEST, __opus_check_int_ptr(x) + +/**@}*/ + +/** @defgroup opus_decoderctls Decoder related CTLs + * @see opus_genericctls, opus_encoderctls, opus_decoder + * @{ + */ + +/** Configures decoder gain adjustment. + * Scales the decoded output by a factor specified in Q8 dB units. + * This has a maximum range of -32768 to 32767 inclusive, and returns + * OPUS_BAD_ARG otherwise. The default is zero indicating no adjustment. + * This setting survives decoder reset. + * + * gain = pow(10, x/(20.0*256)) + * + * @param[in] x opus_int32: Amount to scale PCM signal by in Q8 dB units. + * @hideinitializer */ +#define OPUS_SET_GAIN(x) OPUS_SET_GAIN_REQUEST, __opus_check_int(x) +/** Gets the decoder's configured gain adjustment. @see OPUS_SET_GAIN + * + * @param[out] x opus_int32 *: Amount to scale PCM signal by in Q8 dB units. + * @hideinitializer */ +#define OPUS_GET_GAIN(x) OPUS_GET_GAIN_REQUEST, __opus_check_int_ptr(x) + +/**@}*/ + +/** @defgroup opus_libinfo Opus library information functions + * @{ + */ + +/** Converts an opus error code into a human readable string. + * + * @param[in] error int: Error number + * @returns Error string + */ +OPUS_EXPORT const char *opus_strerror(int error); + +/** Gets the libopus version string. + * + * @returns Version string + */ +OPUS_EXPORT const char *opus_get_version_string(void); +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* OPUS_DEFINES_H */ diff --git a/code/opus-1.0.2/include/opus_multistream.h b/code/opus-1.0.2/include/opus_multistream.h new file mode 100644 index 00000000..658067f7 --- /dev/null +++ b/code/opus-1.0.2/include/opus_multistream.h @@ -0,0 +1,632 @@ +/* Copyright (c) 2011 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (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 opus_multistream.h + * @brief Opus reference implementation multistream API + */ + +#ifndef OPUS_MULTISTREAM_H +#define OPUS_MULTISTREAM_H + +#include "opus.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @cond OPUS_INTERNAL_DOC */ + +/** Macros to trigger compilation errors when the wrong types are provided to a + * CTL. */ +/**@{*/ +#define __opus_check_encstate_ptr(ptr) ((ptr) + ((ptr) - (OpusEncoder**)(ptr))) +#define __opus_check_decstate_ptr(ptr) ((ptr) + ((ptr) - (OpusDecoder**)(ptr))) +/**@}*/ + +/** These are the actual encoder and decoder CTL ID numbers. + * They should not be used directly by applications. + * In general, SETs should be even and GETs should be odd.*/ +/**@{*/ +#define OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST 5120 +#define OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST 5122 +/**@}*/ + +/** @endcond */ + +/** @defgroup opus_multistream_ctls Multistream specific encoder and decoder CTLs + * + * These are convenience macros that are specific to the + * opus_multistream_encoder_ctl() and opus_multistream_decoder_ctl() + * interface. + * The CTLs from @ref opus_genericctls, @ref opus_encoderctls, and + * @ref opus_decoderctls may be applied to a multistream encoder or decoder as + * well. + * In addition, you may retrieve the encoder or decoder state for an specific + * stream via #OPUS_MULTISTREAM_GET_ENCODER_STATE or + * #OPUS_MULTISTREAM_GET_DECODER_STATE and apply CTLs to it individually. + */ +/**@{*/ + +/** Gets the encoder state for an individual stream of a multistream encoder. + * @param[in] x opus_int32: The index of the stream whose encoder you + * wish to retrieve. + * This must be non-negative and less than + * the streams parameter used + * to initialize the encoder. + * @param[out] y OpusEncoder**: Returns a pointer to the given + * encoder state. + * @retval OPUS_BAD_ARG The index of the requested stream was out of range. + * @hideinitializer + */ +#define OPUS_MULTISTREAM_GET_ENCODER_STATE(x,y) OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST, __opus_check_int(x), __opus_check_encstate_ptr(y) + +/** Gets the decoder state for an individual stream of a multistream decoder. + * @param[in] x opus_int32: The index of the stream whose decoder you + * wish to retrieve. + * This must be non-negative and less than + * the streams parameter used + * to initialize the decoder. + * @param[out] y OpusDecoder**: Returns a pointer to the given + * decoder state. + * @retval OPUS_BAD_ARG The index of the requested stream was out of range. + * @hideinitializer + */ +#define OPUS_MULTISTREAM_GET_DECODER_STATE(x,y) OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST, __opus_check_int(x), __opus_check_decstate_ptr(y) + +/**@}*/ + +/** @defgroup opus_multistream Opus Multistream API + * @{ + * + * The multistream API allows individual Opus streams to be combined into a + * single packet, enabling support for up to 255 channels. Unlike an + * elementary Opus stream, the encoder and decoder must negotiate the channel + * configuration before the decoder can successfully interpret the data in the + * packets produced by the encoder. Some basic information, such as packet + * duration, can be computed without any special negotiation. + * + * The format for multistream Opus packets is defined in the + * Ogg + * encapsulation specification and is based on the self-delimited Opus + * framing described in Appendix B of RFC 6716. + * Normal Opus packets are just a degenerate case of multistream Opus packets, + * and can be encoded or decoded with the multistream API by setting + * streams to 1 when initializing the encoder or + * decoder. + * + * Multistream Opus streams can contain up to 255 elementary Opus streams. + * These may be either "uncoupled" or "coupled", indicating that the decoder + * is configured to decode them to either 1 or 2 channels, respectively. + * The streams are ordered so that all coupled streams appear at the + * beginning. + * + * A mapping table defines which decoded channel i + * should be used for each input/output (I/O) channel j. This table is + * typically provided as an unsigned char array. + * Let i = mapping[j] be the index for I/O channel j. + * If i < 2*coupled_streams, then I/O channel j is + * encoded as the left channel of stream (i/2) if i + * is even, or as the right channel of stream (i/2) if + * i is odd. Otherwise, I/O channel j is encoded as + * mono in stream (i - coupled_streams), unless it has the special + * value 255, in which case it is omitted from the encoding entirely (the + * decoder will reproduce it as silence). Each value i must either + * be the special value 255 or be less than streams + coupled_streams. + * + * The output channels specified by the encoder + * should use the + * Vorbis + * channel ordering. A decoder may wish to apply an additional permutation + * to the mapping the encoder used to achieve a different output channel + * order (e.g. for outputing in WAV order). + * + * Each multistream packet contains an Opus packet for each stream, and all of + * the Opus packets in a single multistream packet must have the same + * duration. Therefore the duration of a multistream packet can be extracted + * from the TOC sequence of the first stream, which is located at the + * beginning of the packet, just like an elementary Opus stream: + * + * @code + * int nb_samples; + * int nb_frames; + * nb_frames = opus_packet_get_nb_frames(data, len); + * if (nb_frames < 1) + * return nb_frames; + * nb_samples = opus_packet_get_samples_per_frame(data, 48000) * nb_frames; + * @endcode + * + * The general encoding and decoding process proceeds exactly the same as in + * the normal @ref opus_encoder and @ref opus_decoder APIs. + * See their documentation for an overview of how to use the corresponding + * multistream functions. + */ + +/** Opus multistream encoder state. + * This contains the complete state of a multistream Opus encoder. + * It is position independent and can be freely copied. + * @see opus_multistream_encoder_create + * @see opus_multistream_encoder_init + */ +typedef struct OpusMSEncoder OpusMSEncoder; + +/** Opus multistream decoder state. + * This contains the complete state of a multistream Opus decoder. + * It is position independent and can be freely copied. + * @see opus_multistream_decoder_create + * @see opus_multistream_decoder_init + */ +typedef struct OpusMSDecoder OpusMSDecoder; + +/**\name Multistream encoder functions */ +/**@{*/ + +/** Gets the size of an OpusMSEncoder structure. + * @param streams int: The total number of streams to encode from the + * input. + * This must be no more than 255. + * @param coupled_streams int: Number of coupled (2 channel) streams + * to encode. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * encoded channels (streams + + * coupled_streams) must be no + * more than 255. + * @returns The size in bytes on success, or a negative error code + * (see @ref opus_errorcodes) on error. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_encoder_get_size( + int streams, + int coupled_streams +); + +/** Allocates and initializes a multistream encoder state. + * Call opus_multistream_encoder_destroy() to release + * this object when finished. + * @param Fs opus_int32: Sampling rate of the input signal (in Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param channels int: Number of channels in the input signal. + * This must be at most 255. + * It may be greater than the number of + * coded channels (streams + + * coupled_streams). + * @param streams int: The total number of streams to encode from the + * input. + * This must be no more than the number of channels. + * @param coupled_streams int: Number of coupled (2 channel) streams + * to encode. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * encoded channels (streams + + * coupled_streams) must be no + * more than the number of input channels. + * @param[in] mapping const unsigned char[channels]: Mapping from + * encoded channels to input channels, as described in + * @ref opus_multistream. As an extra constraint, the + * multistream encoder does not allow encoding coupled + * streams for which one channel is unused since this + * is never a good idea. + * @param application int: The target encoder application. + * This must be one of the following: + *
    + *
    #OPUS_APPLICATION_VOIP
    + *
    Process signal for improved speech intelligibility.
    + *
    #OPUS_APPLICATION_AUDIO
    + *
    Favor faithfulness to the original input.
    + *
    #OPUS_APPLICATION_RESTRICTED_LOWDELAY
    + *
    Configure the minimum possible coding delay by disabling certain modes + * of operation.
    + *
    + * @param[out] error int *: Returns #OPUS_OK on success, or an error + * code (see @ref opus_errorcodes) on + * failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusMSEncoder *opus_multistream_encoder_create( + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping, + int application, + int *error +) OPUS_ARG_NONNULL(5); + +/** Initialize a previously allocated multistream encoder state. + * The memory pointed to by \a st must be at least the size returned by + * opus_multistream_encoder_get_size(). + * This is intended for applications which use their own allocator instead of + * malloc. + * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL. + * @see opus_multistream_encoder_create + * @see opus_multistream_encoder_get_size + * @param st OpusMSEncoder*: Multistream encoder state to initialize. + * @param Fs opus_int32: Sampling rate of the input signal (in Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param channels int: Number of channels in the input signal. + * This must be at most 255. + * It may be greater than the number of + * coded channels (streams + + * coupled_streams). + * @param streams int: The total number of streams to encode from the + * input. + * This must be no more than the number of channels. + * @param coupled_streams int: Number of coupled (2 channel) streams + * to encode. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * encoded channels (streams + + * coupled_streams) must be no + * more than the number of input channels. + * @param[in] mapping const unsigned char[channels]: Mapping from + * encoded channels to input channels, as described in + * @ref opus_multistream. As an extra constraint, the + * multistream encoder does not allow encoding coupled + * streams for which one channel is unused since this + * is never a good idea. + * @param application int: The target encoder application. + * This must be one of the following: + *
    + *
    #OPUS_APPLICATION_VOIP
    + *
    Process signal for improved speech intelligibility.
    + *
    #OPUS_APPLICATION_AUDIO
    + *
    Favor faithfulness to the original input.
    + *
    #OPUS_APPLICATION_RESTRICTED_LOWDELAY
    + *
    Configure the minimum possible coding delay by disabling certain modes + * of operation.
    + *
    + * @returns #OPUS_OK on success, or an error code (see @ref opus_errorcodes) + * on failure. + */ +OPUS_EXPORT int opus_multistream_encoder_init( + OpusMSEncoder *st, + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping, + int application +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(6); + +/** Encodes a multistream Opus frame. + * @param st OpusMSEncoder*: Multistream encoder state. + * @param[in] pcm const opus_int16*: The input signal as interleaved + * samples. + * This must contain + * frame_size*channels + * samples. + * @param frame_size int: Number of samples per channel in the input + * signal. + * This must be an Opus frame size for the + * encoder's sampling rate. + * For example, at 48 kHz the permitted values + * are 120, 240, 480, 960, 1920, and 2880. + * Passing in a duration of less than 10 ms + * (480 samples at 48 kHz) will prevent the + * encoder from using the LPC or hybrid modes. + * @param[out] data unsigned char*: Output payload. + * This must contain storage for at + * least \a max_data_bytes. + * @param [in] max_data_bytes opus_int32: Size of the allocated + * memory for the output + * payload. This may be + * used to impose an upper limit on + * the instant bitrate, but should + * not be used as the only bitrate + * control. Use #OPUS_SET_BITRATE to + * control the bitrate. + * @returns The length of the encoded packet (in bytes) on success or a + * negative error code (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_encode( + OpusMSEncoder *st, + const opus_int16 *pcm, + int frame_size, + unsigned char *data, + opus_int32 max_data_bytes +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); + +/** Encodes a multistream Opus frame from floating point input. + * @param st OpusMSEncoder*: Multistream encoder state. + * @param[in] pcm const float*: The input signal as interleaved + * samples with a normal range of + * +/-1.0. + * Samples with a range beyond +/-1.0 + * are supported but will be clipped by + * decoders using the integer API and + * should only be used if it is known + * that the far end supports extended + * dynamic range. + * This must contain + * frame_size*channels + * samples. + * @param frame_size int: Number of samples per channel in the input + * signal. + * This must be an Opus frame size for the + * encoder's sampling rate. + * For example, at 48 kHz the permitted values + * are 120, 240, 480, 960, 1920, and 2880. + * Passing in a duration of less than 10 ms + * (480 samples at 48 kHz) will prevent the + * encoder from using the LPC or hybrid modes. + * @param[out] data unsigned char*: Output payload. + * This must contain storage for at + * least \a max_data_bytes. + * @param [in] max_data_bytes opus_int32: Size of the allocated + * memory for the output + * payload. This may be + * used to impose an upper limit on + * the instant bitrate, but should + * not be used as the only bitrate + * control. Use #OPUS_SET_BITRATE to + * control the bitrate. + * @returns The length of the encoded packet (in bytes) on success or a + * negative error code (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_encode_float( + OpusMSEncoder *st, + const float *pcm, + int frame_size, + unsigned char *data, + opus_int32 max_data_bytes +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); + +/** Frees an OpusMSEncoder allocated by + * opus_multistream_encoder_create(). + * @param st OpusMSEncoder*: Multistream encoder state to be freed. + */ +OPUS_EXPORT void opus_multistream_encoder_destroy(OpusMSEncoder *st); + +/** Perform a CTL function on a multistream Opus encoder. + * + * Generally the request and subsequent arguments are generated by a + * convenience macro. + * @param st OpusMSEncoder*: Multistream encoder state. + * @param request This and all remaining parameters should be replaced by one + * of the convenience macros in @ref opus_genericctls, + * @ref opus_encoderctls, or @ref opus_multistream_ctls. + * @see opus_genericctls + * @see opus_encoderctls + * @see opus_multistream_ctls + */ +OPUS_EXPORT int opus_multistream_encoder_ctl(OpusMSEncoder *st, int request, ...) OPUS_ARG_NONNULL(1); + +/**@}*/ + +/**\name Multistream decoder functions */ +/**@{*/ + +/** Gets the size of an OpusMSDecoder structure. + * @param streams int: The total number of streams coded in the + * input. + * This must be no more than 255. + * @param coupled_streams int: Number streams to decode as coupled + * (2 channel) streams. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * coded channels (streams + + * coupled_streams) must be no + * more than 255. + * @returns The size in bytes on success, or a negative error code + * (see @ref opus_errorcodes) on error. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_decoder_get_size( + int streams, + int coupled_streams +); + +/** Allocates and initializes a multistream decoder state. + * Call opus_multistream_decoder_destroy() to release + * this object when finished. + * @param Fs opus_int32: Sampling rate to decode at (in Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param channels int: Number of channels to output. + * This must be at most 255. + * It may be different from the number of coded + * channels (streams + + * coupled_streams). + * @param streams int: The total number of streams coded in the + * input. + * This must be no more than 255. + * @param coupled_streams int: Number of streams to decode as coupled + * (2 channel) streams. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * coded channels (streams + + * coupled_streams) must be no + * more than 255. + * @param[in] mapping const unsigned char[channels]: Mapping from + * coded channels to output channels, as described in + * @ref opus_multistream. + * @param[out] error int *: Returns #OPUS_OK on success, or an error + * code (see @ref opus_errorcodes) on + * failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusMSDecoder *opus_multistream_decoder_create( + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping, + int *error +) OPUS_ARG_NONNULL(5); + +/** Intialize a previously allocated decoder state object. + * The memory pointed to by \a st must be at least the size returned by + * opus_multistream_encoder_get_size(). + * This is intended for applications which use their own allocator instead of + * malloc. + * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL. + * @see opus_multistream_decoder_create + * @see opus_multistream_deocder_get_size + * @param st OpusMSEncoder*: Multistream encoder state to initialize. + * @param Fs opus_int32: Sampling rate to decode at (in Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param channels int: Number of channels to output. + * This must be at most 255. + * It may be different from the number of coded + * channels (streams + + * coupled_streams). + * @param streams int: The total number of streams coded in the + * input. + * This must be no more than 255. + * @param coupled_streams int: Number of streams to decode as coupled + * (2 channel) streams. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * coded channels (streams + + * coupled_streams) must be no + * more than 255. + * @param[in] mapping const unsigned char[channels]: Mapping from + * coded channels to output channels, as described in + * @ref opus_multistream. + * @returns #OPUS_OK on success, or an error code (see @ref opus_errorcodes) + * on failure. + */ +OPUS_EXPORT int opus_multistream_decoder_init( + OpusMSDecoder *st, + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(6); + +/** Decode a multistream Opus packet. + * @param st OpusMSDecoder*: Multistream decoder state. + * @param[in] data const unsigned char*: Input payload. + * Use a NULL + * pointer to indicate packet + * loss. + * @param len opus_int32: Number of bytes in payload. + * @param[out] pcm opus_int16*: Output signal, with interleaved + * samples. + * This must contain room for + * frame_size*channels + * samples. + * @param frame_size int: The number of samples per channel of + * available space in \a pcm. + * If this is less than the maximum packet duration + * (120 ms; 5760 for 48kHz), this function will not be capable + * of decoding some packets. In the case of PLC (data==NULL) + * or FEC (decode_fec=1), then frame_size needs to be exactly + * the duration of audio that is missing, otherwise the + * decoder will not be in the optimal state to decode the + * next incoming packet. For the PLC and FEC cases, frame_size + * must be a multiple of 2.5 ms. + * @param decode_fec int: Flag (0 or 1) to request that any in-band + * forward error correction data be decoded. + * If no such data is available, the frame is + * decoded as if it were lost. + * @returns Number of samples decoded on success or a negative error code + * (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_decode( + OpusMSDecoder *st, + const unsigned char *data, + opus_int32 len, + opus_int16 *pcm, + int frame_size, + int decode_fec +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + +/** Decode a multistream Opus packet with floating point output. + * @param st OpusMSDecoder*: Multistream decoder state. + * @param[in] data const unsigned char*: Input payload. + * Use a NULL + * pointer to indicate packet + * loss. + * @param len opus_int32: Number of bytes in payload. + * @param[out] pcm opus_int16*: Output signal, with interleaved + * samples. + * This must contain room for + * frame_size*channels + * samples. + * @param frame_size int: The number of samples per channel of + * available space in \a pcm. + * If this is less than the maximum packet duration + * (120 ms; 5760 for 48kHz), this function will not be capable + * of decoding some packets. In the case of PLC (data==NULL) + * or FEC (decode_fec=1), then frame_size needs to be exactly + * the duration of audio that is missing, otherwise the + * decoder will not be in the optimal state to decode the + * next incoming packet. For the PLC and FEC cases, frame_size + * must be a multiple of 2.5 ms. + * @param decode_fec int: Flag (0 or 1) to request that any in-band + * forward error correction data be decoded. + * If no such data is available, the frame is + * decoded as if it were lost. + * @returns Number of samples decoded on success or a negative error code + * (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_decode_float( + OpusMSDecoder *st, + const unsigned char *data, + opus_int32 len, + float *pcm, + int frame_size, + int decode_fec +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + +/** Perform a CTL function on a multistream Opus decoder. + * + * Generally the request and subsequent arguments are generated by a + * convenience macro. + * @param st OpusMSDecoder*: Multistream decoder state. + * @param request This and all remaining parameters should be replaced by one + * of the convenience macros in @ref opus_genericctls, + * @ref opus_decoderctls, or @ref opus_multistream_ctls. + * @see opus_genericctls + * @see opus_decoderctls + * @see opus_multistream_ctls + */ +OPUS_EXPORT int opus_multistream_decoder_ctl(OpusMSDecoder *st, int request, ...) OPUS_ARG_NONNULL(1); + +/** Frees an OpusMSDecoder allocated by + * opus_multistream_decoder_create(). + * @param st OpusMSDecoder: Multistream decoder state to be freed. + */ +OPUS_EXPORT void opus_multistream_decoder_destroy(OpusMSDecoder *st); + +/**@}*/ + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* OPUS_MULTISTREAM_H */ diff --git a/code/opus-1.0.2/include/opus_types.h b/code/opus-1.0.2/include/opus_types.h new file mode 100644 index 00000000..b28e03ae --- /dev/null +++ b/code/opus-1.0.2/include/opus_types.h @@ -0,0 +1,159 @@ +/* (C) COPYRIGHT 1994-2002 Xiph.Org Foundation */ +/* Modified by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/* opus_types.h based on ogg_types.h from libogg */ + +/** + @file opus_types.h + @brief Opus reference implementation types +*/ +#ifndef OPUS_TYPES_H +#define OPUS_TYPES_H + +/* Use the real stdint.h if it's there (taken from Paul Hsieh's pstdint.h) */ +#if (defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_)) || defined (HAVE_STDINT_H)) +#include + + typedef int16_t opus_int16; + typedef uint16_t opus_uint16; + typedef int32_t opus_int32; + typedef uint32_t opus_uint32; +#elif defined(_WIN32) + +# if defined(__CYGWIN__) +# include <_G_config.h> + typedef _G_int32_t opus_int32; + typedef _G_uint32_t opus_uint32; + typedef _G_int16 opus_int16; + typedef _G_uint16 opus_uint16; +# elif defined(__MINGW32__) + typedef short opus_int16; + typedef unsigned short opus_uint16; + typedef int opus_int32; + typedef unsigned int opus_uint32; +# elif defined(__MWERKS__) + typedef int opus_int32; + typedef unsigned int opus_uint32; + typedef short opus_int16; + typedef unsigned short opus_uint16; +# else + /* MSVC/Borland */ + typedef __int32 opus_int32; + typedef unsigned __int32 opus_uint32; + typedef __int16 opus_int16; + typedef unsigned __int16 opus_uint16; +# endif + +#elif defined(__MACOS__) + +# include + typedef SInt16 opus_int16; + typedef UInt16 opus_uint16; + typedef SInt32 opus_int32; + typedef UInt32 opus_uint32; + +#elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */ + +# include + typedef int16_t opus_int16; + typedef u_int16_t opus_uint16; + typedef int32_t opus_int32; + typedef u_int32_t opus_uint32; + +#elif defined(__BEOS__) + + /* Be */ +# include + typedef int16 opus_int16; + typedef u_int16 opus_uint16; + typedef int32_t opus_int32; + typedef u_int32_t opus_uint32; + +#elif defined (__EMX__) + + /* OS/2 GCC */ + typedef short opus_int16; + typedef unsigned short opus_uint16; + typedef int opus_int32; + typedef unsigned int opus_uint32; + +#elif defined (DJGPP) + + /* DJGPP */ + typedef short opus_int16; + typedef unsigned short opus_uint16; + typedef int opus_int32; + typedef unsigned int opus_uint32; + +#elif defined(R5900) + + /* PS2 EE */ + typedef int opus_int32; + typedef unsigned opus_uint32; + typedef short opus_int16; + typedef unsigned short opus_uint16; + +#elif defined(__SYMBIAN32__) + + /* Symbian GCC */ + typedef signed short opus_int16; + typedef unsigned short opus_uint16; + typedef signed int opus_int32; + typedef unsigned int opus_uint32; + +#elif defined(CONFIG_TI_C54X) || defined (CONFIG_TI_C55X) + + typedef short opus_int16; + typedef unsigned short opus_uint16; + typedef long opus_int32; + typedef unsigned long opus_uint32; + +#elif defined(CONFIG_TI_C6X) + + typedef short opus_int16; + typedef unsigned short opus_uint16; + typedef int opus_int32; + typedef unsigned int opus_uint32; + +#else + + /* Give up, take a reasonable guess */ + typedef short opus_int16; + typedef unsigned short opus_uint16; + typedef int opus_int32; + typedef unsigned int opus_uint32; + +#endif + +#define opus_int int /* used for counters etc; at least 16 bits */ +#define opus_int64 long long +#define opus_int8 signed char + +#define opus_uint unsigned int /* used for counters etc; at least 16 bits */ +#define opus_uint64 unsigned long long +#define opus_uint8 unsigned char + +#endif /* OPUS_TYPES_H */ diff --git a/code/opus-1.0.2/silk/A2NLSF.c b/code/opus-1.0.2/silk/A2NLSF.c new file mode 100644 index 00000000..49d5d9d9 --- /dev/null +++ b/code/opus-1.0.2/silk/A2NLSF.c @@ -0,0 +1,252 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (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 */ +/* functions are accurate inverses of each other */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "tables.h" + +/* Number of binary divisions, when not in low complexity mode */ +#define BIN_DIV_STEPS_A2NLSF_FIX 3 /* must be no higher than 16 - log2( LSF_COS_TAB_SZ_FIX ) */ +#define MAX_ITERATIONS_A2NLSF_FIX 30 + +/* Helper function for A2NLSF(..) */ +/* Transforms polynomials from cos(n*f) to cos(f)^n */ +static inline void silk_A2NLSF_trans_poly( + opus_int32 *p, /* I/O Polynomial */ + const opus_int dd /* I Polynomial order (= filter order / 2 ) */ +) +{ + opus_int k, n; + + for( k = 2; k <= dd; k++ ) { + for( n = dd; n > k; n-- ) { + p[ n - 2 ] -= p[ n ]; + } + p[ k - 2 ] -= silk_LSHIFT( p[ k ], 1 ); + } +} +/* Helper function for A2NLSF(..) */ +/* Polynomial evaluation */ +static inline opus_int32 silk_A2NLSF_eval_poly( /* return the polynomial evaluation, in Q16 */ + opus_int32 *p, /* I Polynomial, Q16 */ + const opus_int32 x, /* I Evaluation point, Q12 */ + const opus_int dd /* I Order */ +) +{ + opus_int n; + opus_int32 x_Q16, y32; + + y32 = p[ dd ]; /* Q16 */ + x_Q16 = silk_LSHIFT( x, 4 ); + for( n = dd - 1; n >= 0; n-- ) { + y32 = silk_SMLAWW( p[ n ], y32, x_Q16 ); /* Q16 */ + } + return y32; +} + +static inline void silk_A2NLSF_init( + const opus_int32 *a_Q16, + opus_int32 *P, + opus_int32 *Q, + const opus_int dd +) +{ + opus_int k; + + /* Convert filter coefs to even and odd polynomials */ + P[dd] = silk_LSHIFT( 1, 16 ); + Q[dd] = silk_LSHIFT( 1, 16 ); + for( k = 0; k < dd; k++ ) { + P[ k ] = -a_Q16[ dd - k - 1 ] - a_Q16[ dd + k ]; /* Q16 */ + Q[ k ] = -a_Q16[ dd - k - 1 ] + a_Q16[ dd + k ]; /* Q16 */ + } + + /* 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 */ + silk_A2NLSF_trans_poly( P, dd ); + 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 silk_A2NLSF( + opus_int16 *NLSF, /* O Normalized Line Spectral Frequencies in Q15 (0..2^15-1) [d] */ + opus_int32 *a_Q16, /* I/O Monic whitening filter coefficients in Q16 [d] */ + const opus_int d /* I Filter order (must be even) */ +) +{ + opus_int i, k, m, dd, root_ix, ffrac; + opus_int32 xlo, xhi, xmid; + opus_int32 ylo, yhi, ymid, thr; + opus_int32 nom, den; + opus_int32 P[ SILK_MAX_ORDER_LPC / 2 + 1 ]; + opus_int32 Q[ SILK_MAX_ORDER_LPC / 2 + 1 ]; + opus_int32 *PQ[ 2 ]; + opus_int32 *p; + + /* Store pointers to array */ + PQ[ 0 ] = P; + PQ[ 1 ] = Q; + + dd = silk_RSHIFT( d, 1 ); + + silk_A2NLSF_init( a_Q16, P, Q, dd ); + + /* Find roots, alternating between P and Q */ + p = P; /* Pointer to polynomial */ + + xlo = silk_LSFCosTab_FIX_Q12[ 0 ]; /* Q12*/ + ylo = 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 = 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 */ + thr = 0; + while( 1 ) { + /* Evaluate polynomial */ + xhi = silk_LSFCosTab_FIX_Q12[ k ]; /* Q12 */ + yhi = silk_A2NLSF_eval_poly( p, xhi, dd ); + + /* Detect zero crossing */ + if( ( ylo <= 0 && yhi >= thr ) || ( ylo >= 0 && yhi <= -thr ) ) { + if( yhi == 0 ) { + /* If the root lies exactly at the end of the current */ + /* interval, look for the next root in the next interval */ + thr = 1; + } else { + thr = 0; + } + /* Binary division */ + ffrac = -256; + for( m = 0; m < BIN_DIV_STEPS_A2NLSF_FIX; m++ ) { + /* Evaluate polynomial */ + xmid = silk_RSHIFT_ROUND( xlo + xhi, 1 ); + ymid = 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; + ffrac = silk_ADD_RSHIFT( ffrac, 128, m ); + } + } + + /* Interpolate */ + if( silk_abs( ylo ) < 65536 ) { + /* Avoid dividing by zero */ + den = ylo - yhi; + nom = silk_LSHIFT( ylo, 8 - BIN_DIV_STEPS_A2NLSF_FIX ) + silk_RSHIFT( den, 1 ); + if( den != 0 ) { + ffrac += silk_DIV32( nom, den ); + } + } else { + /* No risk of dividing by zero because abs(ylo - yhi) >= abs(ylo) >= 65536 */ + ffrac += silk_DIV32( ylo, silk_RSHIFT( ylo - yhi, 8 - BIN_DIV_STEPS_A2NLSF_FIX ) ); + } + NLSF[ root_ix ] = (opus_int16)silk_min_32( silk_LSHIFT( (opus_int32)k, 8 ) + ffrac, silk_int16_MAX ); + + silk_assert( NLSF[ root_ix ] >= 0 ); + + root_ix++; /* Next root */ + if( root_ix >= d ) { + /* Found all roots */ + break; + } + /* Alternate pointer to polynomial */ + p = PQ[ root_ix & 1 ]; + + /* Evaluate polynomial */ + xlo = silk_LSFCosTab_FIX_Q12[ k - 1 ]; /* Q12*/ + ylo = silk_LSHIFT( 1 - ( root_ix & 2 ), 12 ); + } else { + /* Increment loop counter */ + k++; + xlo = xhi; + ylo = yhi; + thr = 0; + + if( k > LSF_COS_TAB_SZ_FIX ) { + i++; + if( i > MAX_ITERATIONS_A2NLSF_FIX ) { + /* Set NLSFs to white spectrum and exit */ + NLSF[ 0 ] = (opus_int16)silk_DIV32_16( 1 << 15, d + 1 ); + for( k = 1; k < d; k++ ) { + NLSF[ k ] = (opus_int16)silk_SMULBB( k + 1, NLSF[ 0 ] ); + } + return; + } + + /* Error: Apply progressively more bandwidth expansion and run again */ + silk_bwexpander_32( a_Q16, d, 65536 - silk_SMULBB( 10 + i, i ) ); /* 10_Q16 = 0.00015*/ + + silk_A2NLSF_init( a_Q16, P, Q, dd ); + p = P; /* Pointer to polynomial */ + xlo = silk_LSFCosTab_FIX_Q12[ 0 ]; /* Q12*/ + ylo = 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 = 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/code/opus-1.0.2/silk/API.h b/code/opus-1.0.2/silk/API.h new file mode 100644 index 00000000..4b8ca12a --- /dev/null +++ b/code/opus-1.0.2/silk/API.h @@ -0,0 +1,132 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (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 SILK_API_H +#define SILK_API_H + +#include "control.h" +#include "typedef.h" +#include "errors.h" +#include "entenc.h" +#include "entdec.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define SILK_MAX_FRAMES_PER_PACKET 3 + +/* Struct for TOC (Table of Contents) */ +typedef struct { + opus_int VADFlag; /* Voice activity for packet */ + opus_int VADFlags[ SILK_MAX_FRAMES_PER_PACKET ]; /* Voice activity for each frame in packet */ + opus_int inbandFECFlag; /* Flag indicating if packet contains in-band FEC */ +} silk_TOC_struct; + +/****************************************/ +/* Encoder functions */ +/****************************************/ + +/***********************************************/ +/* Get size in bytes of the Silk encoder state */ +/***********************************************/ +opus_int silk_Get_Encoder_Size( /* O Returns error code */ + opus_int *encSizeBytes /* O Number of bytes in SILK encoder state */ +); + +/*************************/ +/* Init or reset encoder */ +/*************************/ +opus_int silk_InitEncoder( /* O Returns error code */ + void *encState, /* I/O State */ + silk_EncControlStruct *encStatus /* O Encoder Status */ +); + +/**************************/ +/* Encode frame with Silk */ +/**************************/ +/* Note: if prefillFlag is set, the input must contain 10 ms of audio, irrespective of what */ +/* encControl->payloadSize_ms is set to */ +opus_int silk_Encode( /* O Returns error code */ + void *encState, /* I/O State */ + silk_EncControlStruct *encControl, /* I Control status */ + const opus_int16 *samplesIn, /* I Speech sample input vector */ + opus_int nSamplesIn, /* I Number of samples in input vector */ + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int32 *nBytesOut, /* I/O Number of bytes in payload (input: Max bytes) */ + const opus_int prefillFlag /* I Flag to indicate prefilling buffers no coding */ +); + +/****************************************/ +/* Decoder functions */ +/****************************************/ + +/***********************************************/ +/* Get size in bytes of the Silk decoder state */ +/***********************************************/ +opus_int silk_Get_Decoder_Size( /* O Returns error code */ + opus_int *decSizeBytes /* O Number of bytes in SILK decoder state */ +); + +/*************************/ +/* Init or Reset decoder */ +/*************************/ +opus_int silk_InitDecoder( /* O Returns error code */ + void *decState /* I/O State */ +); + +/******************/ +/* Decode a frame */ +/******************/ +opus_int silk_Decode( /* O Returns error code */ + void* decState, /* I/O State */ + silk_DecControlStruct* decControl, /* I/O Control Structure */ + opus_int lostFlag, /* I 0: no loss, 1 loss, 2 decode fec */ + opus_int newPacketFlag, /* I Indicates first decoder call for this packet */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int16 *samplesOut, /* O Decoded output speech vector */ + opus_int32 *nSamplesOut /* O Number of samples decoded */ +); + +#if 0 +/**************************************/ +/* Get table of contents for a packet */ +/**************************************/ +opus_int silk_get_TOC( + const opus_uint8 *payload, /* I Payload data */ + const opus_int nBytesIn, /* I Number of input bytes */ + const opus_int nFramesPerPayload, /* I Number of SILK frames per payload */ + silk_TOC_struct *Silk_TOC /* O Type of content */ +); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/code/opus-1.0.2/silk/CNG.c b/code/opus-1.0.2/silk/CNG.c new file mode 100644 index 00000000..d0a619c1 --- /dev/null +++ b/code/opus-1.0.2/silk/CNG.c @@ -0,0 +1,167 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Generates excitation for CNG LPC synthesis */ +static inline void silk_CNG_exc( + opus_int32 residual_Q10[], /* O CNG residual signal Q10 */ + opus_int32 exc_buf_Q14[], /* I Random samples buffer Q10 */ + opus_int32 Gain_Q16, /* I Gain to apply */ + opus_int length, /* I Length */ + opus_int32 *rand_seed /* I/O Seed to random index generator */ +) +{ + opus_int32 seed; + opus_int i, idx, exc_mask; + + exc_mask = CNG_BUF_MASK_MAX; + while( exc_mask > length ) { + exc_mask = silk_RSHIFT( exc_mask, 1 ); + } + + seed = *rand_seed; + for( i = 0; i < length; i++ ) { + seed = silk_RAND( seed ); + idx = (opus_int)( silk_RSHIFT( seed, 24 ) & exc_mask ); + silk_assert( idx >= 0 ); + silk_assert( idx <= CNG_BUF_MASK_MAX ); + residual_Q10[ i ] = (opus_int16)silk_SAT16( silk_SMULWW( exc_buf_Q14[ idx ], Gain_Q16 >> 4 ) ); + } + *rand_seed = seed; +} + +void silk_CNG_Reset( + silk_decoder_state *psDec /* I/O Decoder state */ +) +{ + opus_int i, NLSF_step_Q15, NLSF_acc_Q15; + + NLSF_step_Q15 = silk_DIV32_16( silk_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 silk_CNG( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int16 frame[], /* I/O Signal */ + opus_int length /* I Length of residual */ +) +{ + opus_int i, subfr; + opus_int32 sum_Q6, max_Gain_Q16; + opus_int16 A_Q12[ MAX_LPC_ORDER ]; + opus_int32 CNG_sig_Q10[ MAX_FRAME_LENGTH + MAX_LPC_ORDER ]; + silk_CNG_struct *psCNG = &psDec->sCNG; + + if( psDec->fs_kHz != psCNG->fs_kHz ) { + /* Reset state */ + silk_CNG_Reset( psDec ); + + psCNG->fs_kHz = psDec->fs_kHz; + } + if( psDec->lossCnt == 0 && psDec->prevSignalType == TYPE_NO_VOICE_ACTIVITY ) { + /* Update CNG parameters */ + + /* Smoothing of LSF's */ + for( i = 0; i < psDec->LPC_order; i++ ) { + psCNG->CNG_smth_NLSF_Q15[ i ] += silk_SMULWB( (opus_int32)psDec->prevNLSF_Q15[ i ] - (opus_int32)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 < psDec->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 */ + silk_memmove( &psCNG->CNG_exc_buf_Q14[ psDec->subfr_length ], psCNG->CNG_exc_buf_Q14, ( psDec->nb_subfr - 1 ) * psDec->subfr_length * sizeof( opus_int32 ) ); + silk_memcpy( psCNG->CNG_exc_buf_Q14, &psDec->exc_Q14[ subfr * psDec->subfr_length ], psDec->subfr_length * sizeof( opus_int32 ) ); + + /* Smooth gains */ + for( i = 0; i < psDec->nb_subfr; i++ ) { + psCNG->CNG_smth_Gain_Q16 += silk_SMULWB( psDecCtrl->Gains_Q16[ i ] - psCNG->CNG_smth_Gain_Q16, CNG_GAIN_SMTH_Q16 ); + } + } + + /* Add CNG when packet is lost or during DTX */ + if( psDec->lossCnt ) { + + /* Generate CNG excitation */ + silk_CNG_exc( CNG_sig_Q10 + MAX_LPC_ORDER, psCNG->CNG_exc_buf_Q14, psCNG->CNG_smth_Gain_Q16, length, &psCNG->rand_seed ); + + /* Convert CNG NLSF to filter representation */ + silk_NLSF2A( A_Q12, psCNG->CNG_smth_NLSF_Q15, psDec->LPC_order ); + + /* Generate CNG signal, by synthesis filtering */ + silk_memcpy( CNG_sig_Q10, psCNG->CNG_synth_state, MAX_LPC_ORDER * sizeof( opus_int32 ) ); + for( i = 0; i < length; i++ ) { + silk_assert( psDec->LPC_order == 10 || psDec->LPC_order == 16 ); + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + sum_Q6 = silk_RSHIFT( psDec->LPC_order, 1 ); + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 1 ], A_Q12[ 0 ] ); + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 2 ], A_Q12[ 1 ] ); + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 3 ], A_Q12[ 2 ] ); + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 4 ], A_Q12[ 3 ] ); + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 5 ], A_Q12[ 4 ] ); + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 6 ], A_Q12[ 5 ] ); + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 7 ], A_Q12[ 6 ] ); + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 8 ], A_Q12[ 7 ] ); + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 9 ], A_Q12[ 8 ] ); + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 10 ], A_Q12[ 9 ] ); + if( psDec->LPC_order == 16 ) { + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 11 ], A_Q12[ 10 ] ); + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 12 ], A_Q12[ 11 ] ); + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 13 ], A_Q12[ 12 ] ); + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 14 ], A_Q12[ 13 ] ); + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 15 ], A_Q12[ 14 ] ); + sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 16 ], A_Q12[ 15 ] ); + } + + /* Update states */ + CNG_sig_Q10[ MAX_LPC_ORDER + i ] = silk_ADD_LSHIFT( CNG_sig_Q10[ MAX_LPC_ORDER + i ], sum_Q6, 4 ); + + frame[ i ] = silk_ADD_SAT16( frame[ i ], silk_RSHIFT_ROUND( sum_Q6, 6 ) ); + } + silk_memcpy( psCNG->CNG_synth_state, &CNG_sig_Q10[ length ], MAX_LPC_ORDER * sizeof( opus_int32 ) ); + } else { + silk_memset( psCNG->CNG_synth_state, 0, psDec->LPC_order * sizeof( opus_int32 ) ); + } +} diff --git a/code/opus-1.0.2/silk/HP_variable_cutoff.c b/code/opus-1.0.2/silk/HP_variable_cutoff.c new file mode 100644 index 00000000..199dbb34 --- /dev/null +++ b/code/opus-1.0.2/silk/HP_variable_cutoff.c @@ -0,0 +1,77 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef FIXED_POINT +#include "main_FIX.h" +#else +#include "main_FLP.h" +#endif +#include "tuning_parameters.h" + +/* High-pass filter with cutoff frequency adaptation based on pitch lag statistics */ +void silk_HP_variable_cutoff( + silk_encoder_state_Fxx state_Fxx[] /* I/O Encoder states */ +) +{ + opus_int quality_Q15; + opus_int32 pitch_freq_Hz_Q16, pitch_freq_log_Q7, delta_freq_Q7; + silk_encoder_state *psEncC1 = &state_Fxx[ 0 ].sCmn; + + /* Adaptive cutoff frequency: estimate low end of pitch frequency range */ + if( psEncC1->prevSignalType == TYPE_VOICED ) { + /* difference, in log domain */ + pitch_freq_Hz_Q16 = silk_DIV32_16( silk_LSHIFT( silk_MUL( psEncC1->fs_kHz, 1000 ), 16 ), psEncC1->prevLag ); + pitch_freq_log_Q7 = silk_lin2log( pitch_freq_Hz_Q16 ) - ( 16 << 7 ); + + /* adjustment based on quality */ + quality_Q15 = psEncC1->input_quality_bands_Q15[ 0 ]; + pitch_freq_log_Q7 = silk_SMLAWB( pitch_freq_log_Q7, silk_SMULWB( silk_LSHIFT( -quality_Q15, 2 ), quality_Q15 ), + pitch_freq_log_Q7 - ( silk_lin2log( SILK_FIX_CONST( VARIABLE_HP_MIN_CUTOFF_HZ, 16 ) ) - ( 16 << 7 ) ) ); + + /* delta_freq = pitch_freq_log - psEnc->variable_HP_smth1; */ + delta_freq_Q7 = pitch_freq_log_Q7 - silk_RSHIFT( psEncC1->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 = silk_MUL( delta_freq_Q7, 3 ); + } + + /* limit delta, to reduce impact of outliers in pitch estimation */ + delta_freq_Q7 = silk_LIMIT_32( delta_freq_Q7, -SILK_FIX_CONST( VARIABLE_HP_MAX_DELTA_FREQ, 7 ), SILK_FIX_CONST( VARIABLE_HP_MAX_DELTA_FREQ, 7 ) ); + + /* update smoother */ + psEncC1->variable_HP_smth1_Q15 = silk_SMLAWB( psEncC1->variable_HP_smth1_Q15, + silk_SMULBB( psEncC1->speech_activity_Q8, delta_freq_Q7 ), SILK_FIX_CONST( VARIABLE_HP_SMTH_COEF1, 16 ) ); + + /* limit frequency range */ + psEncC1->variable_HP_smth1_Q15 = silk_LIMIT_32( psEncC1->variable_HP_smth1_Q15, + silk_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 ), + silk_LSHIFT( silk_lin2log( VARIABLE_HP_MAX_CUTOFF_HZ ), 8 ) ); + } +} diff --git a/code/opus-1.0.2/silk/Inlines.h b/code/opus-1.0.2/silk/Inlines.h new file mode 100644 index 00000000..87ac2e20 --- /dev/null +++ b/code/opus-1.0.2/silk/Inlines.h @@ -0,0 +1,188 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (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 silk_Inlines.h + * \brief silk_Inlines.h defines inline signal processing functions. + */ + +#ifndef SILK_FIX_INLINES_H +#define SILK_FIX_INLINES_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* count leading zeros of opus_int64 */ +static inline opus_int32 silk_CLZ64( opus_int64 in ) +{ + opus_int32 in_upper; + + in_upper = (opus_int32)silk_RSHIFT64(in, 32); + if (in_upper == 0) { + /* Search in the lower 32 bits */ + return 32 + silk_CLZ32( (opus_int32) in ); + } else { + /* Search in the upper 32 bits */ + return silk_CLZ32( in_upper ); + } +} + +/* get number of leading zeros and fractional part (the bits right after the leading one */ +static inline void silk_CLZ_FRAC( + opus_int32 in, /* I input */ + opus_int32 *lz, /* O number of leading zeros */ + opus_int32 *frac_Q7 /* O the 7 bits right after the leading one */ +) +{ + opus_int32 lzeros = silk_CLZ32(in); + + * lz = lzeros; + * frac_Q7 = silk_ROR32(in, 24 - lzeros) & 0x7f; +} + +/* Approximation of square root */ +/* Accuracy: < +/- 10% for output values > 15 */ +/* < +/- 2.5% for output values > 120 */ +static inline opus_int32 silk_SQRT_APPROX( opus_int32 x ) +{ + opus_int32 y, lz, frac_Q7; + + if( x <= 0 ) { + return 0; + } + + silk_CLZ_FRAC(x, &lz, &frac_Q7); + + if( lz & 1 ) { + y = 32768; + } else { + y = 46214; /* 46214 = sqrt(2) * 32768 */ + } + + /* get scaling right */ + y >>= silk_RSHIFT(lz, 1); + + /* increment using fractional part of input */ + y = silk_SMLAWB(y, y, silk_SMULBB(213, frac_Q7)); + + return y; +} + +/* Divide two int32 values and return result as int32 in a given Q-domain */ +static inline opus_int32 silk_DIV32_varQ( /* O returns a good approximation of "(a32 << Qres) / b32" */ + const opus_int32 a32, /* I numerator (Q0) */ + const opus_int32 b32, /* I denominator (Q0) */ + const opus_int Qres /* I Q-domain of result (>= 0) */ +) +{ + opus_int a_headrm, b_headrm, lshift; + opus_int32 b32_inv, a32_nrm, b32_nrm, result; + + silk_assert( b32 != 0 ); + silk_assert( Qres >= 0 ); + + /* Compute number of bits head room and normalize inputs */ + a_headrm = silk_CLZ32( silk_abs(a32) ) - 1; + a32_nrm = silk_LSHIFT(a32, a_headrm); /* Q: a_headrm */ + b_headrm = silk_CLZ32( silk_abs(b32) ) - 1; + b32_nrm = silk_LSHIFT(b32, b_headrm); /* Q: b_headrm */ + + /* Inverse of b32, with 14 bits of precision */ + b32_inv = silk_DIV32_16( silk_int32_MAX >> 2, silk_RSHIFT(b32_nrm, 16) ); /* Q: 29 + 16 - b_headrm */ + + /* First approximation */ + result = silk_SMULWB(a32_nrm, b32_inv); /* Q: 29 + a_headrm - b_headrm */ + + /* Compute residual by subtracting product of denominator and first approximation */ + /* It's OK to overflow because the final value of a32_nrm should always be small */ + a32_nrm = silk_SUB32_ovflw(a32_nrm, silk_LSHIFT_ovflw( silk_SMMUL(b32_nrm, result), 3 )); /* Q: a_headrm */ + + /* Refinement */ + result = silk_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 silk_LSHIFT_SAT32(result, -lshift); + } else { + if( lshift < 32){ + return silk_RSHIFT(result, lshift); + } else { + /* Avoid undefined result */ + return 0; + } + } +} + +/* Invert int32 value and return result as int32 in a given Q-domain */ +static inline opus_int32 silk_INVERSE32_varQ( /* O returns a good approximation of "(1 << Qres) / b32" */ + const opus_int32 b32, /* I denominator (Q0) */ + const opus_int Qres /* I Q-domain of result (> 0) */ +) +{ + opus_int b_headrm, lshift; + opus_int32 b32_inv, b32_nrm, err_Q32, result; + + silk_assert( b32 != 0 ); + silk_assert( Qres > 0 ); + + /* Compute number of bits head room and normalize input */ + b_headrm = silk_CLZ32( silk_abs(b32) ) - 1; + b32_nrm = silk_LSHIFT(b32, b_headrm); /* Q: b_headrm */ + + /* Inverse of b32, with 14 bits of precision */ + b32_inv = silk_DIV32_16( silk_int32_MAX >> 2, silk_RSHIFT(b32_nrm, 16) ); /* Q: 29 + 16 - b_headrm */ + + /* First approximation */ + result = silk_LSHIFT(b32_inv, 16); /* Q: 61 - b_headrm */ + + /* Compute residual by subtracting product of denominator and first approximation from one */ + err_Q32 = silk_LSHIFT( ((opus_int32)1<<29) - silk_SMULWB(b32_nrm, b32_inv), 3 ); /* Q32 */ + + /* Refinement */ + result = silk_SMLAWW(result, err_Q32, b32_inv); /* Q: 61 - b_headrm */ + + /* Convert to Qres domain */ + lshift = 61 - b_headrm - Qres; + if( lshift <= 0 ) { + return silk_LSHIFT_SAT32(result, -lshift); + } else { + if( lshift < 32){ + return silk_RSHIFT(result, lshift); + }else{ + /* Avoid undefined result */ + return 0; + } + } +} + +#ifdef __cplusplus +} +#endif + +#endif /* SILK_FIX_INLINES_H */ diff --git a/code/opus-1.0.2/silk/LPC_analysis_filter.c b/code/opus-1.0.2/silk/LPC_analysis_filter.c new file mode 100644 index 00000000..421dba0b --- /dev/null +++ b/code/opus-1.0.2/silk/LPC_analysis_filter.c @@ -0,0 +1,85 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/*******************************************/ +/* LPC analysis filter */ +/* NB! State is kept internally and the */ +/* filter always starts with zero state */ +/* first d output samples are set to zero */ +/*******************************************/ + +void silk_LPC_analysis_filter( + opus_int16 *out, /* O Output signal */ + const opus_int16 *in, /* I Input signal */ + const opus_int16 *B, /* I MA prediction coefficients, Q12 [order] */ + const opus_int32 len, /* I Signal length */ + const opus_int32 d /* I Filter order */ +) +{ + opus_int ix, j; + opus_int32 out32_Q12, out32; + const opus_int16 *in_ptr; + + silk_assert( d >= 6 ); + silk_assert( (d & 1) == 0 ); + silk_assert( d <= len ); + + for( ix = d; ix < len; ix++ ) { + in_ptr = &in[ ix - 1 ]; + + out32_Q12 = silk_SMULBB( in_ptr[ 0 ], B[ 0 ] ); + /* Allowing wrap around so that two wraps can cancel each other. The rare + cases where the result wraps around can only be triggered by invalid streams*/ + out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -1 ], B[ 1 ] ); + out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -2 ], B[ 2 ] ); + out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -3 ], B[ 3 ] ); + out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -4 ], B[ 4 ] ); + out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -5 ], B[ 5 ] ); + for( j = 6; j < d; j += 2 ) { + out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -j ], B[ j ] ); + out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -j - 1 ], B[ j + 1 ] ); + } + + /* Subtract prediction */ + out32_Q12 = silk_SUB32_ovflw( silk_LSHIFT( (opus_int32)in_ptr[ 1 ], 12 ), out32_Q12 ); + + /* Scale to Q0 */ + out32 = silk_RSHIFT_ROUND( out32_Q12, 12 ); + + /* Saturate output */ + out[ ix ] = (opus_int16)silk_SAT16( out32 ); + } + + /* Set first d output samples to zero */ + silk_memset( out, 0, d * sizeof( opus_int16 ) ); +} diff --git a/code/opus-1.0.2/silk/LPC_inv_pred_gain.c b/code/opus-1.0.2/silk/LPC_inv_pred_gain.c new file mode 100644 index 00000000..c36f3422 --- /dev/null +++ b/code/opus-1.0.2/silk/LPC_inv_pred_gain.c @@ -0,0 +1,154 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +#define QA 24 +#define A_LIMIT SILK_FIX_CONST( 0.99975, QA ) + +#define MUL32_FRAC_Q(a32, b32, Q) ((opus_int32)(silk_RSHIFT_ROUND64(silk_SMULL(a32, b32), Q))) + +/* Compute inverse of LPC prediction gain, and */ +/* test if LPC coefficients are stable (all poles within unit circle) */ +static opus_int32 LPC_inverse_pred_gain_QA( /* O Returns inverse prediction gain in energy domain, Q30 */ + opus_int32 A_QA[ 2 ][ SILK_MAX_ORDER_LPC ], /* I Prediction coefficients */ + const opus_int order /* I Prediction order */ +) +{ + opus_int k, n, mult2Q; + opus_int32 invGain_Q30, rc_Q31, rc_mult1_Q30, rc_mult2, tmp_QA; + opus_int32 *Aold_QA, *Anew_QA; + + Anew_QA = A_QA[ order & 1 ]; + + invGain_Q30 = (opus_int32)1 << 30; + for( k = order - 1; k > 0; k-- ) { + /* Check for stability */ + if( ( Anew_QA[ k ] > A_LIMIT ) || ( Anew_QA[ k ] < -A_LIMIT ) ) { + return 0; + } + + /* Set RC equal to negated AR coef */ + rc_Q31 = -silk_LSHIFT( Anew_QA[ k ], 31 - QA ); + + /* rc_mult1_Q30 range: [ 1 : 2^30 ] */ + rc_mult1_Q30 = ( (opus_int32)1 << 30 ) - silk_SMMUL( rc_Q31, rc_Q31 ); + silk_assert( rc_mult1_Q30 > ( 1 << 15 ) ); /* reduce A_LIMIT if fails */ + silk_assert( rc_mult1_Q30 <= ( 1 << 30 ) ); + + /* rc_mult2 range: [ 2^30 : silk_int32_MAX ] */ + mult2Q = 32 - silk_CLZ32( silk_abs( rc_mult1_Q30 ) ); + rc_mult2 = silk_INVERSE32_varQ( rc_mult1_Q30, mult2Q + 30 ); + + /* Update inverse gain */ + /* invGain_Q30 range: [ 0 : 2^30 ] */ + invGain_Q30 = silk_LSHIFT( silk_SMMUL( invGain_Q30, rc_mult1_Q30 ), 2 ); + silk_assert( invGain_Q30 >= 0 ); + silk_assert( invGain_Q30 <= ( 1 << 30 ) ); + + /* Swap pointers */ + Aold_QA = Anew_QA; + Anew_QA = A_QA[ k & 1 ]; + + /* Update AR coefficient */ + for( n = 0; n < k; n++ ) { + tmp_QA = Aold_QA[ n ] - MUL32_FRAC_Q( Aold_QA[ k - n - 1 ], rc_Q31, 31 ); + Anew_QA[ n ] = MUL32_FRAC_Q( tmp_QA, rc_mult2 , mult2Q ); + } + } + + /* Check for stability */ + if( ( Anew_QA[ 0 ] > A_LIMIT ) || ( Anew_QA[ 0 ] < -A_LIMIT ) ) { + return 0; + } + + /* Set RC equal to negated AR coef */ + rc_Q31 = -silk_LSHIFT( Anew_QA[ 0 ], 31 - QA ); + + /* Range: [ 1 : 2^30 ] */ + rc_mult1_Q30 = ( (opus_int32)1 << 30 ) - silk_SMMUL( rc_Q31, rc_Q31 ); + + /* Update inverse gain */ + /* Range: [ 0 : 2^30 ] */ + invGain_Q30 = silk_LSHIFT( silk_SMMUL( invGain_Q30, rc_mult1_Q30 ), 2 ); + silk_assert( invGain_Q30 >= 0 ); + silk_assert( invGain_Q30 <= 1<<30 ); + + return invGain_Q30; +} + +/* For input in Q12 domain */ +opus_int32 silk_LPC_inverse_pred_gain( /* O Returns inverse prediction gain in energy domain, Q30 */ + const opus_int16 *A_Q12, /* I Prediction coefficients, Q12 [order] */ + const opus_int order /* I Prediction order */ +) +{ + opus_int k; + opus_int32 Atmp_QA[ 2 ][ SILK_MAX_ORDER_LPC ]; + opus_int32 *Anew_QA; + opus_int32 DC_resp = 0; + + Anew_QA = Atmp_QA[ order & 1 ]; + + /* Increase Q domain of the AR coefficients */ + for( k = 0; k < order; k++ ) { + DC_resp += (opus_int32)A_Q12[ k ]; + Anew_QA[ k ] = silk_LSHIFT32( (opus_int32)A_Q12[ k ], QA - 12 ); + } + /* If the DC is unstable, we don't even need to do the full calculations */ + if( DC_resp >= 4096 ) { + return 0; + } + return LPC_inverse_pred_gain_QA( Atmp_QA, order ); +} + +#ifdef FIXED_POINT + +/* For input in Q24 domain */ +opus_int32 silk_LPC_inverse_pred_gain_Q24( /* O Returns inverse prediction gain in energy domain, Q30 */ + const opus_int32 *A_Q24, /* I Prediction coefficients [order] */ + const opus_int order /* I Prediction order */ +) +{ + opus_int k; + opus_int32 Atmp_QA[ 2 ][ SILK_MAX_ORDER_LPC ]; + opus_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 ] = silk_RSHIFT32( A_Q24[ k ], 24 - QA ); + } + + return LPC_inverse_pred_gain_QA( Atmp_QA, order ); +} +#endif diff --git a/code/opus-1.0.2/silk/LP_variable_cutoff.c b/code/opus-1.0.2/silk/LP_variable_cutoff.c new file mode 100644 index 00000000..d0912a64 --- /dev/null +++ b/code/opus-1.0.2/silk/LP_variable_cutoff.c @@ -0,0 +1,135 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* + 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 "main.h" + +/* Helper function, interpolates the filter taps */ +static inline void silk_LP_interpolate_filter_taps( + opus_int32 B_Q28[ TRANSITION_NB ], + opus_int32 A_Q28[ TRANSITION_NA ], + const opus_int ind, + const opus_int32 fac_Q16 +) +{ + opus_int nb, na; + + if( ind < TRANSITION_INT_NUM - 1 ) { + if( fac_Q16 > 0 ) { + if( fac_Q16 < 32768 ) { /* 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 ] = silk_SMLAWB( + silk_Transition_LP_B_Q28[ ind ][ nb ], + silk_Transition_LP_B_Q28[ ind + 1 ][ nb ] - + silk_Transition_LP_B_Q28[ ind ][ nb ], + fac_Q16 ); + } + for( na = 0; na < TRANSITION_NA; na++ ) { + A_Q28[ na ] = silk_SMLAWB( + silk_Transition_LP_A_Q28[ ind ][ na ], + silk_Transition_LP_A_Q28[ ind + 1 ][ na ] - + silk_Transition_LP_A_Q28[ ind ][ na ], + fac_Q16 ); + } + } else { /* ( fac_Q16 - ( 1 << 16 ) ) is in range of a 16-bit int */ + silk_assert( fac_Q16 - ( 1 << 16 ) == silk_SAT16( fac_Q16 - ( 1 << 16 ) ) ); + /* Piece-wise linear interpolation of B and A */ + for( nb = 0; nb < TRANSITION_NB; nb++ ) { + B_Q28[ nb ] = silk_SMLAWB( + silk_Transition_LP_B_Q28[ ind + 1 ][ nb ], + silk_Transition_LP_B_Q28[ ind + 1 ][ nb ] - + silk_Transition_LP_B_Q28[ ind ][ nb ], + fac_Q16 - ( (opus_int32)1 << 16 ) ); + } + for( na = 0; na < TRANSITION_NA; na++ ) { + A_Q28[ na ] = silk_SMLAWB( + silk_Transition_LP_A_Q28[ ind + 1 ][ na ], + silk_Transition_LP_A_Q28[ ind + 1 ][ na ] - + silk_Transition_LP_A_Q28[ ind ][ na ], + fac_Q16 - ( (opus_int32)1 << 16 ) ); + } + } + } else { + silk_memcpy( B_Q28, silk_Transition_LP_B_Q28[ ind ], TRANSITION_NB * sizeof( opus_int32 ) ); + silk_memcpy( A_Q28, silk_Transition_LP_A_Q28[ ind ], TRANSITION_NA * sizeof( opus_int32 ) ); + } + } else { + silk_memcpy( B_Q28, silk_Transition_LP_B_Q28[ TRANSITION_INT_NUM - 1 ], TRANSITION_NB * sizeof( opus_int32 ) ); + silk_memcpy( A_Q28, silk_Transition_LP_A_Q28[ TRANSITION_INT_NUM - 1 ], TRANSITION_NA * sizeof( opus_int32 ) ); + } +} + +/* Low-pass filter with variable cutoff frequency based on */ +/* piece-wise linear interpolation between elliptic filters */ +/* Start by setting psEncC->mode <> 0; */ +/* Deactivate by setting psEncC->mode = 0; */ +void silk_LP_variable_cutoff( + silk_LP_state *psLP, /* I/O LP filter state */ + opus_int16 *frame, /* I/O Low-pass filtered output signal */ + const opus_int frame_length /* I Frame length */ +) +{ + opus_int32 B_Q28[ TRANSITION_NB ], A_Q28[ TRANSITION_NA ], fac_Q16 = 0; + opus_int ind = 0; + + silk_assert( psLP->transition_frame_no >= 0 && psLP->transition_frame_no <= TRANSITION_FRAMES ); + + /* Run filter if needed */ + if( psLP->mode != 0 ) { + /* Calculate index and interpolation factor for interpolation */ +#if( TRANSITION_INT_STEPS == 64 ) + fac_Q16 = silk_LSHIFT( TRANSITION_FRAMES - psLP->transition_frame_no, 16 - 6 ); +#else + fac_Q16 = silk_DIV32_16( silk_LSHIFT( TRANSITION_FRAMES - psLP->transition_frame_no, 16 ), TRANSITION_FRAMES ); +#endif + ind = silk_RSHIFT( fac_Q16, 16 ); + fac_Q16 -= silk_LSHIFT( ind, 16 ); + + silk_assert( ind >= 0 ); + silk_assert( ind < TRANSITION_INT_NUM ); + + /* Interpolate filter coefficients */ + silk_LP_interpolate_filter_taps( B_Q28, A_Q28, ind, fac_Q16 ); + + /* Update transition frame number for next frame */ + psLP->transition_frame_no = silk_LIMIT( psLP->transition_frame_no + psLP->mode, 0, TRANSITION_FRAMES ); + + /* ARMA low-pass filtering */ + silk_assert( TRANSITION_NB == 3 && TRANSITION_NA == 2 ); + silk_biquad_alt( frame, B_Q28, A_Q28, psLP->In_LP_State, frame, frame_length, 1); + } +} diff --git a/code/opus-1.0.2/silk/MacroCount.h b/code/opus-1.0.2/silk/MacroCount.h new file mode 100644 index 00000000..2829e8cc --- /dev/null +++ b/code/opus-1.0.2/silk/MacroCount.h @@ -0,0 +1,718 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (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_API_MACROCOUNT_H +#define SIGPROCFIX_API_MACROCOUNT_H +#include + +#ifdef silk_MACRO_COUNT +#define varDefine opus_int64 ops_count = 0; + +extern opus_int64 ops_count; + +static inline opus_int64 silk_SaveCount(){ + return(ops_count); +} + +static inline opus_int64 silk_SaveResetCount(){ + opus_int64 ret; + + ret = ops_count; + ops_count = 0; + return(ret); +} + +static inline silk_PrintCount(){ + printf("ops_count = %d \n ", (opus_int32)ops_count); +} + +#undef silk_MUL +static inline opus_int32 silk_MUL(opus_int32 a32, opus_int32 b32){ + opus_int32 ret; + ops_count += 4; + ret = a32 * b32; + return ret; +} + +#undef silk_MUL_uint +static inline opus_uint32 silk_MUL_uint(opus_uint32 a32, opus_uint32 b32){ + opus_uint32 ret; + ops_count += 4; + ret = a32 * b32; + return ret; +} +#undef silk_MLA +static inline opus_int32 silk_MLA(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + ops_count += 4; + ret = a32 + b32 * c32; + return ret; +} + +#undef silk_MLA_uint +static inline opus_int32 silk_MLA_uint(opus_uint32 a32, opus_uint32 b32, opus_uint32 c32){ + opus_uint32 ret; + ops_count += 4; + ret = a32 + b32 * c32; + return ret; +} + +#undef silk_SMULWB +static inline opus_int32 silk_SMULWB(opus_int32 a32, opus_int32 b32){ + opus_int32 ret; + ops_count += 5; + ret = (a32 >> 16) * (opus_int32)((opus_int16)b32) + (((a32 & 0x0000FFFF) * (opus_int32)((opus_int16)b32)) >> 16); + return ret; +} +#undef silk_SMLAWB +static inline opus_int32 silk_SMLAWB(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + ops_count += 5; + ret = ((a32) + ((((b32) >> 16) * (opus_int32)((opus_int16)(c32))) + ((((b32) & 0x0000FFFF) * (opus_int32)((opus_int16)(c32))) >> 16))); + return ret; +} + +#undef silk_SMULWT +static inline opus_int32 silk_SMULWT(opus_int32 a32, opus_int32 b32){ + opus_int32 ret; + ops_count += 4; + ret = (a32 >> 16) * (b32 >> 16) + (((a32 & 0x0000FFFF) * (b32 >> 16)) >> 16); + return ret; +} +#undef silk_SMLAWT +static inline opus_int32 silk_SMLAWT(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + ops_count += 4; + ret = a32 + ((b32 >> 16) * (c32 >> 16)) + (((b32 & 0x0000FFFF) * ((c32 >> 16)) >> 16)); + return ret; +} + +#undef silk_SMULBB +static inline opus_int32 silk_SMULBB(opus_int32 a32, opus_int32 b32){ + opus_int32 ret; + ops_count += 1; + ret = (opus_int32)((opus_int16)a32) * (opus_int32)((opus_int16)b32); + return ret; +} +#undef silk_SMLABB +static inline opus_int32 silk_SMLABB(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + ops_count += 1; + ret = a32 + (opus_int32)((opus_int16)b32) * (opus_int32)((opus_int16)c32); + return ret; +} + +#undef silk_SMULBT +static inline opus_int32 silk_SMULBT(opus_int32 a32, opus_int32 b32 ){ + opus_int32 ret; + ops_count += 4; + ret = ((opus_int32)((opus_int16)a32)) * (b32 >> 16); + return ret; +} + +#undef silk_SMLABT +static inline opus_int32 silk_SMLABT(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + ops_count += 1; + ret = a32 + ((opus_int32)((opus_int16)b32)) * (c32 >> 16); + return ret; +} + +#undef silk_SMULTT +static inline opus_int32 silk_SMULTT(opus_int32 a32, opus_int32 b32){ + opus_int32 ret; + ops_count += 1; + ret = (a32 >> 16) * (b32 >> 16); + return ret; +} + +#undef silk_SMLATT +static inline opus_int32 silk_SMLATT(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + ops_count += 1; + ret = a32 + (b32 >> 16) * (c32 >> 16); + return ret; +} + + +/* multiply-accumulate macros that allow overflow in the addition (ie, no asserts in debug mode)*/ +#undef silk_MLA_ovflw +#define silk_MLA_ovflw silk_MLA + +#undef silk_SMLABB_ovflw +#define silk_SMLABB_ovflw silk_SMLABB + +#undef silk_SMLABT_ovflw +#define silk_SMLABT_ovflw silk_SMLABT + +#undef silk_SMLATT_ovflw +#define silk_SMLATT_ovflw silk_SMLATT + +#undef silk_SMLAWB_ovflw +#define silk_SMLAWB_ovflw silk_SMLAWB + +#undef silk_SMLAWT_ovflw +#define silk_SMLAWT_ovflw silk_SMLAWT + +#undef silk_SMULL +static inline opus_int64 silk_SMULL(opus_int32 a32, opus_int32 b32){ + opus_int64 ret; + ops_count += 8; + ret = ((opus_int64)(a32) * /*(opus_int64)*/(b32)); + return ret; +} + +#undef silk_SMLAL +static inline opus_int64 silk_SMLAL(opus_int64 a64, opus_int32 b32, opus_int32 c32){ + opus_int64 ret; + ops_count += 8; + ret = a64 + ((opus_int64)(b32) * /*(opus_int64)*/(c32)); + return ret; +} +#undef silk_SMLALBB +static inline opus_int64 silk_SMLALBB(opus_int64 a64, opus_int16 b16, opus_int16 c16){ + opus_int64 ret; + ops_count += 4; + ret = a64 + ((opus_int64)(b16) * /*(opus_int64)*/(c16)); + return ret; +} + +#undef SigProcFIX_CLZ16 +static inline opus_int32 SigProcFIX_CLZ16(opus_int16 in16) +{ + opus_int32 out32 = 0; + ops_count += 10; + 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; + } +} + +#undef SigProcFIX_CLZ32 +static inline opus_int32 SigProcFIX_CLZ32(opus_int32 in32) +{ + /* test highest 16 bits and convert to opus_int16 */ + ops_count += 2; + if( in32 & 0xFFFF0000 ) { + return SigProcFIX_CLZ16((opus_int16)(in32 >> 16)); + } else { + return SigProcFIX_CLZ16((opus_int16)in32) + 16; + } +} + +#undef silk_DIV32 +static inline opus_int32 silk_DIV32(opus_int32 a32, opus_int32 b32){ + ops_count += 64; + return a32 / b32; +} + +#undef silk_DIV32_16 +static inline opus_int32 silk_DIV32_16(opus_int32 a32, opus_int32 b32){ + ops_count += 32; + return a32 / b32; +} + +#undef silk_SAT8 +static inline opus_int8 silk_SAT8(opus_int64 a){ + opus_int8 tmp; + ops_count += 1; + tmp = (opus_int8)((a) > silk_int8_MAX ? silk_int8_MAX : \ + ((a) < silk_int8_MIN ? silk_int8_MIN : (a))); + return(tmp); +} + +#undef silk_SAT16 +static inline opus_int16 silk_SAT16(opus_int64 a){ + opus_int16 tmp; + ops_count += 1; + tmp = (opus_int16)((a) > silk_int16_MAX ? silk_int16_MAX : \ + ((a) < silk_int16_MIN ? silk_int16_MIN : (a))); + return(tmp); +} +#undef silk_SAT32 +static inline opus_int32 silk_SAT32(opus_int64 a){ + opus_int32 tmp; + ops_count += 1; + tmp = (opus_int32)((a) > silk_int32_MAX ? silk_int32_MAX : \ + ((a) < silk_int32_MIN ? silk_int32_MIN : (a))); + return(tmp); +} +#undef silk_POS_SAT32 +static inline opus_int32 silk_POS_SAT32(opus_int64 a){ + opus_int32 tmp; + ops_count += 1; + tmp = (opus_int32)((a) > silk_int32_MAX ? silk_int32_MAX : (a)); + return(tmp); +} + +#undef silk_ADD_POS_SAT8 +static inline opus_int8 silk_ADD_POS_SAT8(opus_int64 a, opus_int64 b){ + opus_int8 tmp; + ops_count += 1; + tmp = (opus_int8)((((a)+(b)) & 0x80) ? silk_int8_MAX : ((a)+(b))); + return(tmp); +} +#undef silk_ADD_POS_SAT16 +static inline opus_int16 silk_ADD_POS_SAT16(opus_int64 a, opus_int64 b){ + opus_int16 tmp; + ops_count += 1; + tmp = (opus_int16)((((a)+(b)) & 0x8000) ? silk_int16_MAX : ((a)+(b))); + return(tmp); +} + +#undef silk_ADD_POS_SAT32 +static inline opus_int32 silk_ADD_POS_SAT32(opus_int64 a, opus_int64 b){ + opus_int32 tmp; + ops_count += 1; + tmp = (opus_int32)((((a)+(b)) & 0x80000000) ? silk_int32_MAX : ((a)+(b))); + return(tmp); +} + +#undef silk_ADD_POS_SAT64 +static inline opus_int64 silk_ADD_POS_SAT64(opus_int64 a, opus_int64 b){ + opus_int64 tmp; + ops_count += 1; + tmp = ((((a)+(b)) & 0x8000000000000000LL) ? silk_int64_MAX : ((a)+(b))); + return(tmp); +} + +#undef silk_LSHIFT8 +static inline opus_int8 silk_LSHIFT8(opus_int8 a, opus_int32 shift){ + opus_int8 ret; + ops_count += 1; + ret = a << shift; + return ret; +} +#undef silk_LSHIFT16 +static inline opus_int16 silk_LSHIFT16(opus_int16 a, opus_int32 shift){ + opus_int16 ret; + ops_count += 1; + ret = a << shift; + return ret; +} +#undef silk_LSHIFT32 +static inline opus_int32 silk_LSHIFT32(opus_int32 a, opus_int32 shift){ + opus_int32 ret; + ops_count += 1; + ret = a << shift; + return ret; +} +#undef silk_LSHIFT64 +static inline opus_int64 silk_LSHIFT64(opus_int64 a, opus_int shift){ + ops_count += 1; + return a << shift; +} + +#undef silk_LSHIFT_ovflw +static inline opus_int32 silk_LSHIFT_ovflw(opus_int32 a, opus_int32 shift){ + ops_count += 1; + return a << shift; +} + +#undef silk_LSHIFT_uint +static inline opus_uint32 silk_LSHIFT_uint(opus_uint32 a, opus_int32 shift){ + opus_uint32 ret; + ops_count += 1; + ret = a << shift; + return ret; +} + +#undef silk_RSHIFT8 +static inline opus_int8 silk_RSHIFT8(opus_int8 a, opus_int32 shift){ + ops_count += 1; + return a >> shift; +} +#undef silk_RSHIFT16 +static inline opus_int16 silk_RSHIFT16(opus_int16 a, opus_int32 shift){ + ops_count += 1; + return a >> shift; +} +#undef silk_RSHIFT32 +static inline opus_int32 silk_RSHIFT32(opus_int32 a, opus_int32 shift){ + ops_count += 1; + return a >> shift; +} +#undef silk_RSHIFT64 +static inline opus_int64 silk_RSHIFT64(opus_int64 a, opus_int64 shift){ + ops_count += 1; + return a >> shift; +} + +#undef silk_RSHIFT_uint +static inline opus_uint32 silk_RSHIFT_uint(opus_uint32 a, opus_int32 shift){ + ops_count += 1; + return a >> shift; +} + +#undef silk_ADD_LSHIFT +static inline opus_int32 silk_ADD_LSHIFT(opus_int32 a, opus_int32 b, opus_int32 shift){ + opus_int32 ret; + ops_count += 1; + ret = a + (b << shift); + return ret; /* shift >= 0*/ +} +#undef silk_ADD_LSHIFT32 +static inline opus_int32 silk_ADD_LSHIFT32(opus_int32 a, opus_int32 b, opus_int32 shift){ + opus_int32 ret; + ops_count += 1; + ret = a + (b << shift); + return ret; /* shift >= 0*/ +} +#undef silk_ADD_LSHIFT_uint +static inline opus_uint32 silk_ADD_LSHIFT_uint(opus_uint32 a, opus_uint32 b, opus_int32 shift){ + opus_uint32 ret; + ops_count += 1; + ret = a + (b << shift); + return ret; /* shift >= 0*/ +} +#undef silk_ADD_RSHIFT +static inline opus_int32 silk_ADD_RSHIFT(opus_int32 a, opus_int32 b, opus_int32 shift){ + opus_int32 ret; + ops_count += 1; + ret = a + (b >> shift); + return ret; /* shift > 0*/ +} +#undef silk_ADD_RSHIFT32 +static inline opus_int32 silk_ADD_RSHIFT32(opus_int32 a, opus_int32 b, opus_int32 shift){ + opus_int32 ret; + ops_count += 1; + ret = a + (b >> shift); + return ret; /* shift > 0*/ +} +#undef silk_ADD_RSHIFT_uint +static inline opus_uint32 silk_ADD_RSHIFT_uint(opus_uint32 a, opus_uint32 b, opus_int32 shift){ + opus_uint32 ret; + ops_count += 1; + ret = a + (b >> shift); + return ret; /* shift > 0*/ +} +#undef silk_SUB_LSHIFT32 +static inline opus_int32 silk_SUB_LSHIFT32(opus_int32 a, opus_int32 b, opus_int32 shift){ + opus_int32 ret; + ops_count += 1; + ret = a - (b << shift); + return ret; /* shift >= 0*/ +} +#undef silk_SUB_RSHIFT32 +static inline opus_int32 silk_SUB_RSHIFT32(opus_int32 a, opus_int32 b, opus_int32 shift){ + opus_int32 ret; + ops_count += 1; + ret = a - (b >> shift); + return ret; /* shift > 0*/ +} + +#undef silk_RSHIFT_ROUND +static inline opus_int32 silk_RSHIFT_ROUND(opus_int32 a, opus_int32 shift){ + opus_int32 ret; + ops_count += 3; + ret = shift == 1 ? (a >> 1) + (a & 1) : ((a >> (shift - 1)) + 1) >> 1; + return ret; +} + +#undef silk_RSHIFT_ROUND64 +static inline opus_int64 silk_RSHIFT_ROUND64(opus_int64 a, opus_int32 shift){ + opus_int64 ret; + ops_count += 6; + ret = shift == 1 ? (a >> 1) + (a & 1) : ((a >> (shift - 1)) + 1) >> 1; + return ret; +} + +#undef silk_abs_int64 +static inline opus_int64 silk_abs_int64(opus_int64 a){ + ops_count += 1; + return (((a) > 0) ? (a) : -(a)); /* Be careful, silk_abs returns wrong when input equals to silk_intXX_MIN*/ +} + +#undef silk_abs_int32 +static inline opus_int32 silk_abs_int32(opus_int32 a){ + ops_count += 1; + return silk_abs(a); +} + + +#undef silk_min +static silk_min(a, b){ + ops_count += 1; + return (((a) < (b)) ? (a) : (b)); +} +#undef silk_max +static silk_max(a, b){ + ops_count += 1; + return (((a) > (b)) ? (a) : (b)); +} +#undef silk_sign +static silk_sign(a){ + ops_count += 1; + return ((a) > 0 ? 1 : ( (a) < 0 ? -1 : 0 )); +} + +#undef silk_ADD16 +static inline opus_int16 silk_ADD16(opus_int16 a, opus_int16 b){ + opus_int16 ret; + ops_count += 1; + ret = a + b; + return ret; +} + +#undef silk_ADD32 +static inline opus_int32 silk_ADD32(opus_int32 a, opus_int32 b){ + opus_int32 ret; + ops_count += 1; + ret = a + b; + return ret; +} + +#undef silk_ADD64 +static inline opus_int64 silk_ADD64(opus_int64 a, opus_int64 b){ + opus_int64 ret; + ops_count += 2; + ret = a + b; + return ret; +} + +#undef silk_SUB16 +static inline opus_int16 silk_SUB16(opus_int16 a, opus_int16 b){ + opus_int16 ret; + ops_count += 1; + ret = a - b; + return ret; +} + +#undef silk_SUB32 +static inline opus_int32 silk_SUB32(opus_int32 a, opus_int32 b){ + opus_int32 ret; + ops_count += 1; + ret = a - b; + return ret; +} + +#undef silk_SUB64 +static inline opus_int64 silk_SUB64(opus_int64 a, opus_int64 b){ + opus_int64 ret; + ops_count += 2; + ret = a - b; + return ret; +} + +#undef silk_ADD_SAT16 +static inline opus_int16 silk_ADD_SAT16( opus_int16 a16, opus_int16 b16 ) { + opus_int16 res; + /* Nb will be counted in AKP_add32 and silk_SAT16*/ + res = (opus_int16)silk_SAT16( silk_ADD32( (opus_int32)(a16), (b16) ) ); + return res; +} + +#undef silk_ADD_SAT32 +static inline opus_int32 silk_ADD_SAT32(opus_int32 a32, opus_int32 b32){ + opus_int32 res; + ops_count += 1; + res = ((((a32) + (b32)) & 0x80000000) == 0 ? \ + ((((a32) & (b32)) & 0x80000000) != 0 ? silk_int32_MIN : (a32)+(b32)) : \ + ((((a32) | (b32)) & 0x80000000) == 0 ? silk_int32_MAX : (a32)+(b32)) ); + return res; +} + +#undef silk_ADD_SAT64 +static inline opus_int64 silk_ADD_SAT64( opus_int64 a64, opus_int64 b64 ) { + opus_int64 res; + ops_count += 1; + res = ((((a64) + (b64)) & 0x8000000000000000LL) == 0 ? \ + ((((a64) & (b64)) & 0x8000000000000000LL) != 0 ? silk_int64_MIN : (a64)+(b64)) : \ + ((((a64) | (b64)) & 0x8000000000000000LL) == 0 ? silk_int64_MAX : (a64)+(b64)) ); + return res; +} + +#undef silk_SUB_SAT16 +static inline opus_int16 silk_SUB_SAT16( opus_int16 a16, opus_int16 b16 ) { + opus_int16 res; + silk_assert(0); + /* Nb will be counted in sub-macros*/ + res = (opus_int16)silk_SAT16( silk_SUB32( (opus_int32)(a16), (b16) ) ); + return res; +} + +#undef silk_SUB_SAT32 +static inline opus_int32 silk_SUB_SAT32( opus_int32 a32, opus_int32 b32 ) { + opus_int32 res; + ops_count += 1; + res = ((((a32)-(b32)) & 0x80000000) == 0 ? \ + (( (a32) & ((b32)^0x80000000) & 0x80000000) ? silk_int32_MIN : (a32)-(b32)) : \ + ((((a32)^0x80000000) & (b32) & 0x80000000) ? silk_int32_MAX : (a32)-(b32)) ); + return res; +} + +#undef silk_SUB_SAT64 +static inline opus_int64 silk_SUB_SAT64( opus_int64 a64, opus_int64 b64 ) { + opus_int64 res; + ops_count += 1; + res = ((((a64)-(b64)) & 0x8000000000000000LL) == 0 ? \ + (( (a64) & ((b64)^0x8000000000000000LL) & 0x8000000000000000LL) ? silk_int64_MIN : (a64)-(b64)) : \ + ((((a64)^0x8000000000000000LL) & (b64) & 0x8000000000000000LL) ? silk_int64_MAX : (a64)-(b64)) ); + + return res; +} + +#undef silk_SMULWW +static inline opus_int32 silk_SMULWW(opus_int32 a32, opus_int32 b32){ + opus_int32 ret; + /* Nb will be counted in sub-macros*/ + ret = silk_MLA(silk_SMULWB((a32), (b32)), (a32), silk_RSHIFT_ROUND((b32), 16)); + return ret; +} + +#undef silk_SMLAWW +static inline opus_int32 silk_SMLAWW(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + /* Nb will be counted in sub-macros*/ + ret = silk_MLA(silk_SMLAWB((a32), (b32), (c32)), (b32), silk_RSHIFT_ROUND((c32), 16)); + return ret; +} + +#undef silk_min_int +static inline opus_int silk_min_int(opus_int a, opus_int b) +{ + ops_count += 1; + return (((a) < (b)) ? (a) : (b)); +} + +#undef silk_min_16 +static inline opus_int16 silk_min_16(opus_int16 a, opus_int16 b) +{ + ops_count += 1; + return (((a) < (b)) ? (a) : (b)); +} +#undef silk_min_32 +static inline opus_int32 silk_min_32(opus_int32 a, opus_int32 b) +{ + ops_count += 1; + return (((a) < (b)) ? (a) : (b)); +} +#undef silk_min_64 +static inline opus_int64 silk_min_64(opus_int64 a, opus_int64 b) +{ + ops_count += 1; + return (((a) < (b)) ? (a) : (b)); +} + +/* silk_min() versions with typecast in the function call */ +#undef silk_max_int +static inline opus_int silk_max_int(opus_int a, opus_int b) +{ + ops_count += 1; + return (((a) > (b)) ? (a) : (b)); +} +#undef silk_max_16 +static inline opus_int16 silk_max_16(opus_int16 a, opus_int16 b) +{ + ops_count += 1; + return (((a) > (b)) ? (a) : (b)); +} +#undef silk_max_32 +static inline opus_int32 silk_max_32(opus_int32 a, opus_int32 b) +{ + ops_count += 1; + return (((a) > (b)) ? (a) : (b)); +} + +#undef silk_max_64 +static inline opus_int64 silk_max_64(opus_int64 a, opus_int64 b) +{ + ops_count += 1; + return (((a) > (b)) ? (a) : (b)); +} + + +#undef silk_LIMIT_int +static inline opus_int silk_LIMIT_int(opus_int a, opus_int limit1, opus_int limit2) +{ + opus_int ret; + ops_count += 6; + + ret = ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) \ + : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a)))); + + return(ret); +} + +#undef silk_LIMIT_16 +static inline opus_int16 silk_LIMIT_16(opus_int16 a, opus_int16 limit1, opus_int16 limit2) +{ + opus_int16 ret; + ops_count += 6; + + ret = ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) \ + : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a)))); + +return(ret); +} + + +#undef silk_LIMIT_32 +static inline opus_int silk_LIMIT_32(opus_int32 a, opus_int32 limit1, opus_int32 limit2) +{ + opus_int32 ret; + ops_count += 6; + + ret = ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) \ + : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a)))); + return(ret); +} + +#else +#define varDefine +#define silk_SaveCount() + +#endif +#endif + diff --git a/code/opus-1.0.2/silk/MacroDebug.h b/code/opus-1.0.2/silk/MacroDebug.h new file mode 100644 index 00000000..ecd90bc4 --- /dev/null +++ b/code/opus-1.0.2/silk/MacroDebug.h @@ -0,0 +1,952 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Copyright (C) 2012 Xiph.Org Foundation +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (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 MACRO_DEBUG_H +#define MACRO_DEBUG_H + +/* Redefine macro functions with extensive assertion in DEBUG mode. + As functions can't be undefined, this file can't work with SigProcFIX_MacroCount.h */ + +#if ( defined (FIXED_DEBUG) || ( 0 && defined (_DEBUG) ) ) && !defined (silk_MACRO_COUNT) + +#undef silk_ADD16 +#define silk_ADD16(a,b) silk_ADD16_((a), (b), __FILE__, __LINE__) +static inline opus_int16 silk_ADD16_(opus_int16 a, opus_int16 b, char *file, int line){ + opus_int16 ret; + + ret = a + b; + if ( ret != silk_ADD_SAT16( a, b ) ) + { + fprintf (stderr, "silk_ADD16(%d, %d) in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_ADD32 +#define silk_ADD32(a,b) silk_ADD32_((a), (b), __FILE__, __LINE__) +static inline opus_int32 silk_ADD32_(opus_int32 a, opus_int32 b, char *file, int line){ + opus_int32 ret; + + ret = a + b; + if ( ret != silk_ADD_SAT32( a, b ) ) + { + fprintf (stderr, "silk_ADD32(%d, %d) in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_ADD64 +#define silk_ADD64(a,b) silk_ADD64_((a), (b), __FILE__, __LINE__) +static inline opus_int64 silk_ADD64_(opus_int64 a, opus_int64 b, char *file, int line){ + opus_int64 ret; + + ret = a + b; + if ( ret != silk_ADD_SAT64( a, b ) ) + { + fprintf (stderr, "silk_ADD64(%lld, %lld) in %s: line %d\n", (long long)a, (long long)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SUB16 +#define silk_SUB16(a,b) silk_SUB16_((a), (b), __FILE__, __LINE__) +static inline opus_int16 silk_SUB16_(opus_int16 a, opus_int16 b, char *file, int line){ + opus_int16 ret; + + ret = a - b; + if ( ret != silk_SUB_SAT16( a, b ) ) + { + fprintf (stderr, "silk_SUB16(%d, %d) in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SUB32 +#define silk_SUB32(a,b) silk_SUB32_((a), (b), __FILE__, __LINE__) +static inline opus_int32 silk_SUB32_(opus_int32 a, opus_int32 b, char *file, int line){ + opus_int32 ret; + + ret = a - b; + if ( ret != silk_SUB_SAT32( a, b ) ) + { + fprintf (stderr, "silk_SUB32(%d, %d) in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SUB64 +#define silk_SUB64(a,b) silk_SUB64_((a), (b), __FILE__, __LINE__) +static inline opus_int64 silk_SUB64_(opus_int64 a, opus_int64 b, char *file, int line){ + opus_int64 ret; + + ret = a - b; + if ( ret != silk_SUB_SAT64( a, b ) ) + { + fprintf (stderr, "silk_SUB64(%lld, %lld) in %s: line %d\n", (long long)a, (long long)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_ADD_SAT16 +#define silk_ADD_SAT16(a,b) silk_ADD_SAT16_((a), (b), __FILE__, __LINE__) +static inline opus_int16 silk_ADD_SAT16_( opus_int16 a16, opus_int16 b16, char *file, int line) { + opus_int16 res; + res = (opus_int16)silk_SAT16( silk_ADD32( (opus_int32)(a16), (b16) ) ); + if ( res != silk_SAT16( (opus_int32)a16 + (opus_int32)b16 ) ) + { + fprintf (stderr, "silk_ADD_SAT16(%d, %d) in %s: line %d\n", a16, b16, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return res; +} + +#undef silk_ADD_SAT32 +#define silk_ADD_SAT32(a,b) silk_ADD_SAT32_((a), (b), __FILE__, __LINE__) +static inline opus_int32 silk_ADD_SAT32_(opus_int32 a32, opus_int32 b32, char *file, int line){ + opus_int32 res; + res = ((((opus_uint32)(a32) + (opus_uint32)(b32)) & 0x80000000) == 0 ? \ + ((((a32) & (b32)) & 0x80000000) != 0 ? silk_int32_MIN : (a32)+(b32)) : \ + ((((a32) | (b32)) & 0x80000000) == 0 ? silk_int32_MAX : (a32)+(b32)) ); + if ( res != silk_SAT32( (opus_int64)a32 + (opus_int64)b32 ) ) + { + fprintf (stderr, "silk_ADD_SAT32(%d, %d) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return res; +} + +#undef silk_ADD_SAT64 +#define silk_ADD_SAT64(a,b) silk_ADD_SAT64_((a), (b), __FILE__, __LINE__) +static inline opus_int64 silk_ADD_SAT64_( opus_int64 a64, opus_int64 b64, char *file, int line) { + opus_int64 res; + int fail = 0; + res = ((((a64) + (b64)) & 0x8000000000000000LL) == 0 ? \ + ((((a64) & (b64)) & 0x8000000000000000LL) != 0 ? silk_int64_MIN : (a64)+(b64)) : \ + ((((a64) | (b64)) & 0x8000000000000000LL) == 0 ? silk_int64_MAX : (a64)+(b64)) ); + if( res != a64 + b64 ) { + /* Check that we saturated to the correct extreme value */ + if ( !(( res == silk_int64_MAX && ( ( a64 >> 1 ) + ( b64 >> 1 ) > ( silk_int64_MAX >> 3 ) ) ) || + ( res == silk_int64_MIN && ( ( a64 >> 1 ) + ( b64 >> 1 ) < ( silk_int64_MIN >> 3 ) ) ) ) ) + { + fail = 1; + } + } else { + /* Saturation not necessary */ + fail = res != a64 + b64; + } + if ( fail ) + { + fprintf (stderr, "silk_ADD_SAT64(%lld, %lld) in %s: line %d\n", (long long)a64, (long long)b64, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return res; +} + +#undef silk_SUB_SAT16 +#define silk_SUB_SAT16(a,b) silk_SUB_SAT16_((a), (b), __FILE__, __LINE__) +static inline opus_int16 silk_SUB_SAT16_( opus_int16 a16, opus_int16 b16, char *file, int line ) { + opus_int16 res; + res = (opus_int16)silk_SAT16( silk_SUB32( (opus_int32)(a16), (b16) ) ); + if ( res != silk_SAT16( (opus_int32)a16 - (opus_int32)b16 ) ) + { + fprintf (stderr, "silk_SUB_SAT16(%d, %d) in %s: line %d\n", a16, b16, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return res; +} + +#undef silk_SUB_SAT32 +#define silk_SUB_SAT32(a,b) silk_SUB_SAT32_((a), (b), __FILE__, __LINE__) +static inline opus_int32 silk_SUB_SAT32_( opus_int32 a32, opus_int32 b32, char *file, int line ) { + opus_int32 res; + res = ((((opus_uint32)(a32)-(opus_uint32)(b32)) & 0x80000000) == 0 ? \ + (( (a32) & ((b32)^0x80000000) & 0x80000000) ? silk_int32_MIN : (a32)-(b32)) : \ + ((((a32)^0x80000000) & (b32) & 0x80000000) ? silk_int32_MAX : (a32)-(b32)) ); + if ( res != silk_SAT32( (opus_int64)a32 - (opus_int64)b32 ) ) + { + fprintf (stderr, "silk_SUB_SAT32(%d, %d) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return res; +} + +#undef silk_SUB_SAT64 +#define silk_SUB_SAT64(a,b) silk_SUB_SAT64_((a), (b), __FILE__, __LINE__) +static inline opus_int64 silk_SUB_SAT64_( opus_int64 a64, opus_int64 b64, char *file, int line ) { + opus_int64 res; + int fail = 0; + res = ((((a64)-(b64)) & 0x8000000000000000LL) == 0 ? \ + (( (a64) & ((b64)^0x8000000000000000LL) & 0x8000000000000000LL) ? silk_int64_MIN : (a64)-(b64)) : \ + ((((a64)^0x8000000000000000LL) & (b64) & 0x8000000000000000LL) ? silk_int64_MAX : (a64)-(b64)) ); + if( res != a64 - b64 ) { + /* Check that we saturated to the correct extreme value */ + if( !(( res == silk_int64_MAX && ( ( a64 >> 1 ) + ( b64 >> 1 ) > ( silk_int64_MAX >> 3 ) ) ) || + ( res == silk_int64_MIN && ( ( a64 >> 1 ) + ( b64 >> 1 ) < ( silk_int64_MIN >> 3 ) ) ) )) + { + fail = 1; + } + } else { + /* Saturation not necessary */ + fail = res != a64 - b64; + } + if ( fail ) + { + fprintf (stderr, "silk_SUB_SAT64(%lld, %lld) in %s: line %d\n", (long long)a64, (long long)b64, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return res; +} + +#undef silk_MUL +#define silk_MUL(a,b) silk_MUL_((a), (b), __FILE__, __LINE__) +static inline opus_int32 silk_MUL_(opus_int32 a32, opus_int32 b32, char *file, int line){ + opus_int32 ret; + opus_int64 ret64; + ret = a32 * b32; + ret64 = (opus_int64)a32 * (opus_int64)b32; + if ( (opus_int64)ret != ret64 ) + { + fprintf (stderr, "silk_MUL(%d, %d) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_MUL_uint +#define silk_MUL_uint(a,b) silk_MUL_uint_((a), (b), __FILE__, __LINE__) +static inline opus_uint32 silk_MUL_uint_(opus_uint32 a32, opus_uint32 b32, char *file, int line){ + opus_uint32 ret; + ret = a32 * b32; + if ( (opus_uint64)ret != (opus_uint64)a32 * (opus_uint64)b32 ) + { + fprintf (stderr, "silk_MUL_uint(%u, %u) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_MLA +#define silk_MLA(a,b,c) silk_MLA_((a), (b), (c), __FILE__, __LINE__) +static inline opus_int32 silk_MLA_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){ + opus_int32 ret; + ret = a32 + b32 * c32; + if ( (opus_int64)ret != (opus_int64)a32 + (opus_int64)b32 * (opus_int64)c32 ) + { + fprintf (stderr, "silk_MLA(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_MLA_uint +#define silk_MLA_uint(a,b,c) silk_MLA_uint_((a), (b), (c), __FILE__, __LINE__) +static inline opus_int32 silk_MLA_uint_(opus_uint32 a32, opus_uint32 b32, opus_uint32 c32, char *file, int line){ + opus_uint32 ret; + ret = a32 + b32 * c32; + if ( (opus_int64)ret != (opus_int64)a32 + (opus_int64)b32 * (opus_int64)c32 ) + { + fprintf (stderr, "silk_MLA_uint(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SMULWB +#define silk_SMULWB(a,b) silk_SMULWB_((a), (b), __FILE__, __LINE__) +static inline opus_int32 silk_SMULWB_(opus_int32 a32, opus_int32 b32, char *file, int line){ + opus_int32 ret; + ret = (a32 >> 16) * (opus_int32)((opus_int16)b32) + (((a32 & 0x0000FFFF) * (opus_int32)((opus_int16)b32)) >> 16); + if ( (opus_int64)ret != ((opus_int64)a32 * (opus_int16)b32) >> 16 ) + { + fprintf (stderr, "silk_SMULWB(%d, %d) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SMLAWB +#define silk_SMLAWB(a,b,c) silk_SMLAWB_((a), (b), (c), __FILE__, __LINE__) +static inline opus_int32 silk_SMLAWB_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){ + opus_int32 ret; + ret = silk_ADD32( a32, silk_SMULWB( b32, c32 ) ); + if ( silk_ADD32( a32, silk_SMULWB( b32, c32 ) ) != silk_ADD_SAT32( a32, silk_SMULWB( b32, c32 ) ) ) + { + fprintf (stderr, "silk_SMLAWB(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SMULWT +#define silk_SMULWT(a,b) silk_SMULWT_((a), (b), __FILE__, __LINE__) +static inline opus_int32 silk_SMULWT_(opus_int32 a32, opus_int32 b32, char *file, int line){ + opus_int32 ret; + ret = (a32 >> 16) * (b32 >> 16) + (((a32 & 0x0000FFFF) * (b32 >> 16)) >> 16); + if ( (opus_int64)ret != ((opus_int64)a32 * (b32 >> 16)) >> 16 ) + { + fprintf (stderr, "silk_SMULWT(%d, %d) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SMLAWT +#define silk_SMLAWT(a,b,c) silk_SMLAWT_((a), (b), (c), __FILE__, __LINE__) +static inline opus_int32 silk_SMLAWT_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){ + opus_int32 ret; + ret = a32 + ((b32 >> 16) * (c32 >> 16)) + (((b32 & 0x0000FFFF) * ((c32 >> 16)) >> 16)); + if ( (opus_int64)ret != (opus_int64)a32 + (((opus_int64)b32 * (c32 >> 16)) >> 16) ) + { + fprintf (stderr, "silk_SMLAWT(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SMULL +#define silk_SMULL(a,b) silk_SMULL_((a), (b), __FILE__, __LINE__) +static inline opus_int64 silk_SMULL_(opus_int64 a64, opus_int64 b64, char *file, int line){ + opus_int64 ret64; + int fail = 0; + ret64 = a64 * b64; + if( b64 != 0 ) { + fail = a64 != (ret64 / b64); + } else if( a64 != 0 ) { + fail = b64 != (ret64 / a64); + } + if ( fail ) + { + fprintf (stderr, "silk_SMULL(%lld, %lld) in %s: line %d\n", (long long)a64, (long long)b64, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret64; +} + +/* no checking needed for silk_SMULBB */ +#undef silk_SMLABB +#define silk_SMLABB(a,b,c) silk_SMLABB_((a), (b), (c), __FILE__, __LINE__) +static inline opus_int32 silk_SMLABB_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){ + opus_int32 ret; + ret = a32 + (opus_int32)((opus_int16)b32) * (opus_int32)((opus_int16)c32); + if ( (opus_int64)ret != (opus_int64)a32 + (opus_int64)b32 * (opus_int16)c32 ) + { + fprintf (stderr, "silk_SMLABB(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +/* no checking needed for silk_SMULBT */ +#undef silk_SMLABT +#define silk_SMLABT(a,b,c) silk_SMLABT_((a), (b), (c), __FILE__, __LINE__) +static inline opus_int32 silk_SMLABT_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){ + opus_int32 ret; + ret = a32 + ((opus_int32)((opus_int16)b32)) * (c32 >> 16); + if ( (opus_int64)ret != (opus_int64)a32 + (opus_int64)b32 * (c32 >> 16) ) + { + fprintf (stderr, "silk_SMLABT(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +/* no checking needed for silk_SMULTT */ +#undef silk_SMLATT +#define silk_SMLATT(a,b,c) silk_SMLATT_((a), (b), (c), __FILE__, __LINE__) +static inline opus_int32 silk_SMLATT_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){ + opus_int32 ret; + ret = a32 + (b32 >> 16) * (c32 >> 16); + if ( (opus_int64)ret != (opus_int64)a32 + (b32 >> 16) * (c32 >> 16) ) + { + fprintf (stderr, "silk_SMLATT(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SMULWW +#define silk_SMULWW(a,b) silk_SMULWW_((a), (b), __FILE__, __LINE__) +static inline opus_int32 silk_SMULWW_(opus_int32 a32, opus_int32 b32, char *file, int line){ + opus_int32 ret, tmp1, tmp2; + opus_int64 ret64; + int fail = 0; + + ret = silk_SMULWB( a32, b32 ); + tmp1 = silk_RSHIFT_ROUND( b32, 16 ); + tmp2 = silk_MUL( a32, tmp1 ); + + fail |= (opus_int64)tmp2 != (opus_int64) a32 * (opus_int64) tmp1; + + tmp1 = ret; + ret = silk_ADD32( tmp1, tmp2 ); + fail |= silk_ADD32( tmp1, tmp2 ) != silk_ADD_SAT32( tmp1, tmp2 ); + + ret64 = silk_RSHIFT64( silk_SMULL( a32, b32 ), 16 ); + fail |= (opus_int64)ret != ret64; + + if ( fail ) + { + fprintf (stderr, "silk_SMULWT(%d, %d) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + + return ret; +} + +#undef silk_SMLAWW +#define silk_SMLAWW(a,b,c) silk_SMLAWW_((a), (b), (c), __FILE__, __LINE__) +static inline opus_int32 silk_SMLAWW_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){ + opus_int32 ret, tmp; + + tmp = silk_SMULWW( b32, c32 ); + ret = silk_ADD32( a32, tmp ); + if ( ret != silk_ADD_SAT32( a32, tmp ) ) + { + fprintf (stderr, "silk_SMLAWW(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +/* Multiply-accumulate macros that allow overflow in the addition (ie, no asserts in debug mode) */ +#undef silk_MLA_ovflw +#define silk_MLA_ovflw(a32, b32, c32) ((a32) + ((b32) * (c32))) +#undef silk_SMLABB_ovflw +#define silk_SMLABB_ovflw(a32, b32, c32) ((a32) + ((opus_int32)((opus_int16)(b32))) * (opus_int32)((opus_int16)(c32))) + +/* no checking needed for silk_SMULL + no checking needed for silk_SMLAL + no checking needed for silk_SMLALBB + no checking needed for SigProcFIX_CLZ16 + no checking needed for SigProcFIX_CLZ32*/ + +#undef silk_DIV32 +#define silk_DIV32(a,b) silk_DIV32_((a), (b), __FILE__, __LINE__) +static inline opus_int32 silk_DIV32_(opus_int32 a32, opus_int32 b32, char *file, int line){ + if ( b32 == 0 ) + { + fprintf (stderr, "silk_DIV32(%d, %d) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return a32 / b32; +} + +#undef silk_DIV32_16 +#define silk_DIV32_16(a,b) silk_DIV32_16_((a), (b), __FILE__, __LINE__) +static inline opus_int32 silk_DIV32_16_(opus_int32 a32, opus_int32 b32, char *file, int line){ + int fail = 0; + fail |= b32 == 0; + fail |= b32 > silk_int16_MAX; + fail |= b32 < silk_int16_MIN; + if ( fail ) + { + fprintf (stderr, "silk_DIV32_16(%d, %d) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return a32 / b32; +} + +/* no checking needed for silk_SAT8 + no checking needed for silk_SAT16 + no checking needed for silk_SAT32 + no checking needed for silk_POS_SAT32 + no checking needed for silk_ADD_POS_SAT8 + no checking needed for silk_ADD_POS_SAT16 + no checking needed for silk_ADD_POS_SAT32 + no checking needed for silk_ADD_POS_SAT64 */ + +#undef silk_LSHIFT8 +#define silk_LSHIFT8(a,b) silk_LSHIFT8_((a), (b), __FILE__, __LINE__) +static inline opus_int8 silk_LSHIFT8_(opus_int8 a, opus_int32 shift, char *file, int line){ + opus_int8 ret; + int fail = 0; + ret = a << shift; + fail |= shift < 0; + fail |= shift >= 8; + fail |= (opus_int64)ret != ((opus_int64)a) << shift; + if ( fail ) + { + fprintf (stderr, "silk_LSHIFT8(%d, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_LSHIFT16 +#define silk_LSHIFT16(a,b) silk_LSHIFT16_((a), (b), __FILE__, __LINE__) +static inline opus_int16 silk_LSHIFT16_(opus_int16 a, opus_int32 shift, char *file, int line){ + opus_int16 ret; + int fail = 0; + ret = a << shift; + fail |= shift < 0; + fail |= shift >= 16; + fail |= (opus_int64)ret != ((opus_int64)a) << shift; + if ( fail ) + { + fprintf (stderr, "silk_LSHIFT16(%d, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_LSHIFT32 +#define silk_LSHIFT32(a,b) silk_LSHIFT32_((a), (b), __FILE__, __LINE__) +static inline opus_int32 silk_LSHIFT32_(opus_int32 a, opus_int32 shift, char *file, int line){ + opus_int32 ret; + int fail = 0; + ret = a << shift; + fail |= shift < 0; + fail |= shift >= 32; + fail |= (opus_int64)ret != ((opus_int64)a) << shift; + if ( fail ) + { + fprintf (stderr, "silk_LSHIFT32(%d, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_LSHIFT64 +#define silk_LSHIFT64(a,b) silk_LSHIFT64_((a), (b), __FILE__, __LINE__) +static inline opus_int64 silk_LSHIFT64_(opus_int64 a, opus_int shift, char *file, int line){ + opus_int64 ret; + int fail = 0; + ret = a << shift; + fail |= shift < 0; + fail |= shift >= 64; + fail |= (ret>>shift) != ((opus_int64)a); + if ( fail ) + { + fprintf (stderr, "silk_LSHIFT64(%lld, %d) in %s: line %d\n", (long long)a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_LSHIFT_ovflw +#define silk_LSHIFT_ovflw(a,b) silk_LSHIFT_ovflw_((a), (b), __FILE__, __LINE__) +static inline opus_int32 silk_LSHIFT_ovflw_(opus_int32 a, opus_int32 shift, char *file, int line){ + if ( (shift < 0) || (shift >= 32) ) /* no check for overflow */ + { + fprintf (stderr, "silk_LSHIFT_ovflw(%d, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return a << shift; +} + +#undef silk_LSHIFT_uint +#define silk_LSHIFT_uint(a,b) silk_LSHIFT_uint_((a), (b), __FILE__, __LINE__) +static inline opus_uint32 silk_LSHIFT_uint_(opus_uint32 a, opus_int32 shift, char *file, int line){ + opus_uint32 ret; + ret = a << shift; + if ( (shift < 0) || ((opus_int64)ret != ((opus_int64)a) << shift)) + { + fprintf (stderr, "silk_LSHIFT_uint(%u, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_RSHIFT8 +#define silk_RSHITF8(a,b) silk_RSHIFT8_((a), (b), __FILE__, __LINE__) +static inline opus_int8 silk_RSHIFT8_(opus_int8 a, opus_int32 shift, char *file, int line){ + if ( (shift < 0) || (shift>=8) ) + { + fprintf (stderr, "silk_RSHITF8(%d, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return a >> shift; +} + +#undef silk_RSHIFT16 +#define silk_RSHITF16(a,b) silk_RSHIFT16_((a), (b), __FILE__, __LINE__) +static inline opus_int16 silk_RSHIFT16_(opus_int16 a, opus_int32 shift, char *file, int line){ + if ( (shift < 0) || (shift>=16) ) + { + fprintf (stderr, "silk_RSHITF16(%d, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return a >> shift; +} + +#undef silk_RSHIFT32 +#define silk_RSHIFT32(a,b) silk_RSHIFT32_((a), (b), __FILE__, __LINE__) +static inline opus_int32 silk_RSHIFT32_(opus_int32 a, opus_int32 shift, char *file, int line){ + if ( (shift < 0) || (shift>=32) ) + { + fprintf (stderr, "silk_RSHITF32(%d, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return a >> shift; +} + +#undef silk_RSHIFT64 +#define silk_RSHIFT64(a,b) silk_RSHIFT64_((a), (b), __FILE__, __LINE__) +static inline opus_int64 silk_RSHIFT64_(opus_int64 a, opus_int64 shift, char *file, int line){ + if ( (shift < 0) || (shift>=64) ) + { + fprintf (stderr, "silk_RSHITF64(%lld, %lld) in %s: line %d\n", (long long)a, (long long)shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return a >> shift; +} + +#undef silk_RSHIFT_uint +#define silk_RSHIFT_uint(a,b) silk_RSHIFT_uint_((a), (b), __FILE__, __LINE__) +static inline opus_uint32 silk_RSHIFT_uint_(opus_uint32 a, opus_int32 shift, char *file, int line){ + if ( (shift < 0) || (shift>32) ) + { + fprintf (stderr, "silk_RSHIFT_uint(%u, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return a >> shift; +} + +#undef silk_ADD_LSHIFT +#define silk_ADD_LSHIFT(a,b,c) silk_ADD_LSHIFT_((a), (b), (c), __FILE__, __LINE__) +static inline int silk_ADD_LSHIFT_(int a, int b, int shift, char *file, int line){ + opus_int16 ret; + ret = a + (b << shift); + if ( (shift < 0) || (shift>15) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) << shift)) ) + { + fprintf (stderr, "silk_ADD_LSHIFT(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; /* shift >= 0 */ +} + +#undef silk_ADD_LSHIFT32 +#define silk_ADD_LSHIFT32(a,b,c) silk_ADD_LSHIFT32_((a), (b), (c), __FILE__, __LINE__) +static inline opus_int32 silk_ADD_LSHIFT32_(opus_int32 a, opus_int32 b, opus_int32 shift, char *file, int line){ + opus_int32 ret; + ret = a + (b << shift); + if ( (shift < 0) || (shift>31) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) << shift)) ) + { + fprintf (stderr, "silk_ADD_LSHIFT32(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; /* shift >= 0 */ +} + +#undef silk_ADD_LSHIFT_uint +#define silk_ADD_LSHIFT_uint(a,b,c) silk_ADD_LSHIFT_uint_((a), (b), (c), __FILE__, __LINE__) +static inline opus_uint32 silk_ADD_LSHIFT_uint_(opus_uint32 a, opus_uint32 b, opus_int32 shift, char *file, int line){ + opus_uint32 ret; + ret = a + (b << shift); + if ( (shift < 0) || (shift>32) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) << shift)) ) + { + fprintf (stderr, "silk_ADD_LSHIFT_uint(%u, %u, %d) in %s: line %d\n", a, b, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; /* shift >= 0 */ +} + +#undef silk_ADD_RSHIFT +#define silk_ADD_RSHIFT(a,b,c) silk_ADD_RSHIFT_((a), (b), (c), __FILE__, __LINE__) +static inline int silk_ADD_RSHIFT_(int a, int b, int shift, char *file, int line){ + opus_int16 ret; + ret = a + (b >> shift); + if ( (shift < 0) || (shift>15) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) >> shift)) ) + { + fprintf (stderr, "silk_ADD_RSHIFT(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; /* shift > 0 */ +} + +#undef silk_ADD_RSHIFT32 +#define silk_ADD_RSHIFT32(a,b,c) silk_ADD_RSHIFT32_((a), (b), (c), __FILE__, __LINE__) +static inline opus_int32 silk_ADD_RSHIFT32_(opus_int32 a, opus_int32 b, opus_int32 shift, char *file, int line){ + opus_int32 ret; + ret = a + (b >> shift); + if ( (shift < 0) || (shift>31) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) >> shift)) ) + { + fprintf (stderr, "silk_ADD_RSHIFT32(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; /* shift > 0 */ +} + +#undef silk_ADD_RSHIFT_uint +#define silk_ADD_RSHIFT_uint(a,b,c) silk_ADD_RSHIFT_uint_((a), (b), (c), __FILE__, __LINE__) +static inline opus_uint32 silk_ADD_RSHIFT_uint_(opus_uint32 a, opus_uint32 b, opus_int32 shift, char *file, int line){ + opus_uint32 ret; + ret = a + (b >> shift); + if ( (shift < 0) || (shift>32) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) >> shift)) ) + { + fprintf (stderr, "silk_ADD_RSHIFT_uint(%u, %u, %d) in %s: line %d\n", a, b, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; /* shift > 0 */ +} + +#undef silk_SUB_LSHIFT32 +#define silk_SUB_LSHIFT32(a,b,c) silk_SUB_LSHIFT32_((a), (b), (c), __FILE__, __LINE__) +static inline opus_int32 silk_SUB_LSHIFT32_(opus_int32 a, opus_int32 b, opus_int32 shift, char *file, int line){ + opus_int32 ret; + ret = a - (b << shift); + if ( (shift < 0) || (shift>31) || ((opus_int64)ret != (opus_int64)a - (((opus_int64)b) << shift)) ) + { + fprintf (stderr, "silk_SUB_LSHIFT32(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; /* shift >= 0 */ +} + +#undef silk_SUB_RSHIFT32 +#define silk_SUB_RSHIFT32(a,b,c) silk_SUB_RSHIFT32_((a), (b), (c), __FILE__, __LINE__) +static inline opus_int32 silk_SUB_RSHIFT32_(opus_int32 a, opus_int32 b, opus_int32 shift, char *file, int line){ + opus_int32 ret; + ret = a - (b >> shift); + if ( (shift < 0) || (shift>31) || ((opus_int64)ret != (opus_int64)a - (((opus_int64)b) >> shift)) ) + { + fprintf (stderr, "silk_SUB_RSHIFT32(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; /* shift > 0 */ +} + +#undef silk_RSHIFT_ROUND +#define silk_RSHIFT_ROUND(a,b) silk_RSHIFT_ROUND_((a), (b), __FILE__, __LINE__) +static inline opus_int32 silk_RSHIFT_ROUND_(opus_int32 a, opus_int32 shift, char *file, int line){ + opus_int32 ret; + ret = shift == 1 ? (a >> 1) + (a & 1) : ((a >> (shift - 1)) + 1) >> 1; + /* the marco definition can't handle a shift of zero */ + if ( (shift <= 0) || (shift>31) || ((opus_int64)ret != ((opus_int64)a + ((opus_int64)1 << (shift - 1))) >> shift) ) + { + fprintf (stderr, "silk_RSHIFT_ROUND(%d, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_RSHIFT_ROUND64 +#define silk_RSHIFT_ROUND64(a,b) silk_RSHIFT_ROUND64_((a), (b), __FILE__, __LINE__) +static inline opus_int64 silk_RSHIFT_ROUND64_(opus_int64 a, opus_int32 shift, char *file, int line){ + opus_int64 ret; + /* the marco definition can't handle a shift of zero */ + if ( (shift <= 0) || (shift>=64) ) + { + fprintf (stderr, "silk_RSHIFT_ROUND64(%lld, %d) in %s: line %d\n", (long long)a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + ret = shift == 1 ? (a >> 1) + (a & 1) : ((a >> (shift - 1)) + 1) >> 1; + return ret; +} + +/* silk_abs is used on floats also, so doesn't work... */ +/*#undef silk_abs +static inline opus_int32 silk_abs(opus_int32 a){ + silk_assert(a != 0x80000000); + return (((a) > 0) ? (a) : -(a)); // Be careful, silk_abs returns wrong when input equals to silk_intXX_MIN +}*/ + +#undef silk_abs_int64 +#define silk_abs_int64(a) silk_abs_int64_((a), __FILE__, __LINE__) +static inline opus_int64 silk_abs_int64_(opus_int64 a, char *file, int line){ + if ( a == silk_int64_MIN ) + { + fprintf (stderr, "silk_abs_int64(%lld) in %s: line %d\n", (long long)a, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return (((a) > 0) ? (a) : -(a)); /* Be careful, silk_abs returns wrong when input equals to silk_intXX_MIN */ +} + +#undef silk_abs_int32 +#define silk_abs_int32(a) silk_abs_int32_((a), __FILE__, __LINE__) +static inline opus_int32 silk_abs_int32_(opus_int32 a, char *file, int line){ + if ( a == silk_int32_MIN ) + { + fprintf (stderr, "silk_abs_int32(%d) in %s: line %d\n", a, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return silk_abs(a); +} + +#undef silk_CHECK_FIT8 +#define silk_CHECK_FIT8(a) silk_CHECK_FIT8_((a), __FILE__, __LINE__) +static inline opus_int8 silk_CHECK_FIT8_( opus_int64 a, char *file, int line ){ + opus_int8 ret; + ret = (opus_int8)a; + if ( (opus_int64)ret != a ) + { + fprintf (stderr, "silk_CHECK_FIT8(%lld) in %s: line %d\n", (long long)a, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return( ret ); +} + +#undef silk_CHECK_FIT16 +#define silk_CHECK_FIT16(a) silk_CHECK_FIT16_((a), __FILE__, __LINE__) +static inline opus_int16 silk_CHECK_FIT16_( opus_int64 a, char *file, int line ){ + opus_int16 ret; + ret = (opus_int16)a; + if ( (opus_int64)ret != a ) + { + fprintf (stderr, "silk_CHECK_FIT16(%lld) in %s: line %d\n", (long long)a, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return( ret ); +} + +#undef silk_CHECK_FIT32 +#define silk_CHECK_FIT32(a) silk_CHECK_FIT32_((a), __FILE__, __LINE__) +static inline opus_int32 silk_CHECK_FIT32_( opus_int64 a, char *file, int line ){ + opus_int32 ret; + ret = (opus_int32)a; + if ( (opus_int64)ret != a ) + { + fprintf (stderr, "silk_CHECK_FIT32(%lld) in %s: line %d\n", (long long)a, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return( ret ); +} + +/* no checking for silk_NSHIFT_MUL_32_32 + no checking for silk_NSHIFT_MUL_16_16 + no checking needed for silk_min + no checking needed for silk_max + no checking needed for silk_sign +*/ + +#endif +#endif /* MACRO_DEBUG_H */ diff --git a/code/opus-1.0.2/silk/NLSF2A.c b/code/opus-1.0.2/silk/NLSF2A.c new file mode 100644 index 00000000..10b66b64 --- /dev/null +++ b/code/opus-1.0.2/silk/NLSF2A.c @@ -0,0 +1,178 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* 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 */ +/* functions are accurate inverses of each other */ + +#include "SigProc_FIX.h" +#include "tables.h" + +#define QA 16 + +/* helper function for NLSF2A(..) */ +static inline void silk_NLSF2A_find_poly( + opus_int32 *out, /* O intermediate polynomial, QA [dd+1] */ + const opus_int32 *cLSF, /* I vector of interleaved 2*cos(LSFs), QA [d] */ + opus_int dd /* I polynomial order (= 1/2 * filter order) */ +) +{ + opus_int k, n; + opus_int32 ftmp; + + out[0] = silk_LSHIFT( 1, QA ); + out[1] = -cLSF[0]; + for( k = 1; k < dd; k++ ) { + ftmp = cLSF[2*k]; /* QA*/ + out[k+1] = silk_LSHIFT( out[k-1], 1 ) - (opus_int32)silk_RSHIFT_ROUND64( silk_SMULL( ftmp, out[k] ), QA ); + for( n = k; n > 1; n-- ) { + out[n] += out[n-2] - (opus_int32)silk_RSHIFT_ROUND64( silk_SMULL( ftmp, out[n-1] ), QA ); + } + out[1] -= ftmp; + } +} + +/* compute whitening filter coefficients from normalized line spectral frequencies */ +void silk_NLSF2A( + opus_int16 *a_Q12, /* O monic whitening filter coefficients in Q12, [ d ] */ + const opus_int16 *NLSF, /* I normalized line spectral frequencies in Q15, [ d ] */ + const opus_int d /* I filter order (should be even) */ +) +{ + /* This ordering was found to maximize quality. It improves numerical accuracy of + silk_NLSF2A_find_poly() compared to "standard" ordering. */ + static const unsigned char ordering16[16] = { + 0, 15, 8, 7, 4, 11, 12, 3, 2, 13, 10, 5, 6, 9, 14, 1 + }; + static const unsigned char ordering10[10] = { + 0, 9, 6, 3, 4, 5, 8, 1, 2, 7 + }; + const unsigned char *ordering; + opus_int k, i, dd; + opus_int32 cos_LSF_QA[ SILK_MAX_ORDER_LPC ]; + opus_int32 P[ SILK_MAX_ORDER_LPC / 2 + 1 ], Q[ SILK_MAX_ORDER_LPC / 2 + 1 ]; + opus_int32 Ptmp, Qtmp, f_int, f_frac, cos_val, delta; + opus_int32 a32_QA1[ SILK_MAX_ORDER_LPC ]; + opus_int32 maxabs, absval, idx=0, sc_Q16; + + silk_assert( LSF_COS_TAB_SZ_FIX == 128 ); + silk_assert( d==10||d==16 ); + + /* convert LSFs to 2*cos(LSF), using piecewise linear curve from table */ + ordering = d == 16 ? ordering16 : ordering10; + for( k = 0; k < d; k++ ) { + silk_assert(NLSF[k] >= 0 ); + + /* f_int on a scale 0-127 (rounded down) */ + f_int = silk_RSHIFT( NLSF[k], 15 - 7 ); + + /* f_frac, range: 0..255 */ + f_frac = NLSF[k] - silk_LSHIFT( f_int, 15 - 7 ); + + silk_assert(f_int >= 0); + silk_assert(f_int < LSF_COS_TAB_SZ_FIX ); + + /* Read start and end value from table */ + cos_val = silk_LSFCosTab_FIX_Q12[ f_int ]; /* Q12 */ + delta = silk_LSFCosTab_FIX_Q12[ f_int + 1 ] - cos_val; /* Q12, with a range of 0..200 */ + + /* Linear interpolation */ + cos_LSF_QA[ordering[k]] = silk_RSHIFT_ROUND( silk_LSHIFT( cos_val, 8 ) + silk_MUL( delta, f_frac ), 20 - QA ); /* QA */ + } + + dd = silk_RSHIFT( d, 1 ); + + /* generate even and odd polynomials using convolution */ + silk_NLSF2A_find_poly( P, &cos_LSF_QA[ 0 ], dd ); + silk_NLSF2A_find_poly( Q, &cos_LSF_QA[ 1 ], dd ); + + /* convert even and odd polynomials to opus_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 */ + a32_QA1[ k ] = -Qtmp - Ptmp; /* QA+1 */ + a32_QA1[ d-k-1 ] = Qtmp - Ptmp; /* QA+1 */ + } + + /* Limit the maximum absolute value of the prediction coefficients, so that they'll fit in int16 */ + for( i = 0; i < 10; i++ ) { + /* Find maximum absolute value and its index */ + maxabs = 0; + for( k = 0; k < d; k++ ) { + absval = silk_abs( a32_QA1[k] ); + if( absval > maxabs ) { + maxabs = absval; + idx = k; + } + } + maxabs = silk_RSHIFT_ROUND( maxabs, QA + 1 - 12 ); /* QA+1 -> Q12 */ + + if( maxabs > silk_int16_MAX ) { + /* Reduce magnitude of prediction coefficients */ + maxabs = silk_min( maxabs, 163838 ); /* ( silk_int32_MAX >> 14 ) + silk_int16_MAX = 163838 */ + sc_Q16 = SILK_FIX_CONST( 0.999, 16 ) - silk_DIV32( silk_LSHIFT( maxabs - silk_int16_MAX, 14 ), + silk_RSHIFT32( silk_MUL( maxabs, idx + 1), 2 ) ); + silk_bwexpander_32( a32_QA1, d, sc_Q16 ); + } else { + break; + } + } + + if( i == 10 ) { + /* Reached the last iteration, clip the coefficients */ + for( k = 0; k < d; k++ ) { + a_Q12[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( a32_QA1[ k ], QA + 1 - 12 ) ); /* QA+1 -> Q12 */ + a32_QA1[ k ] = silk_LSHIFT( (opus_int32)a_Q12[ k ], QA + 1 - 12 ); + } + } else { + for( k = 0; k < d; k++ ) { + a_Q12[ k ] = (opus_int16)silk_RSHIFT_ROUND( a32_QA1[ k ], QA + 1 - 12 ); /* QA+1 -> Q12 */ + } + } + + for( i = 0; i < MAX_LPC_STABILIZE_ITERATIONS; i++ ) { + if( silk_LPC_inverse_pred_gain( a_Q12, d ) < SILK_FIX_CONST( 1.0 / MAX_PREDICTION_POWER_GAIN, 30 ) ) { + /* Prediction coefficients are (too close to) unstable; apply bandwidth expansion */ + /* on the unscaled coefficients, convert to Q12 and measure again */ + silk_bwexpander_32( a32_QA1, d, 65536 - silk_LSHIFT( 2, i ) ); + for( k = 0; k < d; k++ ) { + a_Q12[ k ] = (opus_int16)silk_RSHIFT_ROUND( a32_QA1[ k ], QA + 1 - 12 ); /* QA+1 -> Q12 */ + } + } else { + break; + } + } +} + diff --git a/code/opus-1.0.2/silk/NLSF_VQ.c b/code/opus-1.0.2/silk/NLSF_VQ.c new file mode 100644 index 00000000..352dda26 --- /dev/null +++ b/code/opus-1.0.2/silk/NLSF_VQ.c @@ -0,0 +1,68 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Compute quantization errors for an LPC_order element input vector for a VQ codebook */ +void silk_NLSF_VQ( + opus_int32 err_Q26[], /* O Quantization errors [K] */ + const opus_int16 in_Q15[], /* I Input vectors to be quantized [LPC_order] */ + const opus_uint8 pCB_Q8[], /* I Codebook vectors [K*LPC_order] */ + const opus_int K, /* I Number of codebook vectors */ + const opus_int LPC_order /* I Number of LPCs */ +) +{ + opus_int i, m; + opus_int32 diff_Q15, sum_error_Q30, sum_error_Q26; + + silk_assert( LPC_order <= 16 ); + silk_assert( ( LPC_order & 1 ) == 0 ); + + /* Loop over codebook */ + for( i = 0; i < K; i++ ) { + sum_error_Q26 = 0; + for( m = 0; m < LPC_order; m += 2 ) { + /* Compute weighted squared quantization error for index m */ + diff_Q15 = silk_SUB_LSHIFT32( in_Q15[ m ], (opus_int32)*pCB_Q8++, 7 ); /* range: [ -32767 : 32767 ]*/ + sum_error_Q30 = silk_SMULBB( diff_Q15, diff_Q15 ); + + /* Compute weighted squared quantization error for index m + 1 */ + diff_Q15 = silk_SUB_LSHIFT32( in_Q15[m + 1], (opus_int32)*pCB_Q8++, 7 ); /* range: [ -32767 : 32767 ]*/ + sum_error_Q30 = silk_SMLABB( sum_error_Q30, diff_Q15, diff_Q15 ); + + sum_error_Q26 = silk_ADD_RSHIFT32( sum_error_Q26, sum_error_Q30, 4 ); + + silk_assert( sum_error_Q26 >= 0 ); + silk_assert( sum_error_Q30 >= 0 ); + } + err_Q26[ i ] = sum_error_Q26; + } +} diff --git a/code/opus-1.0.2/silk/NLSF_VQ_weights_laroia.c b/code/opus-1.0.2/silk/NLSF_VQ_weights_laroia.c new file mode 100644 index 00000000..05bb17af --- /dev/null +++ b/code/opus-1.0.2/silk/NLSF_VQ_weights_laroia.c @@ -0,0 +1,80 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "define.h" +#include "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. +*/ + +/* Laroia low complexity NLSF weights */ +void silk_NLSF_VQ_weights_laroia( + opus_int16 *pNLSFW_Q_OUT, /* O Pointer to input vector weights [D] */ + const opus_int16 *pNLSF_Q15, /* I Pointer to input vector [D] */ + const opus_int D /* I Input vector dimension (even) */ +) +{ + opus_int k; + opus_int32 tmp1_int, tmp2_int; + + silk_assert( D > 0 ); + silk_assert( ( D & 1 ) == 0 ); + + /* First value */ + tmp1_int = silk_max_int( pNLSF_Q15[ 0 ], 1 ); + tmp1_int = silk_DIV32_16( (opus_int32)1 << ( 15 + NLSF_W_Q ), tmp1_int ); + tmp2_int = silk_max_int( pNLSF_Q15[ 1 ] - pNLSF_Q15[ 0 ], 1 ); + tmp2_int = silk_DIV32_16( (opus_int32)1 << ( 15 + NLSF_W_Q ), tmp2_int ); + pNLSFW_Q_OUT[ 0 ] = (opus_int16)silk_min_int( tmp1_int + tmp2_int, silk_int16_MAX ); + silk_assert( pNLSFW_Q_OUT[ 0 ] > 0 ); + + /* Main loop */ + for( k = 1; k < D - 1; k += 2 ) { + tmp1_int = silk_max_int( pNLSF_Q15[ k + 1 ] - pNLSF_Q15[ k ], 1 ); + tmp1_int = silk_DIV32_16( (opus_int32)1 << ( 15 + NLSF_W_Q ), tmp1_int ); + pNLSFW_Q_OUT[ k ] = (opus_int16)silk_min_int( tmp1_int + tmp2_int, silk_int16_MAX ); + silk_assert( pNLSFW_Q_OUT[ k ] > 0 ); + + tmp2_int = silk_max_int( pNLSF_Q15[ k + 2 ] - pNLSF_Q15[ k + 1 ], 1 ); + tmp2_int = silk_DIV32_16( (opus_int32)1 << ( 15 + NLSF_W_Q ), tmp2_int ); + pNLSFW_Q_OUT[ k + 1 ] = (opus_int16)silk_min_int( tmp1_int + tmp2_int, silk_int16_MAX ); + silk_assert( pNLSFW_Q_OUT[ k + 1 ] > 0 ); + } + + /* Last value */ + tmp1_int = silk_max_int( ( 1 << 15 ) - pNLSF_Q15[ D - 1 ], 1 ); + tmp1_int = silk_DIV32_16( (opus_int32)1 << ( 15 + NLSF_W_Q ), tmp1_int ); + pNLSFW_Q_OUT[ D - 1 ] = (opus_int16)silk_min_int( tmp1_int + tmp2_int, silk_int16_MAX ); + silk_assert( pNLSFW_Q_OUT[ D - 1 ] > 0 ); +} diff --git a/code/opus-1.0.2/silk/NLSF_decode.c b/code/opus-1.0.2/silk/NLSF_decode.c new file mode 100644 index 00000000..e007c49a --- /dev/null +++ b/code/opus-1.0.2/silk/NLSF_decode.c @@ -0,0 +1,101 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Predictive dequantizer for NLSF residuals */ +static inline void silk_NLSF_residual_dequant( /* O Returns RD value in Q30 */ + opus_int16 x_Q10[], /* O Output [ order ] */ + const opus_int8 indices[], /* I Quantization indices [ order ] */ + const opus_uint8 pred_coef_Q8[], /* I Backward predictor coefs [ order ] */ + const opus_int quant_step_size_Q16, /* I Quantization step size */ + const opus_int16 order /* I Number of input values */ +) +{ + opus_int i, out_Q10, pred_Q10; + + out_Q10 = 0; + for( i = order-1; i >= 0; i-- ) { + pred_Q10 = silk_RSHIFT( silk_SMULBB( out_Q10, (opus_int16)pred_coef_Q8[ i ] ), 8 ); + out_Q10 = silk_LSHIFT( indices[ i ], 10 ); + if( out_Q10 > 0 ) { + out_Q10 = silk_SUB16( out_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + } else if( out_Q10 < 0 ) { + out_Q10 = silk_ADD16( out_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + } + out_Q10 = silk_SMLAWB( pred_Q10, (opus_int32)out_Q10, quant_step_size_Q16 ); + x_Q10[ i ] = out_Q10; + } +} + + +/***********************/ +/* NLSF vector decoder */ +/***********************/ +void silk_NLSF_decode( + opus_int16 *pNLSF_Q15, /* O Quantized NLSF vector [ LPC_ORDER ] */ + opus_int8 *NLSFIndices, /* I Codebook path vector [ LPC_ORDER + 1 ] */ + const silk_NLSF_CB_struct *psNLSF_CB /* I Codebook object */ +) +{ + opus_int i; + opus_uint8 pred_Q8[ MAX_LPC_ORDER ]; + opus_int16 ec_ix[ MAX_LPC_ORDER ]; + opus_int16 res_Q10[ MAX_LPC_ORDER ]; + opus_int16 W_tmp_QW[ MAX_LPC_ORDER ]; + opus_int32 W_tmp_Q9, NLSF_Q15_tmp; + const opus_uint8 *pCB_element; + + /* Decode first stage */ + pCB_element = &psNLSF_CB->CB1_NLSF_Q8[ NLSFIndices[ 0 ] * psNLSF_CB->order ]; + for( i = 0; i < psNLSF_CB->order; i++ ) { + pNLSF_Q15[ i ] = silk_LSHIFT( (opus_int16)pCB_element[ i ], 7 ); + } + + /* Unpack entropy table indices and predictor for current CB1 index */ + silk_NLSF_unpack( ec_ix, pred_Q8, psNLSF_CB, NLSFIndices[ 0 ] ); + + /* Predictive residual dequantizer */ + silk_NLSF_residual_dequant( res_Q10, &NLSFIndices[ 1 ], pred_Q8, psNLSF_CB->quantStepSize_Q16, psNLSF_CB->order ); + + /* Weights from codebook vector */ + silk_NLSF_VQ_weights_laroia( W_tmp_QW, pNLSF_Q15, psNLSF_CB->order ); + + /* Apply inverse square-rooted weights and add to output */ + for( i = 0; i < psNLSF_CB->order; i++ ) { + W_tmp_Q9 = silk_SQRT_APPROX( silk_LSHIFT( (opus_int32)W_tmp_QW[ i ], 18 - NLSF_W_Q ) ); + NLSF_Q15_tmp = silk_ADD32( pNLSF_Q15[ i ], silk_DIV32_16( silk_LSHIFT( (opus_int32)res_Q10[ i ], 14 ), W_tmp_Q9 ) ); + pNLSF_Q15[ i ] = (opus_int16)silk_LIMIT( NLSF_Q15_tmp, 0, 32767 ); + } + + /* NLSF stabilization */ + silk_NLSF_stabilize( pNLSF_Q15, psNLSF_CB->deltaMin_Q15, psNLSF_CB->order ); +} diff --git a/code/opus-1.0.2/silk/NLSF_del_dec_quant.c b/code/opus-1.0.2/silk/NLSF_del_dec_quant.c new file mode 100644 index 00000000..78870de5 --- /dev/null +++ b/code/opus-1.0.2/silk/NLSF_del_dec_quant.c @@ -0,0 +1,207 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Delayed-decision quantizer for NLSF residuals */ +opus_int32 silk_NLSF_del_dec_quant( /* O Returns RD value in Q25 */ + opus_int8 indices[], /* O Quantization indices [ order ] */ + const opus_int16 x_Q10[], /* I Input [ order ] */ + const opus_int16 w_Q5[], /* I Weights [ order ] */ + const opus_uint8 pred_coef_Q8[], /* I Backward predictor coefs [ order ] */ + const opus_int16 ec_ix[], /* I Indices to entropy coding tables [ order ] */ + const opus_uint8 ec_rates_Q5[], /* I Rates [] */ + const opus_int quant_step_size_Q16, /* I Quantization step size */ + const opus_int16 inv_quant_step_size_Q6, /* I Inverse quantization step size */ + const opus_int32 mu_Q20, /* I R/D tradeoff */ + const opus_int16 order /* I Number of input values */ +) +{ + opus_int i, j, nStates, ind_tmp, ind_min_max, ind_max_min, in_Q10, res_Q10; + opus_int pred_Q10, diff_Q10, out0_Q10, out1_Q10, rate0_Q5, rate1_Q5; + opus_int32 RD_tmp_Q25, min_Q25, min_max_Q25, max_min_Q25, pred_coef_Q16; + opus_int ind_sort[ NLSF_QUANT_DEL_DEC_STATES ]; + opus_int8 ind[ NLSF_QUANT_DEL_DEC_STATES ][ MAX_LPC_ORDER ]; + opus_int16 prev_out_Q10[ 2 * NLSF_QUANT_DEL_DEC_STATES ]; + opus_int32 RD_Q25[ 2 * NLSF_QUANT_DEL_DEC_STATES ]; + opus_int32 RD_min_Q25[ NLSF_QUANT_DEL_DEC_STATES ]; + opus_int32 RD_max_Q25[ NLSF_QUANT_DEL_DEC_STATES ]; + const opus_uint8 *rates_Q5; + + silk_assert( (NLSF_QUANT_DEL_DEC_STATES & (NLSF_QUANT_DEL_DEC_STATES-1)) == 0 ); /* must be power of two */ + + nStates = 1; + RD_Q25[ 0 ] = 0; + prev_out_Q10[ 0 ] = 0; + for( i = order - 1; ; i-- ) { + rates_Q5 = &ec_rates_Q5[ ec_ix[ i ] ]; + pred_coef_Q16 = silk_LSHIFT( (opus_int32)pred_coef_Q8[ i ], 8 ); + in_Q10 = x_Q10[ i ]; + for( j = 0; j < nStates; j++ ) { + pred_Q10 = silk_SMULWB( pred_coef_Q16, prev_out_Q10[ j ] ); + res_Q10 = silk_SUB16( in_Q10, pred_Q10 ); + ind_tmp = silk_SMULWB( (opus_int32)inv_quant_step_size_Q6, res_Q10 ); + ind_tmp = silk_LIMIT( ind_tmp, -NLSF_QUANT_MAX_AMPLITUDE_EXT, NLSF_QUANT_MAX_AMPLITUDE_EXT-1 ); + ind[ j ][ i ] = (opus_int8)ind_tmp; + + /* compute outputs for ind_tmp and ind_tmp + 1 */ + out0_Q10 = silk_LSHIFT( ind_tmp, 10 ); + out1_Q10 = silk_ADD16( out0_Q10, 1024 ); + if( ind_tmp > 0 ) { + out0_Q10 = silk_SUB16( out0_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + out1_Q10 = silk_SUB16( out1_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + } else if( ind_tmp == 0 ) { + out1_Q10 = silk_SUB16( out1_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + } else if( ind_tmp == -1 ) { + out0_Q10 = silk_ADD16( out0_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + } else { + out0_Q10 = silk_ADD16( out0_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + out1_Q10 = silk_ADD16( out1_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + } + out0_Q10 = silk_SMULWB( (opus_int32)out0_Q10, quant_step_size_Q16 ); + out1_Q10 = silk_SMULWB( (opus_int32)out1_Q10, quant_step_size_Q16 ); + out0_Q10 = silk_ADD16( out0_Q10, pred_Q10 ); + out1_Q10 = silk_ADD16( out1_Q10, pred_Q10 ); + prev_out_Q10[ j ] = out0_Q10; + prev_out_Q10[ j + nStates ] = out1_Q10; + + /* compute RD for ind_tmp and ind_tmp + 1 */ + if( ind_tmp + 1 >= NLSF_QUANT_MAX_AMPLITUDE ) { + if( ind_tmp + 1 == NLSF_QUANT_MAX_AMPLITUDE ) { + rate0_Q5 = rates_Q5[ ind_tmp + NLSF_QUANT_MAX_AMPLITUDE ]; + rate1_Q5 = 280; + } else { + rate0_Q5 = silk_SMLABB( 280 - 43 * NLSF_QUANT_MAX_AMPLITUDE, 43, ind_tmp ); + rate1_Q5 = silk_ADD16( rate0_Q5, 43 ); + } + } else if( ind_tmp <= -NLSF_QUANT_MAX_AMPLITUDE ) { + if( ind_tmp == -NLSF_QUANT_MAX_AMPLITUDE ) { + rate0_Q5 = 280; + rate1_Q5 = rates_Q5[ ind_tmp + 1 + NLSF_QUANT_MAX_AMPLITUDE ]; + } else { + rate0_Q5 = silk_SMLABB( 280 - 43 * NLSF_QUANT_MAX_AMPLITUDE, -43, ind_tmp ); + rate1_Q5 = silk_SUB16( rate0_Q5, 43 ); + } + } else { + rate0_Q5 = rates_Q5[ ind_tmp + NLSF_QUANT_MAX_AMPLITUDE ]; + rate1_Q5 = rates_Q5[ ind_tmp + 1 + NLSF_QUANT_MAX_AMPLITUDE ]; + } + RD_tmp_Q25 = RD_Q25[ j ]; + diff_Q10 = silk_SUB16( in_Q10, out0_Q10 ); + RD_Q25[ j ] = silk_SMLABB( silk_MLA( RD_tmp_Q25, silk_SMULBB( diff_Q10, diff_Q10 ), w_Q5[ i ] ), mu_Q20, rate0_Q5 ); + diff_Q10 = silk_SUB16( in_Q10, out1_Q10 ); + RD_Q25[ j + nStates ] = silk_SMLABB( silk_MLA( RD_tmp_Q25, silk_SMULBB( diff_Q10, diff_Q10 ), w_Q5[ i ] ), mu_Q20, rate1_Q5 ); + } + + if( nStates < NLSF_QUANT_DEL_DEC_STATES ) { + /* double number of states and copy */ + for( j = 0; j < nStates; j++ ) { + ind[ j + nStates ][ i ] = ind[ j ][ i ] + 1; + } + nStates = silk_LSHIFT( nStates, 1 ); + for( j = nStates; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) { + ind[ j ][ i ] = ind[ j - nStates ][ i ]; + } + } else if( i > 0 ) { + /* sort lower and upper half of RD_Q25, pairwise */ + for( j = 0; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) { + if( RD_Q25[ j ] > RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ] ) { + RD_max_Q25[ j ] = RD_Q25[ j ]; + RD_min_Q25[ j ] = RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ]; + RD_Q25[ j ] = RD_min_Q25[ j ]; + RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ] = RD_max_Q25[ j ]; + /* swap prev_out values */ + out0_Q10 = prev_out_Q10[ j ]; + prev_out_Q10[ j ] = prev_out_Q10[ j + NLSF_QUANT_DEL_DEC_STATES ]; + prev_out_Q10[ j + NLSF_QUANT_DEL_DEC_STATES ] = out0_Q10; + ind_sort[ j ] = j + NLSF_QUANT_DEL_DEC_STATES; + } else { + RD_min_Q25[ j ] = RD_Q25[ j ]; + RD_max_Q25[ j ] = RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ]; + ind_sort[ j ] = j; + } + } + /* compare the highest RD values of the winning half with the lowest one in the losing half, and copy if necessary */ + /* afterwards ind_sort[] will contain the indices of the NLSF_QUANT_DEL_DEC_STATES winning RD values */ + while( 1 ) { + min_max_Q25 = silk_int32_MAX; + max_min_Q25 = 0; + ind_min_max = 0; + ind_max_min = 0; + for( j = 0; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) { + if( min_max_Q25 > RD_max_Q25[ j ] ) { + min_max_Q25 = RD_max_Q25[ j ]; + ind_min_max = j; + } + if( max_min_Q25 < RD_min_Q25[ j ] ) { + max_min_Q25 = RD_min_Q25[ j ]; + ind_max_min = j; + } + } + if( min_max_Q25 >= max_min_Q25 ) { + break; + } + /* copy ind_min_max to ind_max_min */ + ind_sort[ ind_max_min ] = ind_sort[ ind_min_max ] ^ NLSF_QUANT_DEL_DEC_STATES; + RD_Q25[ ind_max_min ] = RD_Q25[ ind_min_max + NLSF_QUANT_DEL_DEC_STATES ]; + prev_out_Q10[ ind_max_min ] = prev_out_Q10[ ind_min_max + NLSF_QUANT_DEL_DEC_STATES ]; + RD_min_Q25[ ind_max_min ] = 0; + RD_max_Q25[ ind_min_max ] = silk_int32_MAX; + silk_memcpy( ind[ ind_max_min ], ind[ ind_min_max ], MAX_LPC_ORDER * sizeof( opus_int8 ) ); + } + /* increment index if it comes from the upper half */ + for( j = 0; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) { + ind[ j ][ i ] += silk_RSHIFT( ind_sort[ j ], NLSF_QUANT_DEL_DEC_STATES_LOG2 ); + } + } else { /* i == 0 */ + break; + } + } + + /* last sample: find winner, copy indices and return RD value */ + ind_tmp = 0; + min_Q25 = silk_int32_MAX; + for( j = 0; j < 2 * NLSF_QUANT_DEL_DEC_STATES; j++ ) { + if( min_Q25 > RD_Q25[ j ] ) { + min_Q25 = RD_Q25[ j ]; + ind_tmp = j; + } + } + for( j = 0; j < order; j++ ) { + indices[ j ] = ind[ ind_tmp & ( NLSF_QUANT_DEL_DEC_STATES - 1 ) ][ j ]; + silk_assert( indices[ j ] >= -NLSF_QUANT_MAX_AMPLITUDE_EXT ); + silk_assert( indices[ j ] <= NLSF_QUANT_MAX_AMPLITUDE_EXT ); + } + indices[ 0 ] += silk_RSHIFT( ind_tmp, NLSF_QUANT_DEL_DEC_STATES_LOG2 ); + silk_assert( indices[ 0 ] <= NLSF_QUANT_MAX_AMPLITUDE_EXT ); + silk_assert( min_Q25 >= 0 ); + return min_Q25; +} diff --git a/code/opus-1.0.2/silk/NLSF_encode.c b/code/opus-1.0.2/silk/NLSF_encode.c new file mode 100644 index 00000000..52a263d9 --- /dev/null +++ b/code/opus-1.0.2/silk/NLSF_encode.c @@ -0,0 +1,128 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/***********************/ +/* NLSF vector encoder */ +/***********************/ +opus_int32 silk_NLSF_encode( /* O Returns RD value in Q25 */ + opus_int8 *NLSFIndices, /* I Codebook path vector [ LPC_ORDER + 1 ] */ + opus_int16 *pNLSF_Q15, /* I/O Quantized NLSF vector [ LPC_ORDER ] */ + const silk_NLSF_CB_struct *psNLSF_CB, /* I Codebook object */ + const opus_int16 *pW_QW, /* I NLSF weight vector [ LPC_ORDER ] */ + const opus_int NLSF_mu_Q20, /* I Rate weight for the RD optimization */ + const opus_int nSurvivors, /* I Max survivors after first stage */ + const opus_int signalType /* I Signal type: 0/1/2 */ +) +{ + opus_int i, s, ind1, bestIndex, prob_Q8, bits_q7; + opus_int32 W_tmp_Q9; + opus_int32 err_Q26[ NLSF_VQ_MAX_VECTORS ]; + opus_int32 RD_Q25[ NLSF_VQ_MAX_SURVIVORS ]; + opus_int tempIndices1[ NLSF_VQ_MAX_SURVIVORS ]; + opus_int8 tempIndices2[ NLSF_VQ_MAX_SURVIVORS * MAX_LPC_ORDER ]; + opus_int16 res_Q15[ MAX_LPC_ORDER ]; + opus_int16 res_Q10[ MAX_LPC_ORDER ]; + opus_int16 NLSF_tmp_Q15[ MAX_LPC_ORDER ]; + opus_int16 W_tmp_QW[ MAX_LPC_ORDER ]; + opus_int16 W_adj_Q5[ MAX_LPC_ORDER ]; + opus_uint8 pred_Q8[ MAX_LPC_ORDER ]; + opus_int16 ec_ix[ MAX_LPC_ORDER ]; + const opus_uint8 *pCB_element, *iCDF_ptr; + + silk_assert( nSurvivors <= NLSF_VQ_MAX_SURVIVORS ); + silk_assert( signalType >= 0 && signalType <= 2 ); + silk_assert( NLSF_mu_Q20 <= 32767 && NLSF_mu_Q20 >= 0 ); + + /* NLSF stabilization */ + silk_NLSF_stabilize( pNLSF_Q15, psNLSF_CB->deltaMin_Q15, psNLSF_CB->order ); + + /* First stage: VQ */ + silk_NLSF_VQ( err_Q26, pNLSF_Q15, psNLSF_CB->CB1_NLSF_Q8, psNLSF_CB->nVectors, psNLSF_CB->order ); + + /* Sort the quantization errors */ + silk_insertion_sort_increasing( err_Q26, tempIndices1, psNLSF_CB->nVectors, nSurvivors ); + + /* Loop over survivors */ + for( s = 0; s < nSurvivors; s++ ) { + ind1 = tempIndices1[ s ]; + + /* Residual after first stage */ + pCB_element = &psNLSF_CB->CB1_NLSF_Q8[ ind1 * psNLSF_CB->order ]; + for( i = 0; i < psNLSF_CB->order; i++ ) { + NLSF_tmp_Q15[ i ] = silk_LSHIFT16( (opus_int16)pCB_element[ i ], 7 ); + res_Q15[ i ] = pNLSF_Q15[ i ] - NLSF_tmp_Q15[ i ]; + } + + /* Weights from codebook vector */ + silk_NLSF_VQ_weights_laroia( W_tmp_QW, NLSF_tmp_Q15, psNLSF_CB->order ); + + /* Apply square-rooted weights */ + for( i = 0; i < psNLSF_CB->order; i++ ) { + W_tmp_Q9 = silk_SQRT_APPROX( silk_LSHIFT( (opus_int32)W_tmp_QW[ i ], 18 - NLSF_W_Q ) ); + res_Q10[ i ] = (opus_int16)silk_RSHIFT( silk_SMULBB( res_Q15[ i ], W_tmp_Q9 ), 14 ); + } + + /* Modify input weights accordingly */ + for( i = 0; i < psNLSF_CB->order; i++ ) { + W_adj_Q5[ i ] = silk_DIV32_16( silk_LSHIFT( (opus_int32)pW_QW[ i ], 5 ), W_tmp_QW[ i ] ); + } + + /* Unpack entropy table indices and predictor for current CB1 index */ + silk_NLSF_unpack( ec_ix, pred_Q8, psNLSF_CB, ind1 ); + + /* Trellis quantizer */ + RD_Q25[ s ] = silk_NLSF_del_dec_quant( &tempIndices2[ s * MAX_LPC_ORDER ], res_Q10, W_adj_Q5, pred_Q8, ec_ix, + psNLSF_CB->ec_Rates_Q5, psNLSF_CB->quantStepSize_Q16, psNLSF_CB->invQuantStepSize_Q6, NLSF_mu_Q20, psNLSF_CB->order ); + + /* Add rate for first stage */ + iCDF_ptr = &psNLSF_CB->CB1_iCDF[ ( signalType >> 1 ) * psNLSF_CB->nVectors ]; + if( ind1 == 0 ) { + prob_Q8 = 256 - iCDF_ptr[ ind1 ]; + } else { + prob_Q8 = iCDF_ptr[ ind1 - 1 ] - iCDF_ptr[ ind1 ]; + } + bits_q7 = ( 8 << 7 ) - silk_lin2log( prob_Q8 ); + RD_Q25[ s ] = silk_SMLABB( RD_Q25[ s ], bits_q7, silk_RSHIFT( NLSF_mu_Q20, 2 ) ); + } + + /* Find the lowest rate-distortion error */ + silk_insertion_sort_increasing( RD_Q25, &bestIndex, nSurvivors, 1 ); + + NLSFIndices[ 0 ] = (opus_int8)tempIndices1[ bestIndex ]; + silk_memcpy( &NLSFIndices[ 1 ], &tempIndices2[ bestIndex * MAX_LPC_ORDER ], psNLSF_CB->order * sizeof( opus_int8 ) ); + + /* Decode */ + silk_NLSF_decode( pNLSF_Q15, NLSFIndices, psNLSF_CB ); + + return RD_Q25[ 0 ]; +} diff --git a/code/opus-1.0.2/silk/NLSF_stabilize.c b/code/opus-1.0.2/silk/NLSF_stabilize.c new file mode 100644 index 00000000..7498b54a --- /dev/null +++ b/code/opus-1.0.2/silk/NLSF_stabilize.c @@ -0,0 +1,142 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* NLSF stabilizer: */ +/* */ +/* - Moves NLSFs further 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 "SigProc_FIX.h" + +/* Constant Definitions */ +#define MAX_LOOPS 20 + +/* NLSF stabilizer, for a single input data vector */ +void silk_NLSF_stabilize( + opus_int16 *NLSF_Q15, /* I/O Unstable/stabilized normalized LSF vector in Q15 [L] */ + const opus_int16 *NDeltaMin_Q15, /* I Min distance vector, NDeltaMin_Q15[L] must be >= 1 [L+1] */ + const opus_int L /* I Number of NLSF parameters in the input vector */ +) +{ + opus_int i, I=0, k, loops; + opus_int16 center_freq_Q15; + opus_int32 diff_Q15, min_diff_Q15, min_center_Q15, max_center_Q15; + + /* This is necessary to ensure an output within range of a opus_int16 */ + silk_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 += silk_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 -= silk_RSHIFT( NDeltaMin_Q15[I], 1 ); + + /* Move apart, sorted by value, keeping the same center frequency */ + center_freq_Q15 = (opus_int16)silk_LIMIT_32( silk_RSHIFT_ROUND( (opus_int32)NLSF_Q15[I-1] + (opus_int32)NLSF_Q15[I], 1 ), + min_center_Q15, max_center_Q15 ); + NLSF_Q15[I-1] = center_freq_Q15 - silk_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 */ + silk_insertion_sort_increasing_all_values_int16( &NLSF_Q15[0], L ); + + /* First NLSF should be no less than NDeltaMin[0] */ + NLSF_Q15[0] = silk_max_int( NLSF_Q15[0], NDeltaMin_Q15[0] ); + + /* Keep delta_min distance between the NLSFs */ + for( i = 1; i < L; i++ ) + NLSF_Q15[i] = silk_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] = silk_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] = silk_min_int( NLSF_Q15[i], NLSF_Q15[i+1] - NDeltaMin_Q15[i+1] ); + } +} diff --git a/code/opus-1.0.2/silk/NLSF_unpack.c b/code/opus-1.0.2/silk/NLSF_unpack.c new file mode 100644 index 00000000..47f6cfe8 --- /dev/null +++ b/code/opus-1.0.2/silk/NLSF_unpack.c @@ -0,0 +1,55 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Unpack predictor values and indices for entropy coding tables */ +void silk_NLSF_unpack( + opus_int16 ec_ix[], /* O Indices to entropy tables [ LPC_ORDER ] */ + opus_uint8 pred_Q8[], /* O LSF predictor [ LPC_ORDER ] */ + const silk_NLSF_CB_struct *psNLSF_CB, /* I Codebook object */ + const opus_int CB1_index /* I Index of vector in first LSF codebook */ +) +{ + opus_int i; + opus_uint8 entry; + const opus_uint8 *ec_sel_ptr; + + ec_sel_ptr = &psNLSF_CB->ec_sel[ CB1_index * psNLSF_CB->order / 2 ]; + for( i = 0; i < psNLSF_CB->order; i += 2 ) { + entry = *ec_sel_ptr++; + ec_ix [ i ] = silk_SMULBB( silk_RSHIFT( entry, 1 ) & 7, 2 * NLSF_QUANT_MAX_AMPLITUDE + 1 ); + pred_Q8[ i ] = psNLSF_CB->pred_Q8[ i + ( entry & 1 ) * ( psNLSF_CB->order - 1 ) ]; + ec_ix [ i + 1 ] = silk_SMULBB( silk_RSHIFT( entry, 5 ) & 7, 2 * NLSF_QUANT_MAX_AMPLITUDE + 1 ); + pred_Q8[ i + 1 ] = psNLSF_CB->pred_Q8[ i + ( silk_RSHIFT( entry, 4 ) & 1 ) * ( psNLSF_CB->order - 1 ) + 1 ]; + } +} + diff --git a/code/opus-1.0.2/silk/NSQ.c b/code/opus-1.0.2/silk/NSQ.c new file mode 100644 index 00000000..b49cdf58 --- /dev/null +++ b/code/opus-1.0.2/silk/NSQ.c @@ -0,0 +1,439 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +static inline void silk_nsq_scale_states( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + const opus_int32 x_Q3[], /* I input in Q3 */ + opus_int32 x_sc_Q10[], /* O input scaled with 1/Gain */ + const opus_int16 sLTP[], /* I re-whitened LTP state in Q0 */ + opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */ + opus_int subfr, /* I subframe number */ + const opus_int LTP_scale_Q14, /* I */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */ + const opus_int signal_type /* I Signal type */ +); + +static inline void silk_noise_shape_quantizer( + silk_nsq_state *NSQ, /* I/O NSQ state */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_sc_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP state */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping AR coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int Lambda_Q10, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int shapingLPCOrder, /* I Noise shaping AR filter order */ + opus_int predictLPCOrder /* I Prediction filter order */ +); + +void silk_NSQ( + const silk_encoder_state *psEncC, /* I/O Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int32 x_Q3[], /* I Prefiltered input signal */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +) +{ + opus_int k, lag, start_idx, LSF_interpolation_flag; + const opus_int16 *A_Q12, *B_Q14, *AR_shp_Q13; + opus_int16 *pxq; + opus_int32 sLTP_Q15[ 2 * MAX_FRAME_LENGTH ]; + opus_int16 sLTP[ 2 * MAX_FRAME_LENGTH ]; + opus_int32 HarmShapeFIRPacked_Q14; + opus_int offset_Q10; + opus_int32 x_sc_Q10[ MAX_SUB_FRAME_LENGTH ]; + + NSQ->rand_seed = psIndices->Seed; + + /* Set unvoiced lag to the previous one, overwrite later for voiced */ + lag = NSQ->lagPrev; + + silk_assert( NSQ->prev_gain_Q16 != 0 ); + + offset_Q10 = silk_Quantization_Offsets_Q10[ psIndices->signalType >> 1 ][ psIndices->quantOffsetType ]; + + if( psIndices->NLSFInterpCoef_Q2 == 4 ) { + LSF_interpolation_flag = 0; + } else { + LSF_interpolation_flag = 1; + } + + /* Set up pointers to start of sub frame */ + NSQ->sLTP_shp_buf_idx = psEncC->ltp_mem_length; + NSQ->sLTP_buf_idx = psEncC->ltp_mem_length; + pxq = &NSQ->xq[ psEncC->ltp_mem_length ]; + for( k = 0; k < psEncC->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 */ + silk_assert( HarmShapeGain_Q14[ k ] >= 0 ); + HarmShapeFIRPacked_Q14 = silk_RSHIFT( HarmShapeGain_Q14[ k ], 2 ); + HarmShapeFIRPacked_Q14 |= silk_LSHIFT( (opus_int32)silk_RSHIFT( HarmShapeGain_Q14[ k ], 1 ), 16 ); + + NSQ->rewhite_flag = 0; + if( psIndices->signalType == TYPE_VOICED ) { + /* Voiced */ + lag = pitchL[ k ]; + + /* Re-whitening */ + if( ( k & ( 3 - silk_LSHIFT( LSF_interpolation_flag, 1 ) ) ) == 0 ) { + /* Rewhiten with new A coefs */ + start_idx = psEncC->ltp_mem_length - lag - psEncC->predictLPCOrder - LTP_ORDER / 2; + silk_assert( start_idx > 0 ); + + silk_LPC_analysis_filter( &sLTP[ start_idx ], &NSQ->xq[ start_idx + k * psEncC->subfr_length ], + A_Q12, psEncC->ltp_mem_length - start_idx, psEncC->predictLPCOrder ); + + NSQ->rewhite_flag = 1; + NSQ->sLTP_buf_idx = psEncC->ltp_mem_length; + } + } + + silk_nsq_scale_states( psEncC, NSQ, x_Q3, x_sc_Q10, sLTP, sLTP_Q15, k, LTP_scale_Q14, Gains_Q16, pitchL, psIndices->signalType ); + + silk_noise_shape_quantizer( NSQ, psIndices->signalType, x_sc_Q10, pulses, pxq, sLTP_Q15, 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_Q3 += psEncC->subfr_length; + pulses += psEncC->subfr_length; + pxq += psEncC->subfr_length; + } + + /* Update lagPrev for next frame */ + NSQ->lagPrev = pitchL[ psEncC->nb_subfr - 1 ]; + + /* Save quantized speech and noise shaping signals */ + /* DEBUG_STORE_DATA( enc.pcm, &NSQ->xq[ psEncC->ltp_mem_length ], psEncC->frame_length * sizeof( opus_int16 ) ) */ + silk_memmove( NSQ->xq, &NSQ->xq[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int16 ) ); + silk_memmove( NSQ->sLTP_shp_Q14, &NSQ->sLTP_shp_Q14[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int32 ) ); +} + +/***********************************/ +/* silk_noise_shape_quantizer */ +/***********************************/ +static inline void silk_noise_shape_quantizer( + silk_nsq_state *NSQ, /* I/O NSQ state */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_sc_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP state */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping AR coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int Lambda_Q10, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int shapingLPCOrder, /* I Noise shaping AR filter order */ + opus_int predictLPCOrder /* I Prediction filter order */ +) +{ + opus_int i, j; + opus_int32 LTP_pred_Q13, LPC_pred_Q10, n_AR_Q12, n_LTP_Q13; + opus_int32 n_LF_Q12, r_Q10, rr_Q10, q1_Q0, q1_Q10, q2_Q10, rd1_Q20, rd2_Q20; + opus_int32 exc_Q14, LPC_exc_Q14, xq_Q14, Gain_Q10; + opus_int32 tmp1, tmp2, sLF_AR_shp_Q14; + opus_int32 *psLPC_Q14, *shp_lag_ptr, *pred_lag_ptr; + + shp_lag_ptr = &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ]; + pred_lag_ptr = &sLTP_Q15[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + Gain_Q10 = silk_RSHIFT( Gain_Q16, 6 ); + + /* Set up short term AR state */ + psLPC_Q14 = &NSQ->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 1 ]; + + for( i = 0; i < length; i++ ) { + /* Generate dither */ + NSQ->rand_seed = silk_RAND( NSQ->rand_seed ); + + /* Short-term prediction */ + silk_assert( predictLPCOrder == 10 || predictLPCOrder == 16 ); + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LPC_pred_Q10 = silk_RSHIFT( predictLPCOrder, 1 ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ 0 ], a_Q12[ 0 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -1 ], a_Q12[ 1 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -2 ], a_Q12[ 2 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -3 ], a_Q12[ 3 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -4 ], a_Q12[ 4 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -5 ], a_Q12[ 5 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -6 ], a_Q12[ 6 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -7 ], a_Q12[ 7 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -8 ], a_Q12[ 8 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -9 ], a_Q12[ 9 ] ); + if( predictLPCOrder == 16 ) { + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -10 ], a_Q12[ 10 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -11 ], a_Q12[ 11 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -12 ], a_Q12[ 12 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -13 ], a_Q12[ 13 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -14 ], a_Q12[ 14 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -15 ], a_Q12[ 15 ] ); + } + + /* Long-term prediction */ + if( signalType == TYPE_VOICED ) { + /* Unrolled loop */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LTP_pred_Q13 = 2; + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ 0 ], b_Q14[ 0 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -1 ], b_Q14[ 1 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -2 ], b_Q14[ 2 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -3 ], b_Q14[ 3 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -4 ], b_Q14[ 4 ] ); + pred_lag_ptr++; + } else { + LTP_pred_Q13 = 0; + } + + /* Noise shape feedback */ + silk_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_Q12 = silk_RSHIFT( shapingLPCOrder, 1 ); + n_AR_Q12 = silk_SMLAWB( n_AR_Q12, 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_Q12 = silk_SMLAWB( n_AR_Q12, tmp1, AR_shp_Q13[ j - 1 ] ); + tmp1 = NSQ->sAR2_Q14[ j + 0 ]; + NSQ->sAR2_Q14[ j + 0 ] = tmp2; + n_AR_Q12 = silk_SMLAWB( n_AR_Q12, tmp2, AR_shp_Q13[ j ] ); + } + NSQ->sAR2_Q14[ shapingLPCOrder - 1 ] = tmp1; + n_AR_Q12 = silk_SMLAWB( n_AR_Q12, tmp1, AR_shp_Q13[ shapingLPCOrder - 1 ] ); + + n_AR_Q12 = silk_LSHIFT32( n_AR_Q12, 1 ); /* Q11 -> Q12 */ + n_AR_Q12 = silk_SMLAWB( n_AR_Q12, NSQ->sLF_AR_shp_Q14, Tilt_Q14 ); + + n_LF_Q12 = silk_SMULWB( NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - 1 ], LF_shp_Q14 ); + n_LF_Q12 = silk_SMLAWT( n_LF_Q12, NSQ->sLF_AR_shp_Q14, LF_shp_Q14 ); + + silk_assert( lag > 0 || signalType != TYPE_VOICED ); + + /* Combine prediction and noise shaping signals */ + tmp1 = silk_SUB32( silk_LSHIFT32( LPC_pred_Q10, 2 ), n_AR_Q12 ); /* Q12 */ + tmp1 = silk_SUB32( tmp1, n_LF_Q12 ); /* Q12 */ + if( lag > 0 ) { + /* Symmetric, packed FIR coefficients */ + n_LTP_Q13 = silk_SMULWB( silk_ADD32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 ); + n_LTP_Q13 = silk_SMLAWT( n_LTP_Q13, shp_lag_ptr[ -1 ], HarmShapeFIRPacked_Q14 ); + n_LTP_Q13 = silk_LSHIFT( n_LTP_Q13, 1 ); + shp_lag_ptr++; + + tmp2 = silk_SUB32( LTP_pred_Q13, n_LTP_Q13 ); /* Q13 */ + tmp1 = silk_ADD_LSHIFT32( tmp2, tmp1, 1 ); /* Q13 */ + tmp1 = silk_RSHIFT_ROUND( tmp1, 3 ); /* Q10 */ + } else { + tmp1 = silk_RSHIFT_ROUND( tmp1, 2 ); /* Q10 */ + } + + r_Q10 = silk_SUB32( x_sc_Q10[ i ], tmp1 ); /* residual error Q10 */ + + /* Flip sign depending on dither */ + if ( NSQ->rand_seed < 0 ) { + r_Q10 = -r_Q10; + } + r_Q10 = silk_LIMIT_32( r_Q10, -(31 << 10), 30 << 10 ); + + /* Find two quantization level candidates and measure their rate-distortion */ + q1_Q10 = silk_SUB32( r_Q10, offset_Q10 ); + q1_Q0 = silk_RSHIFT( q1_Q10, 10 ); + if( q1_Q0 > 0 ) { + q1_Q10 = silk_SUB32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 ); + q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 ); + q2_Q10 = silk_ADD32( q1_Q10, 1024 ); + rd1_Q20 = silk_SMULBB( q1_Q10, Lambda_Q10 ); + rd2_Q20 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else if( q1_Q0 == 0 ) { + q1_Q10 = offset_Q10; + q2_Q10 = silk_ADD32( q1_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 ); + rd1_Q20 = silk_SMULBB( q1_Q10, Lambda_Q10 ); + rd2_Q20 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else if( q1_Q0 == -1 ) { + q2_Q10 = offset_Q10; + q1_Q10 = silk_SUB32( q2_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 ); + rd1_Q20 = silk_SMULBB( -q1_Q10, Lambda_Q10 ); + rd2_Q20 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else { /* Q1_Q0 < -1 */ + q1_Q10 = silk_ADD32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 ); + q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 ); + q2_Q10 = silk_ADD32( q1_Q10, 1024 ); + rd1_Q20 = silk_SMULBB( -q1_Q10, Lambda_Q10 ); + rd2_Q20 = silk_SMULBB( -q2_Q10, Lambda_Q10 ); + } + rr_Q10 = silk_SUB32( r_Q10, q1_Q10 ); + rd1_Q20 = silk_SMLABB( rd1_Q20, rr_Q10, rr_Q10 ); + rr_Q10 = silk_SUB32( r_Q10, q2_Q10 ); + rd2_Q20 = silk_SMLABB( rd2_Q20, rr_Q10, rr_Q10 ); + + if( rd2_Q20 < rd1_Q20 ) { + q1_Q10 = q2_Q10; + } + + pulses[ i ] = (opus_int8)silk_RSHIFT_ROUND( q1_Q10, 10 ); + + /* Excitation */ + exc_Q14 = silk_LSHIFT( q1_Q10, 4 ); + if ( NSQ->rand_seed < 0 ) { + exc_Q14 = -exc_Q14; + } + + /* Add predictions */ + LPC_exc_Q14 = silk_ADD_LSHIFT32( exc_Q14, LTP_pred_Q13, 1 ); + xq_Q14 = silk_ADD_LSHIFT32( LPC_exc_Q14, LPC_pred_Q10, 4 ); + + /* Scale XQ back to normal level before saving */ + xq[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( xq_Q14, Gain_Q10 ), 8 ) ); + + /* Update states */ + psLPC_Q14++; + *psLPC_Q14 = xq_Q14; + sLF_AR_shp_Q14 = silk_SUB_LSHIFT32( xq_Q14, n_AR_Q12, 2 ); + NSQ->sLF_AR_shp_Q14 = sLF_AR_shp_Q14; + + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx ] = silk_SUB_LSHIFT32( sLF_AR_shp_Q14, n_LF_Q12, 2 ); + sLTP_Q15[ NSQ->sLTP_buf_idx ] = silk_LSHIFT( LPC_exc_Q14, 1 ); + NSQ->sLTP_shp_buf_idx++; + NSQ->sLTP_buf_idx++; + + /* Make dither dependent on quantized signal */ + NSQ->rand_seed = silk_ADD32_ovflw( NSQ->rand_seed, pulses[ i ] ); + } + + /* Update LPC synth buffer */ + silk_memcpy( NSQ->sLPC_Q14, &NSQ->sLPC_Q14[ length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) ); +} + +static inline void silk_nsq_scale_states( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + const opus_int32 x_Q3[], /* I input in Q3 */ + opus_int32 x_sc_Q10[], /* O input scaled with 1/Gain */ + const opus_int16 sLTP[], /* I re-whitened LTP state in Q0 */ + opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */ + opus_int subfr, /* I subframe number */ + const opus_int LTP_scale_Q14, /* I */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */ + const opus_int signal_type /* I Signal type */ +) +{ + opus_int i, lag; + opus_int32 gain_adj_Q16, inv_gain_Q31, inv_gain_Q23; + + lag = pitchL[ subfr ]; + inv_gain_Q31 = silk_INVERSE32_varQ( silk_max( Gains_Q16[ subfr ], 1 ), 47 ); + silk_assert( inv_gain_Q31 != 0 ); + + /* Calculate gain adjustment factor */ + if( Gains_Q16[ subfr ] != NSQ->prev_gain_Q16 ) { + gain_adj_Q16 = silk_DIV32_varQ( NSQ->prev_gain_Q16, Gains_Q16[ subfr ], 16 ); + } else { + gain_adj_Q16 = (opus_int32)1 << 16; + } + + /* Scale input */ + inv_gain_Q23 = silk_RSHIFT_ROUND( inv_gain_Q31, 8 ); + for( i = 0; i < psEncC->subfr_length; i++ ) { + x_sc_Q10[ i ] = silk_SMULWW( x_Q3[ i ], inv_gain_Q23 ); + } + + /* Save inverse gain */ + NSQ->prev_gain_Q16 = Gains_Q16[ subfr ]; + + /* After rewhitening the LTP state is un-scaled, so scale with inv_gain_Q16 */ + if( NSQ->rewhite_flag ) { + if( subfr == 0 ) { + /* Do LTP downscaling */ + inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, LTP_scale_Q14 ), 2 ); + } + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) { + silk_assert( i < MAX_FRAME_LENGTH ); + sLTP_Q15[ i ] = silk_SMULWB( inv_gain_Q31, sLTP[ i ] ); + } + } + + /* Adjust for changing gain */ + if( gain_adj_Q16 != (opus_int32)1 << 16 ) { + /* Scale long-term shaping state */ + for( i = NSQ->sLTP_shp_buf_idx - psEncC->ltp_mem_length; i < NSQ->sLTP_shp_buf_idx; i++ ) { + NSQ->sLTP_shp_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLTP_shp_Q14[ i ] ); + } + + /* Scale long-term prediction state */ + if( signal_type == TYPE_VOICED && NSQ->rewhite_flag == 0 ) { + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) { + sLTP_Q15[ i ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ i ] ); + } + } + + NSQ->sLF_AR_shp_Q14 = silk_SMULWW( gain_adj_Q16, NSQ->sLF_AR_shp_Q14 ); + + /* Scale short-term prediction and shaping states */ + for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) { + NSQ->sLPC_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLPC_Q14[ i ] ); + } + for( i = 0; i < MAX_SHAPE_LPC_ORDER; i++ ) { + NSQ->sAR2_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sAR2_Q14[ i ] ); + } + } +} diff --git a/code/opus-1.0.2/silk/NSQ_del_dec.c b/code/opus-1.0.2/silk/NSQ_del_dec.c new file mode 100644 index 00000000..b877fa96 --- /dev/null +++ b/code/opus-1.0.2/silk/NSQ_del_dec.c @@ -0,0 +1,705 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +typedef struct { + opus_int32 sLPC_Q14[ MAX_SUB_FRAME_LENGTH + NSQ_LPC_BUF_LENGTH ]; + opus_int32 RandState[ DECISION_DELAY ]; + opus_int32 Q_Q10[ DECISION_DELAY ]; + opus_int32 Xq_Q14[ DECISION_DELAY ]; + opus_int32 Pred_Q15[ DECISION_DELAY ]; + opus_int32 Shape_Q14[ DECISION_DELAY ]; + opus_int32 sAR2_Q14[ MAX_SHAPE_LPC_ORDER ]; + opus_int32 LF_AR_Q14; + opus_int32 Seed; + opus_int32 SeedInit; + opus_int32 RD_Q10; +} NSQ_del_dec_struct; + +typedef struct { + opus_int32 Q_Q10; + opus_int32 RD_Q10; + opus_int32 xq_Q14; + opus_int32 LF_AR_Q14; + opus_int32 sLTP_shp_Q14; + opus_int32 LPC_exc_Q14; +} NSQ_sample_struct; + +static inline void silk_nsq_del_dec_scale_states( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + const opus_int32 x_Q3[], /* I Input in Q3 */ + opus_int32 x_sc_Q10[], /* O Input scaled with 1/Gain in Q10 */ + const opus_int16 sLTP[], /* I Re-whitened LTP state in Q0 */ + opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */ + opus_int subfr, /* I Subframe number */ + opus_int nStatesDelayedDecision, /* I Number of del dec states */ + const opus_int LTP_scale_Q14, /* I LTP state scaling */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */ + const opus_int signal_type, /* I Signal type */ + const opus_int decisionDelay /* I Decision delay */ +); + +/******************************************/ +/* Noise shape quantizer for one subframe */ +/******************************************/ +static inline void silk_noise_shape_quantizer_del_dec( + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP filter state */ + opus_int32 delayedGain_Q10[], /* I/O Gain delay buffer */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int Lambda_Q10, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int subfr, /* I Subframe number */ + opus_int shapingLPCOrder, /* I Shaping LPC filter order */ + opus_int predictLPCOrder, /* I Prediction filter order */ + opus_int warping_Q16, /* I */ + opus_int nStatesDelayedDecision, /* I Number of states in decision tree */ + opus_int *smpl_buf_idx, /* I Index to newest samples in buffers */ + opus_int decisionDelay /* I */ +); + +void silk_NSQ_del_dec( + const silk_encoder_state *psEncC, /* I/O Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int32 x_Q3[], /* I Prefiltered input signal */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +) +{ + opus_int i, k, lag, start_idx, LSF_interpolation_flag, Winner_ind, subfr; + opus_int last_smple_idx, smpl_buf_idx, decisionDelay; + const opus_int16 *A_Q12, *B_Q14, *AR_shp_Q13; + opus_int16 *pxq; + opus_int32 sLTP_Q15[ 2 * MAX_FRAME_LENGTH ]; + opus_int16 sLTP[ 2 * MAX_FRAME_LENGTH ]; + opus_int32 HarmShapeFIRPacked_Q14; + opus_int offset_Q10; + opus_int32 RDmin_Q10, Gain_Q10; + opus_int32 x_sc_Q10[ MAX_SUB_FRAME_LENGTH ]; + opus_int32 delayedGain_Q10[ DECISION_DELAY ]; + NSQ_del_dec_struct psDelDec[ MAX_DEL_DEC_STATES ]; + NSQ_del_dec_struct *psDD; + + /* Set unvoiced lag to the previous one, overwrite later for voiced */ + lag = NSQ->lagPrev; + + silk_assert( NSQ->prev_gain_Q16 != 0 ); + + /* Initialize delayed decision states */ + silk_memset( psDelDec, 0, psEncC->nStatesDelayedDecision * sizeof( NSQ_del_dec_struct ) ); + for( k = 0; k < psEncC->nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + psDD->Seed = ( k + psIndices->Seed ) & 3; + psDD->SeedInit = psDD->Seed; + psDD->RD_Q10 = 0; + psDD->LF_AR_Q14 = NSQ->sLF_AR_shp_Q14; + psDD->Shape_Q14[ 0 ] = NSQ->sLTP_shp_Q14[ psEncC->ltp_mem_length - 1 ]; + silk_memcpy( psDD->sLPC_Q14, NSQ->sLPC_Q14, NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) ); + silk_memcpy( psDD->sAR2_Q14, NSQ->sAR2_Q14, sizeof( NSQ->sAR2_Q14 ) ); + } + + offset_Q10 = silk_Quantization_Offsets_Q10[ psIndices->signalType >> 1 ][ psIndices->quantOffsetType ]; + smpl_buf_idx = 0; /* index of oldest samples */ + + decisionDelay = silk_min_int( DECISION_DELAY, psEncC->subfr_length ); + + /* For voiced frames limit the decision delay to lower than the pitch lag */ + if( psIndices->signalType == TYPE_VOICED ) { + for( k = 0; k < psEncC->nb_subfr; k++ ) { + decisionDelay = silk_min_int( decisionDelay, pitchL[ k ] - LTP_ORDER / 2 - 1 ); + } + } else { + if( lag > 0 ) { + decisionDelay = silk_min_int( decisionDelay, lag - LTP_ORDER / 2 - 1 ); + } + } + + if( psIndices->NLSFInterpCoef_Q2 == 4 ) { + LSF_interpolation_flag = 0; + } else { + LSF_interpolation_flag = 1; + } + + /* Set up pointers to start of sub frame */ + pxq = &NSQ->xq[ psEncC->ltp_mem_length ]; + NSQ->sLTP_shp_buf_idx = psEncC->ltp_mem_length; + NSQ->sLTP_buf_idx = psEncC->ltp_mem_length; + subfr = 0; + for( k = 0; k < psEncC->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 */ + silk_assert( HarmShapeGain_Q14[ k ] >= 0 ); + HarmShapeFIRPacked_Q14 = silk_RSHIFT( HarmShapeGain_Q14[ k ], 2 ); + HarmShapeFIRPacked_Q14 |= silk_LSHIFT( (opus_int32)silk_RSHIFT( HarmShapeGain_Q14[ k ], 1 ), 16 ); + + NSQ->rewhite_flag = 0; + if( psIndices->signalType == TYPE_VOICED ) { + /* Voiced */ + lag = pitchL[ k ]; + + /* Re-whitening */ + if( ( k & ( 3 - silk_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 += ( silk_int32_MAX >> 4 ); + silk_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; + pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 ); + pxq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( + silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], Gains_Q16[ 1 ] ), 14 ) ); + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay + i ] = psDD->Shape_Q14[ last_smple_idx ]; + } + + subfr = 0; + } + + /* Rewhiten with new A coefs */ + start_idx = psEncC->ltp_mem_length - lag - psEncC->predictLPCOrder - LTP_ORDER / 2; + silk_assert( start_idx > 0 ); + + silk_LPC_analysis_filter( &sLTP[ start_idx ], &NSQ->xq[ start_idx + k * psEncC->subfr_length ], + A_Q12, psEncC->ltp_mem_length - start_idx, psEncC->predictLPCOrder ); + + NSQ->sLTP_buf_idx = psEncC->ltp_mem_length; + NSQ->rewhite_flag = 1; + } + } + + silk_nsq_del_dec_scale_states( psEncC, NSQ, psDelDec, x_Q3, x_sc_Q10, sLTP, sLTP_Q15, k, + psEncC->nStatesDelayedDecision, LTP_scale_Q14, Gains_Q16, pitchL, psIndices->signalType, decisionDelay ); + + silk_noise_shape_quantizer_del_dec( NSQ, psDelDec, psIndices->signalType, x_sc_Q10, pulses, pxq, sLTP_Q15, + delayedGain_Q10, 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_Q3 += psEncC->subfr_length; + pulses += 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 ]; + psIndices->Seed = psDD->SeedInit; + last_smple_idx = smpl_buf_idx + decisionDelay; + Gain_Q10 = silk_RSHIFT32( Gains_Q16[ psEncC->nb_subfr - 1 ], 6 ); + for( i = 0; i < decisionDelay; i++ ) { + last_smple_idx = ( last_smple_idx - 1 ) & DECISION_DELAY_MASK; + pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 ); + pxq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( + silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], Gain_Q10 ), 8 ) ); + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay + i ] = psDD->Shape_Q14[ last_smple_idx ]; + } + silk_memcpy( NSQ->sLPC_Q14, &psDD->sLPC_Q14[ psEncC->subfr_length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) ); + silk_memcpy( NSQ->sAR2_Q14, psDD->sAR2_Q14, sizeof( psDD->sAR2_Q14 ) ); + + /* Update states */ + NSQ->sLF_AR_shp_Q14 = psDD->LF_AR_Q14; + NSQ->lagPrev = pitchL[ psEncC->nb_subfr - 1 ]; + + /* Save quantized speech signal */ + /* DEBUG_STORE_DATA( enc.pcm, &NSQ->xq[psEncC->ltp_mem_length], psEncC->frame_length * sizeof( opus_int16 ) ) */ + silk_memmove( NSQ->xq, &NSQ->xq[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int16 ) ); + silk_memmove( NSQ->sLTP_shp_Q14, &NSQ->sLTP_shp_Q14[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int32 ) ); +} + +/******************************************/ +/* Noise shape quantizer for one subframe */ +/******************************************/ +static inline void silk_noise_shape_quantizer_del_dec( + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP filter state */ + opus_int32 delayedGain_Q10[], /* I/O Gain delay buffer */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int Lambda_Q10, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int subfr, /* I Subframe number */ + opus_int shapingLPCOrder, /* I Shaping LPC filter order */ + opus_int predictLPCOrder, /* I Prediction filter order */ + opus_int warping_Q16, /* I */ + opus_int nStatesDelayedDecision, /* I Number of states in decision tree */ + opus_int *smpl_buf_idx, /* I Index to newest samples in buffers */ + opus_int decisionDelay /* I */ +) +{ + opus_int i, j, k, Winner_ind, RDmin_ind, RDmax_ind, last_smple_idx; + opus_int32 Winner_rand_state; + opus_int32 LTP_pred_Q14, LPC_pred_Q14, n_AR_Q14, n_LTP_Q14; + opus_int32 n_LF_Q14, r_Q10, rr_Q10, rd1_Q10, rd2_Q10, RDmin_Q10, RDmax_Q10; + opus_int32 q1_Q0, q1_Q10, q2_Q10, exc_Q14, LPC_exc_Q14, xq_Q14, Gain_Q10; + opus_int32 tmp1, tmp2, sLF_AR_shp_Q14; + opus_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; + + silk_assert( nStatesDelayedDecision > 0 ); + + shp_lag_ptr = &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ]; + pred_lag_ptr = &sLTP_Q15[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + Gain_Q10 = silk_RSHIFT( Gain_Q16, 6 ); + + for( i = 0; i < length; i++ ) { + /* Perform common calculations used in all states */ + + /* Long-term prediction */ + if( signalType == TYPE_VOICED ) { + /* Unrolled loop */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LTP_pred_Q14 = 2; + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ 0 ], b_Q14[ 0 ] ); + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -1 ], b_Q14[ 1 ] ); + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -2 ], b_Q14[ 2 ] ); + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -3 ], b_Q14[ 3 ] ); + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -4 ], b_Q14[ 4 ] ); + LTP_pred_Q14 = silk_LSHIFT( LTP_pred_Q14, 1 ); /* Q13 -> Q14 */ + pred_lag_ptr++; + } else { + LTP_pred_Q14 = 0; + } + + /* Long-term shaping */ + if( lag > 0 ) { + /* Symmetric, packed FIR coefficients */ + n_LTP_Q14 = silk_SMULWB( silk_ADD32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 ); + n_LTP_Q14 = silk_SMLAWT( n_LTP_Q14, shp_lag_ptr[ -1 ], HarmShapeFIRPacked_Q14 ); + n_LTP_Q14 = silk_SUB_LSHIFT32( LTP_pred_Q14, n_LTP_Q14, 2 ); /* Q12 -> Q14 */ + 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 = silk_RAND( psDD->Seed ); + + /* Pointer used in short term prediction and shaping */ + psLPC_Q14 = &psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 1 + i ]; + /* Short-term prediction */ + silk_assert( predictLPCOrder == 10 || predictLPCOrder == 16 ); + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LPC_pred_Q14 = silk_RSHIFT( predictLPCOrder, 1 ); + LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ 0 ], a_Q12[ 0 ] ); + LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -1 ], a_Q12[ 1 ] ); + LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -2 ], a_Q12[ 2 ] ); + LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -3 ], a_Q12[ 3 ] ); + LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -4 ], a_Q12[ 4 ] ); + LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -5 ], a_Q12[ 5 ] ); + LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -6 ], a_Q12[ 6 ] ); + LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -7 ], a_Q12[ 7 ] ); + LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -8 ], a_Q12[ 8 ] ); + LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -9 ], a_Q12[ 9 ] ); + if( predictLPCOrder == 16 ) { + LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -10 ], a_Q12[ 10 ] ); + LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -11 ], a_Q12[ 11 ] ); + LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -12 ], a_Q12[ 12 ] ); + LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -13 ], a_Q12[ 13 ] ); + LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -14 ], a_Q12[ 14 ] ); + LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -15 ], a_Q12[ 15 ] ); + } + LPC_pred_Q14 = silk_LSHIFT( LPC_pred_Q14, 4 ); /* Q10 -> Q14 */ + + /* Noise shape feedback */ + silk_assert( ( shapingLPCOrder & 1 ) == 0 ); /* check that order is even */ + /* Output of lowpass section */ + tmp2 = silk_SMLAWB( psLPC_Q14[ 0 ], psDD->sAR2_Q14[ 0 ], warping_Q16 ); + /* Output of allpass section */ + tmp1 = silk_SMLAWB( psDD->sAR2_Q14[ 0 ], psDD->sAR2_Q14[ 1 ] - tmp2, warping_Q16 ); + psDD->sAR2_Q14[ 0 ] = tmp2; + n_AR_Q14 = silk_RSHIFT( shapingLPCOrder, 1 ); + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp2, AR_shp_Q13[ 0 ] ); + /* Loop over allpass sections */ + for( j = 2; j < shapingLPCOrder; j += 2 ) { + /* Output of allpass section */ + tmp2 = silk_SMLAWB( psDD->sAR2_Q14[ j - 1 ], psDD->sAR2_Q14[ j + 0 ] - tmp1, warping_Q16 ); + psDD->sAR2_Q14[ j - 1 ] = tmp1; + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp1, AR_shp_Q13[ j - 1 ] ); + /* Output of allpass section */ + tmp1 = silk_SMLAWB( psDD->sAR2_Q14[ j + 0 ], psDD->sAR2_Q14[ j + 1 ] - tmp2, warping_Q16 ); + psDD->sAR2_Q14[ j + 0 ] = tmp2; + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp2, AR_shp_Q13[ j ] ); + } + psDD->sAR2_Q14[ shapingLPCOrder - 1 ] = tmp1; + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp1, AR_shp_Q13[ shapingLPCOrder - 1 ] ); + + n_AR_Q14 = silk_LSHIFT( n_AR_Q14, 1 ); /* Q11 -> Q12 */ + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, psDD->LF_AR_Q14, Tilt_Q14 ); /* Q12 */ + n_AR_Q14 = silk_LSHIFT( n_AR_Q14, 2 ); /* Q12 -> Q14 */ + + n_LF_Q14 = silk_SMULWB( psDD->Shape_Q14[ *smpl_buf_idx ], LF_shp_Q14 ); /* Q12 */ + n_LF_Q14 = silk_SMLAWT( n_LF_Q14, psDD->LF_AR_Q14, LF_shp_Q14 ); /* Q12 */ + n_LF_Q14 = silk_LSHIFT( n_LF_Q14, 2 ); /* Q12 -> Q14 */ + + /* Input minus prediction plus noise feedback */ + /* r = x[ i ] - LTP_pred - LPC_pred + n_AR + n_Tilt + n_LF + n_LTP */ + tmp1 = silk_ADD32( n_AR_Q14, n_LF_Q14 ); /* Q14 */ + tmp2 = silk_ADD32( n_LTP_Q14, LPC_pred_Q14 ); /* Q13 */ + tmp1 = silk_SUB32( tmp2, tmp1 ); /* Q13 */ + tmp1 = silk_RSHIFT_ROUND( tmp1, 4 ); /* Q10 */ + + r_Q10 = silk_SUB32( x_Q10[ i ], tmp1 ); /* residual error Q10 */ + + /* Flip sign depending on dither */ + if ( psDD->Seed < 0 ) { + r_Q10 = -r_Q10; + } + r_Q10 = silk_LIMIT_32( r_Q10, -(31 << 10), 30 << 10 ); + + /* Find two quantization level candidates and measure their rate-distortion */ + q1_Q10 = silk_SUB32( r_Q10, offset_Q10 ); + q1_Q0 = silk_RSHIFT( q1_Q10, 10 ); + if( q1_Q0 > 0 ) { + q1_Q10 = silk_SUB32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 ); + q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 ); + q2_Q10 = silk_ADD32( q1_Q10, 1024 ); + rd1_Q10 = silk_SMULBB( q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else if( q1_Q0 == 0 ) { + q1_Q10 = offset_Q10; + q2_Q10 = silk_ADD32( q1_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 ); + rd1_Q10 = silk_SMULBB( q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else if( q1_Q0 == -1 ) { + q2_Q10 = offset_Q10; + q1_Q10 = silk_SUB32( q2_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 ); + rd1_Q10 = silk_SMULBB( -q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else { /* q1_Q0 < -1 */ + q1_Q10 = silk_ADD32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 ); + q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 ); + q2_Q10 = silk_ADD32( q1_Q10, 1024 ); + rd1_Q10 = silk_SMULBB( -q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( -q2_Q10, Lambda_Q10 ); + } + rr_Q10 = silk_SUB32( r_Q10, q1_Q10 ); + rd1_Q10 = silk_RSHIFT( silk_SMLABB( rd1_Q10, rr_Q10, rr_Q10 ), 10 ); + rr_Q10 = silk_SUB32( r_Q10, q2_Q10 ); + rd2_Q10 = silk_RSHIFT( silk_SMLABB( rd2_Q10, rr_Q10, rr_Q10 ), 10 ); + + if( rd1_Q10 < rd2_Q10 ) { + psSS[ 0 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd1_Q10 ); + psSS[ 1 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd2_Q10 ); + psSS[ 0 ].Q_Q10 = q1_Q10; + psSS[ 1 ].Q_Q10 = q2_Q10; + } else { + psSS[ 0 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd2_Q10 ); + psSS[ 1 ].RD_Q10 = silk_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_Q14 = silk_LSHIFT32( psSS[ 0 ].Q_Q10, 4 ); + if ( psDD->Seed < 0 ) { + exc_Q14 = -exc_Q14; + } + + /* Add predictions */ + LPC_exc_Q14 = silk_ADD32( exc_Q14, LTP_pred_Q14 ); + xq_Q14 = silk_ADD32( LPC_exc_Q14, LPC_pred_Q14 ); + + /* Update states */ + sLF_AR_shp_Q14 = silk_SUB32( xq_Q14, n_AR_Q14 ); + psSS[ 0 ].sLTP_shp_Q14 = silk_SUB32( sLF_AR_shp_Q14, n_LF_Q14 ); + psSS[ 0 ].LF_AR_Q14 = sLF_AR_shp_Q14; + psSS[ 0 ].LPC_exc_Q14 = LPC_exc_Q14; + psSS[ 0 ].xq_Q14 = xq_Q14; + + /* Update states for second best quantization */ + + /* Quantized excitation */ + exc_Q14 = silk_LSHIFT32( psSS[ 1 ].Q_Q10, 4 ); + if ( psDD->Seed < 0 ) { + exc_Q14 = -exc_Q14; + } + + + /* Add predictions */ + LPC_exc_Q14 = silk_ADD32( exc_Q14, LTP_pred_Q14 ); + xq_Q14 = silk_ADD32( LPC_exc_Q14, LPC_pred_Q14 ); + + /* Update states */ + sLF_AR_shp_Q14 = silk_SUB32( xq_Q14, n_AR_Q14 ); + psSS[ 1 ].sLTP_shp_Q14 = silk_SUB32( sLF_AR_shp_Q14, n_LF_Q14 ); + psSS[ 1 ].LF_AR_Q14 = sLF_AR_shp_Q14; + psSS[ 1 ].LPC_exc_Q14 = LPC_exc_Q14; + psSS[ 1 ].xq_Q14 = xq_Q14; + } + + *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 = silk_ADD32( psSampleState[ k ][ 0 ].RD_Q10, silk_int32_MAX >> 4 ); + psSampleState[ k ][ 1 ].RD_Q10 = silk_ADD32( psSampleState[ k ][ 1 ].RD_Q10, silk_int32_MAX >> 4 ); + silk_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 ) { + silk_memcpy( ( (opus_int32 *)&psDelDec[ RDmax_ind ] ) + i, + ( (opus_int32 *)&psDelDec[ RDmin_ind ] ) + i, sizeof( NSQ_del_dec_struct ) - i * sizeof( opus_int32) ); + silk_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 ) { + pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 ); + xq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( + silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], delayedGain_Q10[ last_smple_idx ] ), 8 ) ); + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay ] = psDD->Shape_Q14[ last_smple_idx ]; + sLTP_Q15[ NSQ->sLTP_buf_idx - decisionDelay ] = psDD->Pred_Q15[ 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_Q14 = psSS->LF_AR_Q14; + psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH + i ] = psSS->xq_Q14; + psDD->Xq_Q14[ *smpl_buf_idx ] = psSS->xq_Q14; + psDD->Q_Q10[ *smpl_buf_idx ] = psSS->Q_Q10; + psDD->Pred_Q15[ *smpl_buf_idx ] = silk_LSHIFT32( psSS->LPC_exc_Q14, 1 ); + psDD->Shape_Q14[ *smpl_buf_idx ] = psSS->sLTP_shp_Q14; + psDD->Seed = silk_ADD32_ovflw( psDD->Seed, silk_RSHIFT_ROUND( psSS->Q_Q10, 10 ) ); + psDD->RandState[ *smpl_buf_idx ] = psDD->Seed; + psDD->RD_Q10 = psSS->RD_Q10; + } + delayedGain_Q10[ *smpl_buf_idx ] = Gain_Q10; + } + /* Update LPC states */ + for( k = 0; k < nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + silk_memcpy( psDD->sLPC_Q14, &psDD->sLPC_Q14[ length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) ); + } +} + +static inline void silk_nsq_del_dec_scale_states( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + const opus_int32 x_Q3[], /* I Input in Q3 */ + opus_int32 x_sc_Q10[], /* O Input scaled with 1/Gain in Q10 */ + const opus_int16 sLTP[], /* I Re-whitened LTP state in Q0 */ + opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */ + opus_int subfr, /* I Subframe number */ + opus_int nStatesDelayedDecision, /* I Number of del dec states */ + const opus_int LTP_scale_Q14, /* I LTP state scaling */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */ + const opus_int signal_type, /* I Signal type */ + const opus_int decisionDelay /* I Decision delay */ +) +{ + opus_int i, k, lag; + opus_int32 gain_adj_Q16, inv_gain_Q31, inv_gain_Q23; + NSQ_del_dec_struct *psDD; + + lag = pitchL[ subfr ]; + inv_gain_Q31 = silk_INVERSE32_varQ( silk_max( Gains_Q16[ subfr ], 1 ), 47 ); + silk_assert( inv_gain_Q31 != 0 ); + + /* Calculate gain adjustment factor */ + if( Gains_Q16[ subfr ] != NSQ->prev_gain_Q16 ) { + gain_adj_Q16 = silk_DIV32_varQ( NSQ->prev_gain_Q16, Gains_Q16[ subfr ], 16 ); + } else { + gain_adj_Q16 = (opus_int32)1 << 16; + } + + /* Scale input */ + inv_gain_Q23 = silk_RSHIFT_ROUND( inv_gain_Q31, 8 ); + for( i = 0; i < psEncC->subfr_length; i++ ) { + x_sc_Q10[ i ] = silk_SMULWW( x_Q3[ i ], inv_gain_Q23 ); + } + + /* Save inverse gain */ + NSQ->prev_gain_Q16 = Gains_Q16[ subfr ]; + + /* After rewhitening the LTP state is un-scaled, so scale with inv_gain_Q16 */ + if( NSQ->rewhite_flag ) { + if( subfr == 0 ) { + /* Do LTP downscaling */ + inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, LTP_scale_Q14 ), 2 ); + } + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) { + silk_assert( i < MAX_FRAME_LENGTH ); + sLTP_Q15[ i ] = silk_SMULWB( inv_gain_Q31, sLTP[ i ] ); + } + } + + /* Adjust for changing gain */ + if( gain_adj_Q16 != (opus_int32)1 << 16 ) { + /* Scale long-term shaping state */ + for( i = NSQ->sLTP_shp_buf_idx - psEncC->ltp_mem_length; i < NSQ->sLTP_shp_buf_idx; i++ ) { + NSQ->sLTP_shp_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLTP_shp_Q14[ i ] ); + } + + /* Scale long-term prediction state */ + if( signal_type == TYPE_VOICED && NSQ->rewhite_flag == 0 ) { + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx - decisionDelay; i++ ) { + sLTP_Q15[ i ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ i ] ); + } + } + + for( k = 0; k < nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + + /* Scale scalar states */ + psDD->LF_AR_Q14 = silk_SMULWW( gain_adj_Q16, psDD->LF_AR_Q14 ); + + /* Scale short-term prediction and shaping states */ + for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) { + psDD->sLPC_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->sLPC_Q14[ i ] ); + } + for( i = 0; i < MAX_SHAPE_LPC_ORDER; i++ ) { + psDD->sAR2_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->sAR2_Q14[ i ] ); + } + for( i = 0; i < DECISION_DELAY; i++ ) { + psDD->Pred_Q15[ i ] = silk_SMULWW( gain_adj_Q16, psDD->Pred_Q15[ i ] ); + psDD->Shape_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->Shape_Q14[ i ] ); + } + } + } +} diff --git a/code/opus-1.0.2/silk/PLC.c b/code/opus-1.0.2/silk/PLC.c new file mode 100644 index 00000000..8d547295 --- /dev/null +++ b/code/opus-1.0.2/silk/PLC.c @@ -0,0 +1,423 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "stack_alloc.h" +#include "PLC.h" + +#define NB_ATT 2 +static const opus_int16 HARM_ATT_Q15[NB_ATT] = { 32440, 31130 }; /* 0.99, 0.95 */ +static const opus_int16 PLC_RAND_ATTENUATE_V_Q15[NB_ATT] = { 31130, 26214 }; /* 0.95, 0.8 */ +static const opus_int16 PLC_RAND_ATTENUATE_UV_Q15[NB_ATT] = { 32440, 29491 }; /* 0.99, 0.9 */ + +static inline void silk_PLC_update( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl /* I/O Decoder control */ +); + +static inline void silk_PLC_conceal( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int16 frame[] /* O LPC residual signal */ +); + + +void silk_PLC_Reset( + silk_decoder_state *psDec /* I/O Decoder state */ +) +{ + psDec->sPLC.pitchL_Q8 = silk_LSHIFT( psDec->frame_length, 8 - 1 ); + psDec->sPLC.prevGain_Q16[ 0 ] = SILK_FIX_CONST( 1, 16 ); + psDec->sPLC.prevGain_Q16[ 1 ] = SILK_FIX_CONST( 1, 16 ); + psDec->sPLC.subfr_length = 20; + psDec->sPLC.nb_subfr = 2; +} + +void silk_PLC( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int16 frame[], /* I/O signal */ + opus_int lost /* I Loss flag */ +) +{ + /* PLC control function */ + if( psDec->fs_kHz != psDec->sPLC.fs_kHz ) { + silk_PLC_Reset( psDec ); + psDec->sPLC.fs_kHz = psDec->fs_kHz; + } + + if( lost ) { + /****************************/ + /* Generate Signal */ + /****************************/ + silk_PLC_conceal( psDec, psDecCtrl, frame ); + + psDec->lossCnt++; + } else { + /****************************/ + /* Update state */ + /****************************/ + silk_PLC_update( psDec, psDecCtrl ); + } +} + +/**************************************************/ +/* Update state of PLC */ +/**************************************************/ +static inline void silk_PLC_update( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl /* I/O Decoder control */ +) +{ + opus_int32 LTP_Gain_Q14, temp_LTP_Gain_Q14; + opus_int i, j; + silk_PLC_struct *psPLC; + + psPLC = &psDec->sPLC; + + /* Update parameters used in case of packet loss */ + psDec->prevSignalType = psDec->indices.signalType; + LTP_Gain_Q14 = 0; + if( psDec->indices.signalType == TYPE_VOICED ) { + /* Find the parameters for the last subframe which contains a pitch pulse */ + for( j = 0; j * psDec->subfr_length < psDecCtrl->pitchL[ psDec->nb_subfr - 1 ]; j++ ) { + if( j == psDec->nb_subfr ) { + break; + } + temp_LTP_Gain_Q14 = 0; + for( i = 0; i < LTP_ORDER; i++ ) { + temp_LTP_Gain_Q14 += psDecCtrl->LTPCoef_Q14[ ( psDec->nb_subfr - 1 - j ) * LTP_ORDER + i ]; + } + if( temp_LTP_Gain_Q14 > LTP_Gain_Q14 ) { + LTP_Gain_Q14 = temp_LTP_Gain_Q14; + silk_memcpy( psPLC->LTPCoef_Q14, + &psDecCtrl->LTPCoef_Q14[ silk_SMULBB( psDec->nb_subfr - 1 - j, LTP_ORDER ) ], + LTP_ORDER * sizeof( opus_int16 ) ); + + psPLC->pitchL_Q8 = silk_LSHIFT( psDecCtrl->pitchL[ psDec->nb_subfr - 1 - j ], 8 ); + } + } + + silk_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( opus_int16 ) ); + psPLC->LTPCoef_Q14[ LTP_ORDER / 2 ] = LTP_Gain_Q14; + + /* Limit LT coefs */ + if( LTP_Gain_Q14 < V_PITCH_GAIN_START_MIN_Q14 ) { + opus_int scale_Q10; + opus_int32 tmp; + + tmp = silk_LSHIFT( V_PITCH_GAIN_START_MIN_Q14, 10 ); + scale_Q10 = silk_DIV32( tmp, silk_max( LTP_Gain_Q14, 1 ) ); + for( i = 0; i < LTP_ORDER; i++ ) { + psPLC->LTPCoef_Q14[ i ] = silk_RSHIFT( silk_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q10 ), 10 ); + } + } else if( LTP_Gain_Q14 > V_PITCH_GAIN_START_MAX_Q14 ) { + opus_int scale_Q14; + opus_int32 tmp; + + tmp = silk_LSHIFT( V_PITCH_GAIN_START_MAX_Q14, 14 ); + scale_Q14 = silk_DIV32( tmp, silk_max( LTP_Gain_Q14, 1 ) ); + for( i = 0; i < LTP_ORDER; i++ ) { + psPLC->LTPCoef_Q14[ i ] = silk_RSHIFT( silk_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q14 ), 14 ); + } + } + } else { + psPLC->pitchL_Q8 = silk_LSHIFT( silk_SMULBB( psDec->fs_kHz, 18 ), 8 ); + silk_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( opus_int16 )); + } + + /* Save LPC coeficients */ + silk_memcpy( psPLC->prevLPC_Q12, psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order * sizeof( opus_int16 ) ); + psPLC->prevLTP_scale_Q14 = psDecCtrl->LTP_scale_Q14; + + /* Save last two gains */ + silk_memcpy( psPLC->prevGain_Q16, &psDecCtrl->Gains_Q16[ psDec->nb_subfr - 2 ], 2 * sizeof( opus_int32 ) ); + + psPLC->subfr_length = psDec->subfr_length; + psPLC->nb_subfr = psDec->nb_subfr; +} + +static inline void silk_PLC_conceal( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int16 frame[] /* O LPC residual signal */ +) +{ + opus_int i, j, k; + opus_int lag, idx, sLTP_buf_idx, shift1, shift2; + opus_int32 rand_seed, harm_Gain_Q15, rand_Gain_Q15, inv_gain_Q30; + opus_int32 energy1, energy2, *rand_ptr, *pred_lag_ptr; + opus_int32 LPC_pred_Q10, LTP_pred_Q12; + opus_int16 rand_scale_Q14; + opus_int16 *B_Q14, *exc_buf_ptr; + opus_int32 *sLPC_Q14_ptr; + VARDECL( opus_int16, exc_buf ); + opus_int16 A_Q12[ MAX_LPC_ORDER ]; + VARDECL( opus_int16, sLTP ); + VARDECL( opus_int32, sLTP_Q14 ); + silk_PLC_struct *psPLC = &psDec->sPLC; + opus_int32 prevGain_Q10[2]; + SAVE_STACK; + + ALLOC( exc_buf, 2*psPLC->subfr_length, opus_int16 ); + ALLOC( sLTP, psDec->ltp_mem_length, opus_int16 ); + ALLOC( sLTP_Q14, psDec->ltp_mem_length + psDec->frame_length, opus_int32 ); + + prevGain_Q10[0] = silk_RSHIFT( psPLC->prevGain_Q16[ 0 ], 6); + prevGain_Q10[1] = silk_RSHIFT( psPLC->prevGain_Q16[ 1 ], 6); + + if( psDec->first_frame_after_reset ) { + silk_memset( psPLC->prevLPC_Q12, 0, sizeof( psPLC->prevLPC_Q12 ) ); + } + + /* Find random noise component */ + /* Scale previous excitation signal */ + exc_buf_ptr = exc_buf; + for( k = 0; k < 2; k++ ) { + for( i = 0; i < psPLC->subfr_length; i++ ) { + exc_buf_ptr[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT( + silk_SMULWW( psDec->exc_Q14[ i + ( k + psPLC->nb_subfr - 2 ) * psPLC->subfr_length ], prevGain_Q10[ k ] ), 8 ) ); + } + exc_buf_ptr += psPLC->subfr_length; + } + /* Find the subframe with lowest energy of the last two and use that as random noise generator */ + silk_sum_sqr_shift( &energy1, &shift1, exc_buf, psPLC->subfr_length ); + silk_sum_sqr_shift( &energy2, &shift2, &exc_buf[ psPLC->subfr_length ], psPLC->subfr_length ); + + if( silk_RSHIFT( energy1, shift2 ) < silk_RSHIFT( energy2, shift1 ) ) { + /* First sub-frame has lowest energy */ + rand_ptr = &psDec->exc_Q14[ silk_max_int( 0, ( psPLC->nb_subfr - 1 ) * psPLC->subfr_length - RAND_BUF_SIZE ) ]; + } else { + /* Second sub-frame has lowest energy */ + rand_ptr = &psDec->exc_Q14[ silk_max_int( 0, psPLC->nb_subfr * psPLC->subfr_length - RAND_BUF_SIZE ) ]; + } + + /* Set up Gain to random noise component */ + B_Q14 = psPLC->LTPCoef_Q14; + rand_scale_Q14 = psPLC->randScale_Q14; + + /* Set up attenuation gains */ + harm_Gain_Q15 = HARM_ATT_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ]; + if( psDec->prevSignalType == TYPE_VOICED ) { + rand_Gain_Q15 = PLC_RAND_ATTENUATE_V_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ]; + } else { + rand_Gain_Q15 = PLC_RAND_ATTENUATE_UV_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ]; + } + + /* LPC concealment. Apply BWE to previous LPC */ + silk_bwexpander( psPLC->prevLPC_Q12, psDec->LPC_order, SILK_FIX_CONST( BWE_COEF, 16 ) ); + + /* Preload LPC coeficients to array on stack. Gives small performance gain */ + silk_memcpy( A_Q12, psPLC->prevLPC_Q12, psDec->LPC_order * sizeof( opus_int16 ) ); + + /* First Lost frame */ + if( psDec->lossCnt == 0 ) { + rand_scale_Q14 = 1 << 14; + + /* Reduce random noise Gain for voiced frames */ + if( psDec->prevSignalType == TYPE_VOICED ) { + for( i = 0; i < LTP_ORDER; i++ ) { + rand_scale_Q14 -= B_Q14[ i ]; + } + rand_scale_Q14 = silk_max_16( 3277, rand_scale_Q14 ); /* 0.2 */ + rand_scale_Q14 = (opus_int16)silk_RSHIFT( silk_SMULBB( rand_scale_Q14, psPLC->prevLTP_scale_Q14 ), 14 ); + } else { + /* Reduce random noise for unvoiced frames with high LPC gain */ + opus_int32 invGain_Q30, down_scale_Q30; + + invGain_Q30 = silk_LPC_inverse_pred_gain( psPLC->prevLPC_Q12, psDec->LPC_order ); + + down_scale_Q30 = silk_min_32( silk_RSHIFT( (opus_int32)1 << 30, LOG2_INV_LPC_GAIN_HIGH_THRES ), invGain_Q30 ); + down_scale_Q30 = silk_max_32( silk_RSHIFT( (opus_int32)1 << 30, LOG2_INV_LPC_GAIN_LOW_THRES ), down_scale_Q30 ); + down_scale_Q30 = silk_LSHIFT( down_scale_Q30, LOG2_INV_LPC_GAIN_HIGH_THRES ); + + rand_Gain_Q15 = silk_RSHIFT( silk_SMULWB( down_scale_Q30, rand_Gain_Q15 ), 14 ); + } + } + + rand_seed = psPLC->rand_seed; + lag = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 ); + sLTP_buf_idx = psDec->ltp_mem_length; + + /* Rewhiten LTP state */ + idx = psDec->ltp_mem_length - lag - psDec->LPC_order - LTP_ORDER / 2; + silk_assert( idx > 0 ); + silk_LPC_analysis_filter( &sLTP[ idx ], &psDec->outBuf[ idx ], A_Q12, psDec->ltp_mem_length - idx, psDec->LPC_order ); + /* Scale LTP state */ + inv_gain_Q30 = silk_INVERSE32_varQ( psPLC->prevGain_Q16[ 1 ], 46 ); + inv_gain_Q30 = silk_min( inv_gain_Q30, silk_int32_MAX >> 1 ); + for( i = idx + psDec->LPC_order; i < psDec->ltp_mem_length; i++ ) { + sLTP_Q14[ i ] = silk_SMULWB( inv_gain_Q30, sLTP[ i ] ); + } + + /***************************/ + /* LTP synthesis filtering */ + /***************************/ + for( k = 0; k < psDec->nb_subfr; k++ ) { + /* Set up pointer */ + pred_lag_ptr = &sLTP_Q14[ sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + for( i = 0; i < psDec->subfr_length; i++ ) { + /* Unrolled loop */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LTP_pred_Q12 = 2; + LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ 0 ], B_Q14[ 0 ] ); + LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -1 ], B_Q14[ 1 ] ); + LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -2 ], B_Q14[ 2 ] ); + LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -3 ], B_Q14[ 3 ] ); + LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -4 ], B_Q14[ 4 ] ); + pred_lag_ptr++; + + /* Generate LPC excitation */ + rand_seed = silk_RAND( rand_seed ); + idx = silk_RSHIFT( rand_seed, 25 ) & RAND_BUF_MASK; + sLTP_Q14[ sLTP_buf_idx ] = silk_LSHIFT32( silk_SMLAWB( LTP_pred_Q12, rand_ptr[ idx ], rand_scale_Q14 ), 2 ); + sLTP_buf_idx++; + } + + /* Gradually reduce LTP gain */ + for( j = 0; j < LTP_ORDER; j++ ) { + B_Q14[ j ] = silk_RSHIFT( silk_SMULBB( harm_Gain_Q15, B_Q14[ j ] ), 15 ); + } + /* Gradually reduce excitation gain */ + rand_scale_Q14 = silk_RSHIFT( silk_SMULBB( rand_scale_Q14, rand_Gain_Q15 ), 15 ); + + /* Slowly increase pitch lag */ + psPLC->pitchL_Q8 = silk_SMLAWB( psPLC->pitchL_Q8, psPLC->pitchL_Q8, PITCH_DRIFT_FAC_Q16 ); + psPLC->pitchL_Q8 = silk_min_32( psPLC->pitchL_Q8, silk_LSHIFT( silk_SMULBB( MAX_PITCH_LAG_MS, psDec->fs_kHz ), 8 ) ); + lag = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 ); + } + + /***************************/ + /* LPC synthesis filtering */ + /***************************/ + sLPC_Q14_ptr = &sLTP_Q14[ psDec->ltp_mem_length - MAX_LPC_ORDER ]; + + /* Copy LPC state */ + silk_memcpy( sLPC_Q14_ptr, psDec->sLPC_Q14_buf, MAX_LPC_ORDER * sizeof( opus_int32 ) ); + + silk_assert( psDec->LPC_order >= 10 ); /* check that unrolling works */ + for( i = 0; i < psDec->frame_length; i++ ) { + /* partly unrolled */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LPC_pred_Q10 = silk_RSHIFT( psDec->LPC_order, 1 ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 1 ], A_Q12[ 0 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 2 ], A_Q12[ 1 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 3 ], A_Q12[ 2 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 4 ], A_Q12[ 3 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 5 ], A_Q12[ 4 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 6 ], A_Q12[ 5 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 7 ], A_Q12[ 6 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 8 ], A_Q12[ 7 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 9 ], A_Q12[ 8 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 10 ], A_Q12[ 9 ] ); + for( j = 10; j < psDec->LPC_order; j++ ) { + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - j - 1 ], A_Q12[ j ] ); + } + + /* Add prediction to LPC excitation */ + sLPC_Q14_ptr[ MAX_LPC_ORDER + i ] = silk_ADD_LSHIFT32( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ], LPC_pred_Q10, 4 ); + + /* Scale with Gain */ + frame[ i ] = (opus_int16)silk_SAT16( silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ], prevGain_Q10[ 1 ] ), 8 ) ) ); + } + + /* Save LPC state */ + silk_memcpy( psDec->sLPC_Q14_buf, &sLPC_Q14_ptr[ psDec->frame_length ], MAX_LPC_ORDER * sizeof( opus_int32 ) ); + + /**************************************/ + /* Update states */ + /**************************************/ + psPLC->rand_seed = rand_seed; + psPLC->randScale_Q14 = rand_scale_Q14; + for( i = 0; i < MAX_NB_SUBFR; i++ ) { + psDecCtrl->pitchL[ i ] = lag; + } + RESTORE_STACK; +} + +/* Glues concealed frames with new good received frames */ +void silk_PLC_glue_frames( + silk_decoder_state *psDec, /* I/O decoder state */ + opus_int16 frame[], /* I/O signal */ + opus_int length /* I length of signal */ +) +{ + opus_int i, energy_shift; + opus_int32 energy; + silk_PLC_struct *psPLC; + psPLC = &psDec->sPLC; + + if( psDec->lossCnt ) { + /* Calculate energy in concealed residual */ + silk_sum_sqr_shift( &psPLC->conc_energy, &psPLC->conc_energy_shift, frame, length ); + + psPLC->last_frame_lost = 1; + } else { + if( psDec->sPLC.last_frame_lost ) { + /* Calculate residual in decoded signal if last frame was lost */ + silk_sum_sqr_shift( &energy, &energy_shift, frame, length ); + + /* Normalize energies */ + if( energy_shift > psPLC->conc_energy_shift ) { + psPLC->conc_energy = silk_RSHIFT( psPLC->conc_energy, energy_shift - psPLC->conc_energy_shift ); + } else if( energy_shift < psPLC->conc_energy_shift ) { + energy = silk_RSHIFT( energy, psPLC->conc_energy_shift - energy_shift ); + } + + /* Fade in the energy difference */ + if( energy > psPLC->conc_energy ) { + opus_int32 frac_Q24, LZ; + opus_int32 gain_Q16, slope_Q16; + + LZ = silk_CLZ32( psPLC->conc_energy ); + LZ = LZ - 1; + psPLC->conc_energy = silk_LSHIFT( psPLC->conc_energy, LZ ); + energy = silk_RSHIFT( energy, silk_max_32( 24 - LZ, 0 ) ); + + frac_Q24 = silk_DIV32( psPLC->conc_energy, silk_max( energy, 1 ) ); + + gain_Q16 = silk_LSHIFT( silk_SQRT_APPROX( frac_Q24 ), 4 ); + slope_Q16 = silk_DIV32_16( ( (opus_int32)1 << 16 ) - gain_Q16, length ); + /* Make slope 4x steeper to avoid missing onsets after DTX */ + slope_Q16 = silk_LSHIFT( slope_Q16, 2 ); + + for( i = 0; i < length; i++ ) { + frame[ i ] = silk_SMULWB( gain_Q16, frame[ i ] ); + gain_Q16 += slope_Q16; + if( gain_Q16 > (opus_int32)1 << 16 ) { + break; + } + } + } + } + psPLC->last_frame_lost = 0; + } +} diff --git a/code/opus-1.0.2/silk/PLC.h b/code/opus-1.0.2/silk/PLC.h new file mode 100644 index 00000000..1d2d9061 --- /dev/null +++ b/code/opus-1.0.2/silk/PLC.h @@ -0,0 +1,61 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (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 SILK_PLC_H +#define SILK_PLC_H + +#include "main.h" + +#define BWE_COEF 0.99 +#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 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 silk_PLC_Reset( + silk_decoder_state *psDec /* I/O Decoder state */ +); + +void silk_PLC( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int16 frame[], /* I/O signal */ + opus_int lost /* I Loss flag */ +); + +void silk_PLC_glue_frames( + silk_decoder_state *psDec, /* I/O decoder state */ + opus_int16 frame[], /* I/O signal */ + opus_int length /* I length of signal */ +); + +#endif + diff --git a/code/opus-1.0.2/silk/SigProc_FIX.h b/code/opus-1.0.2/silk/SigProc_FIX.h new file mode 100644 index 00000000..daa5fd04 --- /dev/null +++ b/code/opus-1.0.2/silk/SigProc_FIX.h @@ -0,0 +1,589 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (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 SILK_SIGPROC_FIX_H +#define SILK_SIGPROC_FIX_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/*#define silk_MACRO_COUNT */ /* Used to enable WMOPS counting */ + +#define SILK_MAX_ORDER_LPC 16 /* max order of the LPC analysis in schur() and k2a() */ + +#include /* for memset(), memcpy(), memmove() */ +#include "typedef.h" +#include "resampler_structs.h" +#include "macros.h" + + +/********************************************************************/ +/* SIGNAL PROCESSING FUNCTIONS */ +/********************************************************************/ + +/*! + * Initialize/reset the resampler state for a given pair of input/output sampling rates +*/ +opus_int silk_resampler_init( + silk_resampler_state_struct *S, /* I/O Resampler state */ + opus_int32 Fs_Hz_in, /* I Input sampling rate (Hz) */ + opus_int32 Fs_Hz_out, /* I Output sampling rate (Hz) */ + opus_int forEnc /* I If 1: encoder; if 0: decoder */ +); + +/*! + * Resampler: convert from one sampling rate to another + */ +opus_int silk_resampler( + silk_resampler_state_struct *S, /* I/O Resampler state */ + opus_int16 out[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + opus_int32 inLen /* I Number of input samples */ +); + +/*! +* Downsample 2x, mediocre quality +*/ +void silk_resampler_down2( + opus_int32 *S, /* I/O State vector [ 2 ] */ + opus_int16 *out, /* O Output signal [ len ] */ + const opus_int16 *in, /* I Input signal [ floor(len/2) ] */ + opus_int32 inLen /* I Number of input samples */ +); + +/*! + * Downsample by a factor 2/3, low quality +*/ +void silk_resampler_down2_3( + opus_int32 *S, /* I/O State vector [ 6 ] */ + opus_int16 *out, /* O Output signal [ floor(2*inLen/3) ] */ + const opus_int16 *in, /* I Input signal [ inLen ] */ + opus_int32 inLen /* I Number of input samples */ +); + +/*! + * second order ARMA filter; + * slower than biquad() but uses more precise coefficients + * can handle (slowly) varying coefficients + */ +void silk_biquad_alt( + const opus_int16 *in, /* I input signal */ + const opus_int32 *B_Q28, /* I MA coefficients [3] */ + const opus_int32 *A_Q28, /* I AR coefficients [2] */ + opus_int32 *S, /* I/O State vector [2] */ + opus_int16 *out, /* O output signal */ + const opus_int32 len, /* I signal length (must be even) */ + opus_int stride /* I Operate on interleaved signal if > 1 */ +); + +/* Variable order MA prediction error filter. */ +void silk_LPC_analysis_filter( + opus_int16 *out, /* O Output signal */ + const opus_int16 *in, /* I Input signal */ + const opus_int16 *B, /* I MA prediction coefficients, Q12 [order] */ + const opus_int32 len, /* I Signal length */ + const opus_int32 d /* I Filter order */ +); + +/* Chirp (bandwidth expand) LP AR filter */ +void silk_bwexpander( + opus_int16 *ar, /* I/O AR filter to be expanded (without leading 1) */ + const opus_int d, /* I Length of ar */ + opus_int32 chirp_Q16 /* I Chirp factor (typically in the range 0 to 1) */ +); + +/* Chirp (bandwidth expand) LP AR filter */ +void silk_bwexpander_32( + opus_int32 *ar, /* I/O AR filter to be expanded (without leading 1) */ + const opus_int d, /* I Length of ar */ + opus_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) */ +opus_int32 silk_LPC_inverse_pred_gain( /* O Returns inverse prediction gain in energy domain, Q30 */ + const opus_int16 *A_Q12, /* I Prediction coefficients, Q12 [order] */ + const opus_int order /* I Prediction order */ +); + +/* For input in Q24 domain */ +opus_int32 silk_LPC_inverse_pred_gain_Q24( /* O Returns inverse prediction gain in energy domain, Q30 */ + const opus_int32 *A_Q24, /* I Prediction coefficients [order] */ + const opus_int order /* I Prediction order */ +); + +/* Split signal in two decimated bands using first-order allpass filters */ +void silk_ana_filt_bank_1( + const opus_int16 *in, /* I Input signal [N] */ + opus_int32 *S, /* I/O State vector [2] */ + opus_int16 *outL, /* O Low band [N/2] */ + opus_int16 *outH, /* O High band [N/2] */ + const opus_int32 N /* I Number of input samples */ +); + +/********************************************************************/ +/* SCALAR FUNCTIONS */ +/********************************************************************/ + +/* Approximation of 128 * log2() (exact inverse of approx 2^() below) */ +/* Convert input to a log scale */ +opus_int32 silk_lin2log( + const opus_int32 inLin /* I input in linear scale */ +); + +/* Approximation of a sigmoid function */ +opus_int silk_sigm_Q15( + opus_int in_Q5 /* I */ +); + +/* Approximation of 2^() (exact inverse of approx log2() above) */ +/* Convert input to a linear scale */ +opus_int32 silk_log2lin( + const opus_int32 inLog_Q7 /* I input on log scale */ +); + +/* Function that returns the maximum absolut value of the input vector */ +opus_int16 silk_int16_array_maxabs( /* O Maximum absolute value, max: 2^15-1 */ + const opus_int16 *vec, /* I Input vector [len] */ + const opus_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 silk_sum_sqr_shift( + opus_int32 *energy, /* O Energy of x, after shifting to the right */ + opus_int *shift, /* O Number of bits right shift applied to energy */ + const opus_int16 *x, /* I Input vector */ + opus_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. */ +opus_int32 silk_schur( /* O Returns residual energy */ + opus_int16 *rc_Q15, /* O reflection coefficients [order] Q15 */ + const opus_int32 *c, /* I correlations [order+1] */ + const opus_int32 order /* I prediction order */ +); + +/* Calculates the reflection coefficients from the correlation sequence */ +/* Slower than schur(), but more accurate. */ +/* Uses SMULL(), available on armv4 */ +opus_int32 silk_schur64( /* O returns residual energy */ + opus_int32 rc_Q16[], /* O Reflection coefficients [order] Q16 */ + const opus_int32 c[], /* I Correlations [order+1] */ + opus_int32 order /* I Prediction order */ +); + +/* Step up function, converts reflection coefficients to prediction coefficients */ +void silk_k2a( + opus_int32 *A_Q24, /* O Prediction coefficients [order] Q24 */ + const opus_int16 *rc_Q15, /* I Reflection coefficients [order] Q15 */ + const opus_int32 order /* I Prediction order */ +); + +/* Step up function, converts reflection coefficients to prediction coefficients */ +void silk_k2a_Q16( + opus_int32 *A_Q24, /* O Prediction coefficients [order] Q24 */ + const opus_int32 *rc_Q16, /* I Reflection coefficients [order] Q16 */ + const opus_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 of window is linearly interpolated, for speed */ +void silk_apply_sine_window( + opus_int16 px_win[], /* O Pointer to windowed signal */ + const opus_int16 px[], /* I Pointer to input signal */ + const opus_int win_type, /* I Selects a window type */ + const opus_int length /* I Window length, multiple of 4 */ +); + +/* Compute autocorrelation */ +void silk_autocorr( + opus_int32 *results, /* O Result (length correlationCount) */ + opus_int *scale, /* O Scaling of the correlation vector */ + const opus_int16 *inputData, /* I Input data to correlate */ + const opus_int inputDataSize, /* I Length of input */ + const opus_int correlationCount /* I Number of correlation taps to compute */ +); + +void silk_decode_pitch( + opus_int16 lagIndex, /* I */ + opus_int8 contourIndex, /* O */ + opus_int pitch_lags[], /* O 4 pitch values */ + const opus_int Fs_kHz, /* I sampling frequency (kHz) */ + const opus_int nb_subfr /* I number of sub frames */ +); + +opus_int silk_pitch_analysis_core( /* O Voicing estimate: 0 voiced, 1 unvoiced */ + const opus_int16 *frame, /* I Signal of length PE_FRAME_LENGTH_MS*Fs_kHz */ + opus_int *pitch_out, /* O 4 pitch lag values */ + opus_int16 *lagIndex, /* O Lag Index */ + opus_int8 *contourIndex, /* O Pitch contour Index */ + opus_int *LTPCorr_Q15, /* I/O Normalized correlation; input: value from previous frame */ + opus_int prevLag, /* I Last lag of previous frame; set to zero is unvoiced */ + const opus_int32 search_thres1_Q16, /* I First stage threshold for lag candidates 0 - 1 */ + const opus_int search_thres2_Q15, /* I Final threshold for lag candidates 0 - 1 */ + const opus_int Fs_kHz, /* I Sample frequency (kHz) */ + const opus_int complexity, /* I Complexity setting, 0-2, where 2 is highest */ + const opus_int nb_subfr /* I number of 5 ms subframes */ +); + +/* 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 silk_A2NLSF( + opus_int16 *NLSF, /* O Normalized Line Spectral Frequencies in Q15 (0..2^15-1) [d] */ + opus_int32 *a_Q16, /* I/O Monic whitening filter coefficients in Q16 [d] */ + const opus_int d /* I Filter order (must be even) */ +); + +/* compute whitening filter coefficients from normalized line spectral frequencies */ +void silk_NLSF2A( + opus_int16 *a_Q12, /* O monic whitening filter coefficients in Q12, [ d ] */ + const opus_int16 *NLSF, /* I normalized line spectral frequencies in Q15, [ d ] */ + const opus_int d /* I filter order (should be even) */ +); + +void silk_insertion_sort_increasing( + opus_int32 *a, /* I/O Unsorted / Sorted vector */ + opus_int *idx, /* O Index vector for the sorted elements */ + const opus_int L, /* I Vector length */ + const opus_int K /* I Number of correctly sorted positions */ +); + +void silk_insertion_sort_decreasing_int16( + opus_int16 *a, /* I/O Unsorted / Sorted vector */ + opus_int *idx, /* O Index vector for the sorted elements */ + const opus_int L, /* I Vector length */ + const opus_int K /* I Number of correctly sorted positions */ +); + +void silk_insertion_sort_increasing_all_values_int16( + opus_int16 *a, /* I/O Unsorted / Sorted vector */ + const opus_int L /* I Vector length */ +); + +/* NLSF stabilizer, for a single input data vector */ +void silk_NLSF_stabilize( + opus_int16 *NLSF_Q15, /* I/O Unstable/stabilized normalized LSF vector in Q15 [L] */ + const opus_int16 *NDeltaMin_Q15, /* I Min distance vector, NDeltaMin_Q15[L] must be >= 1 [L+1] */ + const opus_int L /* I Number of NLSF parameters in the input vector */ +); + +/* Laroia low complexity NLSF weights */ +void silk_NLSF_VQ_weights_laroia( + opus_int16 *pNLSFW_Q_OUT, /* O Pointer to input vector weights [D] */ + const opus_int16 *pNLSF_Q15, /* I Pointer to input vector [D] */ + const opus_int D /* I Input vector dimension (even) */ +); + +/* Compute reflection coefficients from input signal */ +void silk_burg_modified( + opus_int32 *res_nrg, /* O Residual energy */ + opus_int *res_nrg_Q, /* O Residual energy Q value */ + opus_int32 A_Q16[], /* O Prediction coefficients (length order) */ + const opus_int16 x[], /* I Input signal, length: nb_subfr * ( D + subfr_length ) */ + const opus_int32 minInvGain_Q30, /* I Inverse of max prediction gain */ + const opus_int subfr_length, /* I Input signal subframe length (incl. D preceding samples) */ + const opus_int nb_subfr, /* I Number of subframes stacked in x */ + const opus_int D /* I Order */ +); + +/* Copy and multiply a vector by a constant */ +void silk_scale_copy_vector16( + opus_int16 *data_out, + const opus_int16 *data_in, + opus_int32 gain_Q16, /* I Gain in Q16 */ + const opus_int dataSize /* I Length */ +); + +/* Some for the LTP related function requires Q26 to work.*/ +void silk_scale_vector32_Q26_lshift_18( + opus_int32 *data1, /* I/O Q0/Q18 */ + opus_int32 gain_Q26, /* I Q26 */ + opus_int dataSize /* I length */ +); + +/********************************************************************/ +/* INLINE ARM MATH */ +/********************************************************************/ + +/* return sum( inVec1[i] * inVec2[i] ) */ +opus_int32 silk_inner_prod_aligned( + const opus_int16 *const inVec1, /* I input vector 1 */ + const opus_int16 *const inVec2, /* I input vector 2 */ + const opus_int len /* I vector lengths */ +); + +opus_int32 silk_inner_prod_aligned_scale( + const opus_int16 *const inVec1, /* I input vector 1 */ + const opus_int16 *const inVec2, /* I input vector 2 */ + const opus_int scale, /* I number of bits to shift */ + const opus_int len /* I vector lengths */ +); + +opus_int64 silk_inner_prod16_aligned_64( + const opus_int16 *inVec1, /* I input vector 1 */ + const opus_int16 *inVec2, /* I input vector 2 */ + const opus_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 expression below and + compile it into a 'ror' instruction if available. No need for inline ASM! */ +static inline opus_int32 silk_ROR32( opus_int32 a32, opus_int rot ) +{ + opus_uint32 x = (opus_uint32) a32; + opus_uint32 r = (opus_uint32) rot; + opus_uint32 m = (opus_uint32) -rot; + if( rot == 0 ) { + return a32; + } else if( rot < 0 ) { + return (opus_int32) ((x << m) | (x >> (32 - m))); + } else { + return (opus_int32) ((x << (32 - r)) | (x >> r)); + } +} + +/* Allocate opus_int16 aligned to 4-byte memory address */ +#if EMBEDDED_ARM +#define silk_DWORD_ALIGN __attribute__((aligned(4))) +#else +#define silk_DWORD_ALIGN +#endif + +/* Useful Macros that can be adjusted to other platforms */ +#define silk_memcpy(dest, src, size) memcpy((dest), (src), (size)) +#define silk_memset(dest, src, size) memset((dest), (src), (size)) +#define silk_memmove(dest, src, size) memmove((dest), (src), (size)) + +/* Fixed point macros */ + +/* (a32 * b32) output have to be 32bit int */ +#define silk_MUL(a32, b32) ((a32) * (b32)) + +/* (a32 * b32) output have to be 32bit uint */ +#define silk_MUL_uint(a32, b32) silk_MUL(a32, b32) + +/* a32 + (b32 * c32) output have to be 32bit int */ +#define silk_MLA(a32, b32, c32) silk_ADD32((a32),((b32) * (c32))) + +/* a32 + (b32 * c32) output have to be 32bit uint */ +#define silk_MLA_uint(a32, b32, c32) silk_MLA(a32, b32, c32) + +/* ((a32 >> 16) * (b32 >> 16)) output have to be 32bit int */ +#define silk_SMULTT(a32, b32) (((a32) >> 16) * ((b32) >> 16)) + +/* a32 + ((a32 >> 16) * (b32 >> 16)) output have to be 32bit int */ +#define silk_SMLATT(a32, b32, c32) silk_ADD32((a32),((b32) >> 16) * ((c32) >> 16)) + +#define silk_SMLALBB(a64, b16, c16) silk_ADD64((a64),(opus_int64)((opus_int32)(b16) * (opus_int32)(c16))) + +/* (a32 * b32) */ +#define silk_SMULL(a32, b32) ((opus_int64)(a32) * /*(opus_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 silk_ADD32_ovflw(a, b) ((opus_int32)((opus_uint32)(a) + (opus_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 silk_SUB32_ovflw(a, b) ((opus_int32)((opus_uint32)(a) - (opus_uint32)(b))) + +/* Multiply-accumulate macros that allow overflow in the addition (ie, no asserts in debug mode) */ +#define silk_MLA_ovflw(a32, b32, c32) silk_ADD32_ovflw((a32), (opus_uint32)(b32) * (opus_uint32)(c32)) +#define silk_SMLABB_ovflw(a32, b32, c32) (silk_ADD32_ovflw((a32) , ((opus_int32)((opus_int16)(b32))) * (opus_int32)((opus_int16)(c32)))) + +#define silk_DIV32_16(a32, b16) ((opus_int32)((a32) / (b16))) +#define silk_DIV32(a32, b32) ((opus_int32)((a32) / (b32))) + +/* These macros enables checking for overflow in silk_API_Debug.h*/ +#define silk_ADD16(a, b) ((a) + (b)) +#define silk_ADD32(a, b) ((a) + (b)) +#define silk_ADD64(a, b) ((a) + (b)) + +#define silk_SUB16(a, b) ((a) - (b)) +#define silk_SUB32(a, b) ((a) - (b)) +#define silk_SUB64(a, b) ((a) - (b)) + +#define silk_SAT8(a) ((a) > silk_int8_MAX ? silk_int8_MAX : \ + ((a) < silk_int8_MIN ? silk_int8_MIN : (a))) +#define silk_SAT16(a) ((a) > silk_int16_MAX ? silk_int16_MAX : \ + ((a) < silk_int16_MIN ? silk_int16_MIN : (a))) +#define silk_SAT32(a) ((a) > silk_int32_MAX ? silk_int32_MAX : \ + ((a) < silk_int32_MIN ? silk_int32_MIN : (a))) + +#define silk_CHECK_FIT8(a) (a) +#define silk_CHECK_FIT16(a) (a) +#define silk_CHECK_FIT32(a) (a) + +#define silk_ADD_SAT16(a, b) (opus_int16)silk_SAT16( silk_ADD32( (opus_int32)(a), (b) ) ) +#define silk_ADD_SAT64(a, b) ((((a) + (b)) & 0x8000000000000000LL) == 0 ? \ + ((((a) & (b)) & 0x8000000000000000LL) != 0 ? silk_int64_MIN : (a)+(b)) : \ + ((((a) | (b)) & 0x8000000000000000LL) == 0 ? silk_int64_MAX : (a)+(b)) ) + +#define silk_SUB_SAT16(a, b) (opus_int16)silk_SAT16( silk_SUB32( (opus_int32)(a), (b) ) ) +#define silk_SUB_SAT64(a, b) ((((a)-(b)) & 0x8000000000000000LL) == 0 ? \ + (( (a) & ((b)^0x8000000000000000LL) & 0x8000000000000000LL) ? silk_int64_MIN : (a)-(b)) : \ + ((((a)^0x8000000000000000LL) & (b) & 0x8000000000000000LL) ? silk_int64_MAX : (a)-(b)) ) + +/* Saturation for positive input values */ +#define silk_POS_SAT32(a) ((a) > silk_int32_MAX ? silk_int32_MAX : (a)) + +/* Add with saturation for positive input values */ +#define silk_ADD_POS_SAT8(a, b) ((((a)+(b)) & 0x80) ? silk_int8_MAX : ((a)+(b))) +#define silk_ADD_POS_SAT16(a, b) ((((a)+(b)) & 0x8000) ? silk_int16_MAX : ((a)+(b))) +#define silk_ADD_POS_SAT32(a, b) ((((a)+(b)) & 0x80000000) ? silk_int32_MAX : ((a)+(b))) +#define silk_ADD_POS_SAT64(a, b) ((((a)+(b)) & 0x8000000000000000LL) ? silk_int64_MAX : ((a)+(b))) + +#define silk_LSHIFT8(a, shift) ((opus_int8)((opus_uint8)(a)<<(shift))) /* shift >= 0, shift < 8 */ +#define silk_LSHIFT16(a, shift) ((opus_int16)((opus_uint16)(a)<<(shift))) /* shift >= 0, shift < 16 */ +#define silk_LSHIFT32(a, shift) ((opus_int32)((opus_uint32)(a)<<(shift))) /* shift >= 0, shift < 32 */ +#define silk_LSHIFT64(a, shift) ((opus_int64)((opus_uint64)(a)<<(shift))) /* shift >= 0, shift < 64 */ +#define silk_LSHIFT(a, shift) silk_LSHIFT32(a, shift) /* shift >= 0, shift < 32 */ + +#define silk_RSHIFT8(a, shift) ((a)>>(shift)) /* shift >= 0, shift < 8 */ +#define silk_RSHIFT16(a, shift) ((a)>>(shift)) /* shift >= 0, shift < 16 */ +#define silk_RSHIFT32(a, shift) ((a)>>(shift)) /* shift >= 0, shift < 32 */ +#define silk_RSHIFT64(a, shift) ((a)>>(shift)) /* shift >= 0, shift < 64 */ +#define silk_RSHIFT(a, shift) silk_RSHIFT32(a, shift) /* shift >= 0, shift < 32 */ + +/* saturates before shifting */ +#define silk_LSHIFT_SAT32(a, shift) (silk_LSHIFT32( silk_LIMIT( (a), silk_RSHIFT32( silk_int32_MIN, (shift) ), \ + silk_RSHIFT32( silk_int32_MAX, (shift) ) ), (shift) )) + +#define silk_LSHIFT_ovflw(a, shift) ((opus_int32)((opus_uint32)(a) << (shift))) /* shift >= 0, allowed to overflow */ +#define silk_LSHIFT_uint(a, shift) ((a) << (shift)) /* shift >= 0 */ +#define silk_RSHIFT_uint(a, shift) ((a) >> (shift)) /* shift >= 0 */ + +#define silk_ADD_LSHIFT(a, b, shift) ((a) + silk_LSHIFT((b), (shift))) /* shift >= 0 */ +#define silk_ADD_LSHIFT32(a, b, shift) silk_ADD32((a), silk_LSHIFT32((b), (shift))) /* shift >= 0 */ +#define silk_ADD_LSHIFT_uint(a, b, shift) ((a) + silk_LSHIFT_uint((b), (shift))) /* shift >= 0 */ +#define silk_ADD_RSHIFT(a, b, shift) ((a) + silk_RSHIFT((b), (shift))) /* shift >= 0 */ +#define silk_ADD_RSHIFT32(a, b, shift) silk_ADD32((a), silk_RSHIFT32((b), (shift))) /* shift >= 0 */ +#define silk_ADD_RSHIFT_uint(a, b, shift) ((a) + silk_RSHIFT_uint((b), (shift))) /* shift >= 0 */ +#define silk_SUB_LSHIFT32(a, b, shift) silk_SUB32((a), silk_LSHIFT32((b), (shift))) /* shift >= 0 */ +#define silk_SUB_RSHIFT32(a, b, shift) silk_SUB32((a), silk_RSHIFT32((b), (shift))) /* shift >= 0 */ + +/* Requires that shift > 0 */ +#define silk_RSHIFT_ROUND(a, shift) ((shift) == 1 ? ((a) >> 1) + ((a) & 1) : (((a) >> ((shift) - 1)) + 1) >> 1) +#define silk_RSHIFT_ROUND64(a, shift) ((shift) == 1 ? ((a) >> 1) + ((a) & 1) : (((a) >> ((shift) - 1)) + 1) >> 1) + +/* Number of rightshift required to fit the multiplication */ +#define silk_NSHIFT_MUL_32_32(a, b) ( -(31- (32-silk_CLZ32(silk_abs(a)) + (32-silk_CLZ32(silk_abs(b))))) ) +#define silk_NSHIFT_MUL_16_16(a, b) ( -(15- (16-silk_CLZ16(silk_abs(a)) + (16-silk_CLZ16(silk_abs(b))))) ) + + +#define silk_min(a, b) (((a) < (b)) ? (a) : (b)) +#define silk_max(a, b) (((a) > (b)) ? (a) : (b)) + +/* Macro to convert floating-point constants to fixed-point */ +#define SILK_FIX_CONST( C, Q ) ((opus_int32)((C) * ((opus_int64)1 << (Q)) + 0.5)) + +/* silk_min() versions with typecast in the function call */ +static inline opus_int silk_min_int(opus_int a, opus_int b) +{ + return (((a) < (b)) ? (a) : (b)); +} +static inline opus_int16 silk_min_16(opus_int16 a, opus_int16 b) +{ + return (((a) < (b)) ? (a) : (b)); +} +static inline opus_int32 silk_min_32(opus_int32 a, opus_int32 b) +{ + return (((a) < (b)) ? (a) : (b)); +} +static inline opus_int64 silk_min_64(opus_int64 a, opus_int64 b) +{ + return (((a) < (b)) ? (a) : (b)); +} + +/* silk_min() versions with typecast in the function call */ +static inline opus_int silk_max_int(opus_int a, opus_int b) +{ + return (((a) > (b)) ? (a) : (b)); +} +static inline opus_int16 silk_max_16(opus_int16 a, opus_int16 b) +{ + return (((a) > (b)) ? (a) : (b)); +} +static inline opus_int32 silk_max_32(opus_int32 a, opus_int32 b) +{ + return (((a) > (b)) ? (a) : (b)); +} +static inline opus_int64 silk_max_64(opus_int64 a, opus_int64 b) +{ + return (((a) > (b)) ? (a) : (b)); +} + +#define silk_LIMIT( a, limit1, limit2) ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) \ + : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a)))) + +#define silk_LIMIT_int silk_LIMIT +#define silk_LIMIT_16 silk_LIMIT +#define silk_LIMIT_32 silk_LIMIT + +#define silk_abs(a) (((a) > 0) ? (a) : -(a)) /* Be careful, silk_abs returns wrong when input equals to silk_intXX_MIN */ +#define silk_abs_int(a) (((a) ^ ((a) >> (8 * sizeof(a) - 1))) - ((a) >> (8 * sizeof(a) - 1))) +#define silk_abs_int32(a) (((a) ^ ((a) >> 31)) - ((a) >> 31)) +#define silk_abs_int64(a) (((a) > 0) ? (a) : -(a)) + +#define silk_sign(a) ((a) > 0 ? 1 : ( (a) < 0 ? -1 : 0 )) + +/* 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. */ +#define silk_RAND(seed) (silk_MLA_ovflw(907633515, (seed), 196314165)) + +/* Add some multiplication functions that can be easily mapped to ARM. */ + +/* silk_SMMUL: Signed top word multiply. + ARMv6 2 instruction cycles. + ARMv3M+ 3 instruction cycles. use SMULL and ignore LSB registers.(except xM)*/ +/*#define silk_SMMUL(a32, b32) (opus_int32)silk_RSHIFT(silk_SMLAL(silk_SMULWB((a32), (b32)), (a32), silk_RSHIFT_ROUND((b32), 16)), 16)*/ +/* the following seems faster on x86 */ +#define silk_SMMUL(a32, b32) (opus_int32)silk_RSHIFT64(silk_SMULL((a32), (b32)), 32) + +#include "Inlines.h" +#include "MacroCount.h" +#include "MacroDebug.h" + +#ifdef __cplusplus +} +#endif + +#endif /* SILK_SIGPROC_FIX_H */ diff --git a/code/opus-1.0.2/silk/VAD.c b/code/opus-1.0.2/silk/VAD.c new file mode 100644 index 00000000..bac89b44 --- /dev/null +++ b/code/opus-1.0.2/silk/VAD.c @@ -0,0 +1,330 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Silk VAD noise level estimation */ +static inline void silk_VAD_GetNoiseLevels( + const opus_int32 pX[ VAD_N_BANDS ], /* I subband energies */ + silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */ +); + +/**********************************/ +/* Initialization of the Silk VAD */ +/**********************************/ +opus_int silk_VAD_Init( /* O Return value, 0 if success */ + silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */ +) +{ + opus_int b, ret = 0; + + /* reset state memory */ + silk_memset( psSilk_VAD, 0, sizeof( 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 ] = silk_max_32( silk_DIV32_16( VAD_NOISE_LEVELS_BIAS, b + 1 ), 1 ); + } + + /* Initialize state */ + for( b = 0; b < VAD_N_BANDS; b++ ) { + psSilk_VAD->NL[ b ] = silk_MUL( 100, psSilk_VAD->NoiseLevelBias[ b ] ); + psSilk_VAD->inv_NL[ b ] = silk_DIV32( silk_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 */ +static const opus_int32 tiltWeights[ VAD_N_BANDS ] = { 30000, 6000, -12000, -12000 }; + +/***************************************/ +/* Get the speech activity level in Q8 */ +/***************************************/ +opus_int silk_VAD_GetSA_Q8( /* O Return value, 0 if success */ + silk_encoder_state *psEncC, /* I/O Encoder state */ + const opus_int16 pIn[] /* I PCM input */ +) +{ + opus_int SA_Q15, pSNR_dB_Q7, input_tilt; + opus_int decimated_framelength, dec_subframe_length, dec_subframe_offset, SNR_Q7, i, b, s; + opus_int32 sumSquared, smooth_coef_Q16; + opus_int16 HPstateTmp; + opus_int16 X[ VAD_N_BANDS ][ MAX_FRAME_LENGTH / 2 ]; + opus_int32 Xnrg[ VAD_N_BANDS ]; + opus_int32 NrgToNoiseRatio_Q8[ VAD_N_BANDS ]; + opus_int32 speech_nrg, x_tmp; + opus_int ret = 0; + silk_VAD_state *psSilk_VAD = &psEncC->sVAD; + + /* Safety checks */ + silk_assert( VAD_N_BANDS == 4 ); + silk_assert( MAX_FRAME_LENGTH >= psEncC->frame_length ); + silk_assert( psEncC->frame_length <= 512 ); + silk_assert( psEncC->frame_length == 8 * silk_RSHIFT( psEncC->frame_length, 3 ) ); + + /***********************/ + /* Filter and Decimate */ + /***********************/ + /* 0-8 kHz to 0-4 kHz and 4-8 kHz */ + silk_ana_filt_bank_1( pIn, &psSilk_VAD->AnaState[ 0 ], &X[ 0 ][ 0 ], &X[ 3 ][ 0 ], psEncC->frame_length ); + + /* 0-4 kHz to 0-2 kHz and 2-4 kHz */ + silk_ana_filt_bank_1( &X[ 0 ][ 0 ], &psSilk_VAD->AnaState1[ 0 ], &X[ 0 ][ 0 ], &X[ 2 ][ 0 ], silk_RSHIFT( psEncC->frame_length, 1 ) ); + + /* 0-2 kHz to 0-1 kHz and 1-2 kHz */ + silk_ana_filt_bank_1( &X[ 0 ][ 0 ], &psSilk_VAD->AnaState2[ 0 ], &X[ 0 ][ 0 ], &X[ 1 ][ 0 ], silk_RSHIFT( psEncC->frame_length, 2 ) ); + + /*********************************************/ + /* HP filter on lowest band (differentiator) */ + /*********************************************/ + decimated_framelength = silk_RSHIFT( psEncC->frame_length, 3 ); + X[ 0 ][ decimated_framelength - 1 ] = silk_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 ] = silk_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 = silk_RSHIFT( psEncC->frame_length, silk_min_int( VAD_N_BANDS - b, VAD_N_BANDS - 1 ) ); + + /* Split length into subframe lengths */ + dec_subframe_length = silk_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 * ( silk_int16_MIN / 8 ) ^ 2. */ + /* Therefore we can accumulate with no risk of overflow (unless dec_subframe_length > 128) */ + x_tmp = silk_RSHIFT( X[ b ][ i + dec_subframe_offset ], 3 ); + sumSquared = silk_SMLABB( sumSquared, x_tmp, x_tmp ); + + /* Safety check */ + silk_assert( sumSquared >= 0 ); + } + + /* Add/saturate summed energy of current subframe */ + if( s < VAD_INTERNAL_SUBFRAMES - 1 ) { + Xnrg[ b ] = silk_ADD_POS_SAT32( Xnrg[ b ], sumSquared ); + } else { + /* Look-ahead subframe */ + Xnrg[ b ] = silk_ADD_POS_SAT32( Xnrg[ b ], silk_RSHIFT( sumSquared, 1 ) ); + } + + dec_subframe_offset += dec_subframe_length; + } + psSilk_VAD->XnrgSubfr[ b ] = sumSquared; + } + + /********************/ + /* Noise estimation */ + /********************/ + 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 ] = silk_DIV32( silk_LSHIFT( Xnrg[ b ], 8 ), psSilk_VAD->NL[ b ] + 1 ); + } else { + NrgToNoiseRatio_Q8[ b ] = silk_DIV32( Xnrg[ b ], silk_RSHIFT( psSilk_VAD->NL[ b ], 8 ) + 1 ); + } + + /* Convert to log domain */ + SNR_Q7 = silk_lin2log( NrgToNoiseRatio_Q8[ b ] ) - 8 * 128; + + /* Sum-of-squares */ + sumSquared = silk_SMLABB( sumSquared, SNR_Q7, SNR_Q7 ); /* Q14 */ + + /* Tilt measure */ + if( speech_nrg < ( (opus_int32)1 << 20 ) ) { + /* Scale down SNR value for small subband speech energies */ + SNR_Q7 = silk_SMULWB( silk_LSHIFT( silk_SQRT_APPROX( speech_nrg ), 6 ), SNR_Q7 ); + } + input_tilt = silk_SMLAWB( input_tilt, tiltWeights[ b ], SNR_Q7 ); + } else { + NrgToNoiseRatio_Q8[ b ] = 256; + } + } + + /* Mean-of-squares */ + sumSquared = silk_DIV32_16( sumSquared, VAD_N_BANDS ); /* Q14 */ + + /* Root-mean-square approximation, scale to dBs, and write to output pointer */ + pSNR_dB_Q7 = (opus_int16)( 3 * silk_SQRT_APPROX( sumSquared ) ); /* Q7 */ + + /*********************************/ + /* Speech Probability Estimation */ + /*********************************/ + SA_Q15 = silk_sigm_Q15( silk_SMULWB( VAD_SNR_FACTOR_Q16, pSNR_dB_Q7 ) - VAD_NEGATIVE_OFFSET_Q5 ); + + /**************************/ + /* Frequency Tilt Measure */ + /**************************/ + psEncC->input_tilt_Q15 = silk_LSHIFT( 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 ) * silk_RSHIFT( Xnrg[ b ] - psSilk_VAD->NL[ b ], 4 ); + } + + /* Power scaling */ + if( speech_nrg <= 0 ) { + SA_Q15 = silk_RSHIFT( SA_Q15, 1 ); + } else if( speech_nrg < 32768 ) { + if( psEncC->frame_length == 10 * psEncC->fs_kHz ) { + speech_nrg = silk_LSHIFT_SAT32( speech_nrg, 16 ); + } else { + speech_nrg = silk_LSHIFT_SAT32( speech_nrg, 15 ); + } + + /* square-root */ + speech_nrg = silk_SQRT_APPROX( speech_nrg ); + SA_Q15 = silk_SMULWB( 32768 + speech_nrg, SA_Q15 ); + } + + /* Copy the resulting speech activity in Q8 */ + psEncC->speech_activity_Q8 = silk_min_int( silk_RSHIFT( SA_Q15, 7 ), silk_uint8_MAX ); + + /***********************************/ + /* Energy Level and SNR estimation */ + /***********************************/ + /* Smoothing coefficient */ + smooth_coef_Q16 = silk_SMULWB( VAD_SNR_SMOOTH_COEF_Q18, silk_SMULWB( (opus_int32)SA_Q15, SA_Q15 ) ); + + if( psEncC->frame_length == 10 * psEncC->fs_kHz ) { + smooth_coef_Q16 >>= 1; + } + + for( b = 0; b < VAD_N_BANDS; b++ ) { + /* compute smoothed energy-to-noise ratio per band */ + psSilk_VAD->NrgRatioSmth_Q8[ b ] = silk_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 * ( silk_lin2log( psSilk_VAD->NrgRatioSmth_Q8[b] ) - 8 * 128 ); + /* quality = sigmoid( 0.25 * ( SNR_dB - 16 ) ); */ + psEncC->input_quality_bands_Q15[ b ] = silk_sigm_Q15( silk_RSHIFT( SNR_Q7 - 16 * 128, 4 ) ); + } + + return( ret ); +} + +/**************************/ +/* Noise level estimation */ +/**************************/ +static inline void silk_VAD_GetNoiseLevels( + const opus_int32 pX[ VAD_N_BANDS ], /* I subband energies */ + silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */ +) +{ + opus_int k; + opus_int32 nl, nrg, inv_nrg; + opus_int coef, min_coef; + + /* Initially faster smoothing */ + if( psSilk_VAD->counter < 1000 ) { /* 1000 = 20 sec */ + min_coef = silk_DIV32_16( silk_int16_MAX, silk_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 ]; + silk_assert( nl >= 0 ); + + /* Add bias */ + nrg = silk_ADD_POS_SAT32( pX[ k ], psSilk_VAD->NoiseLevelBias[ k ] ); + silk_assert( nrg > 0 ); + + /* Invert energies */ + inv_nrg = silk_DIV32( silk_int32_MAX, nrg ); + silk_assert( inv_nrg >= 0 ); + + /* Less update when subband energy is high */ + if( nrg > silk_LSHIFT( nl, 3 ) ) { + coef = VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 >> 3; + } else if( nrg < nl ) { + coef = VAD_NOISE_LEVEL_SMOOTH_COEF_Q16; + } else { + coef = silk_SMULWB( silk_SMULWW( inv_nrg, nl ), VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 << 1 ); + } + + /* Initially faster smoothing */ + coef = silk_max_int( coef, min_coef ); + + /* Smooth inverse energies */ + psSilk_VAD->inv_NL[ k ] = silk_SMLAWB( psSilk_VAD->inv_NL[ k ], inv_nrg - psSilk_VAD->inv_NL[ k ], coef ); + silk_assert( psSilk_VAD->inv_NL[ k ] >= 0 ); + + /* Compute noise level by inverting again */ + nl = silk_DIV32( silk_int32_MAX, psSilk_VAD->inv_NL[ k ] ); + silk_assert( nl >= 0 ); + + /* Limit noise levels (guarantee 7 bits of head room) */ + nl = silk_min( nl, 0x00FFFFFF ); + + /* Store as part of state */ + psSilk_VAD->NL[ k ] = nl; + } + + /* Increment frame counter */ + psSilk_VAD->counter++; +} diff --git a/code/opus-1.0.2/silk/VQ_WMat_EC.c b/code/opus-1.0.2/silk/VQ_WMat_EC.c new file mode 100644 index 00000000..a308cfbf --- /dev/null +++ b/code/opus-1.0.2/silk/VQ_WMat_EC.c @@ -0,0 +1,111 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Entropy constrained matrix-weighted VQ, hard-coded to 5-element vectors, for a single input data vector */ +void silk_VQ_WMat_EC( + opus_int8 *ind, /* O index of best codebook vector */ + opus_int32 *rate_dist_Q14, /* O best weighted quant error + mu * rate */ + const opus_int16 *in_Q14, /* I input vector to be quantized */ + const opus_int32 *W_Q18, /* I weighting matrix */ + const opus_int8 *cb_Q7, /* I codebook */ + const opus_uint8 *cl_Q5, /* I code length for each codebook vector */ + const opus_int mu_Q9, /* I tradeoff betw. weighted error and rate */ + opus_int L /* I number of vectors in codebook */ +) +{ + opus_int k; + const opus_int8 *cb_row_Q7; + opus_int16 diff_Q14[ 5 ]; + opus_int32 sum1_Q14, sum2_Q16; + + /* Loop over codebook */ + *rate_dist_Q14 = silk_int32_MAX; + cb_row_Q7 = cb_Q7; + for( k = 0; k < L; k++ ) { + diff_Q14[ 0 ] = in_Q14[ 0 ] - silk_LSHIFT( cb_row_Q7[ 0 ], 7 ); + diff_Q14[ 1 ] = in_Q14[ 1 ] - silk_LSHIFT( cb_row_Q7[ 1 ], 7 ); + diff_Q14[ 2 ] = in_Q14[ 2 ] - silk_LSHIFT( cb_row_Q7[ 2 ], 7 ); + diff_Q14[ 3 ] = in_Q14[ 3 ] - silk_LSHIFT( cb_row_Q7[ 3 ], 7 ); + diff_Q14[ 4 ] = in_Q14[ 4 ] - silk_LSHIFT( cb_row_Q7[ 4 ], 7 ); + + /* Weighted rate */ + sum1_Q14 = silk_SMULBB( mu_Q9, cl_Q5[ k ] ); + + silk_assert( sum1_Q14 >= 0 ); + + /* first row of W_Q18 */ + sum2_Q16 = silk_SMULWB( W_Q18[ 1 ], diff_Q14[ 1 ] ); + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 2 ], diff_Q14[ 2 ] ); + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 3 ], diff_Q14[ 3 ] ); + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 4 ], diff_Q14[ 4 ] ); + sum2_Q16 = silk_LSHIFT( sum2_Q16, 1 ); + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 0 ], diff_Q14[ 0 ] ); + sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 0 ] ); + + /* second row of W_Q18 */ + sum2_Q16 = silk_SMULWB( W_Q18[ 7 ], diff_Q14[ 2 ] ); + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 8 ], diff_Q14[ 3 ] ); + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 9 ], diff_Q14[ 4 ] ); + sum2_Q16 = silk_LSHIFT( sum2_Q16, 1 ); + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 6 ], diff_Q14[ 1 ] ); + sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 1 ] ); + + /* third row of W_Q18 */ + sum2_Q16 = silk_SMULWB( W_Q18[ 13 ], diff_Q14[ 3 ] ); + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 14 ], diff_Q14[ 4 ] ); + sum2_Q16 = silk_LSHIFT( sum2_Q16, 1 ); + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 12 ], diff_Q14[ 2 ] ); + sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 2 ] ); + + /* fourth row of W_Q18 */ + sum2_Q16 = silk_SMULWB( W_Q18[ 19 ], diff_Q14[ 4 ] ); + sum2_Q16 = silk_LSHIFT( sum2_Q16, 1 ); + sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 18 ], diff_Q14[ 3 ] ); + sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 3 ] ); + + /* last row of W_Q18 */ + sum2_Q16 = silk_SMULWB( W_Q18[ 24 ], diff_Q14[ 4 ] ); + sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 4 ] ); + + silk_assert( sum1_Q14 >= 0 ); + + /* find best */ + if( sum1_Q14 < *rate_dist_Q14 ) { + *rate_dist_Q14 = sum1_Q14; + *ind = (opus_int8)k; + } + + /* Go to next cbk vector */ + cb_row_Q7 += LTP_ORDER; + } +} diff --git a/code/opus-1.0.2/silk/ana_filt_bank_1.c b/code/opus-1.0.2/silk/ana_filt_bank_1.c new file mode 100644 index 00000000..4e04bef3 --- /dev/null +++ b/code/opus-1.0.2/silk/ana_filt_bank_1.c @@ -0,0 +1,74 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Coefficients for 2-band filter bank based on first-order allpass filters */ +static opus_int16 A_fb1_20 = 5394 << 1; +static opus_int16 A_fb1_21 = -24290; /* (opus_int16)(20623 << 1) */ + +/* Split signal into two decimated bands using first-order allpass filters */ +void silk_ana_filt_bank_1( + const opus_int16 *in, /* I Input signal [N] */ + opus_int32 *S, /* I/O State vector [2] */ + opus_int16 *outL, /* O Low band [N/2] */ + opus_int16 *outH, /* O High band [N/2] */ + const opus_int32 N /* I Number of input samples */ +) +{ + opus_int k, N2 = silk_RSHIFT( N, 1 ); + opus_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 = silk_LSHIFT( (opus_int32)in[ 2 * k ], 10 ); + + /* All-pass section for even input sample */ + Y = silk_SUB32( in32, S[ 0 ] ); + X = silk_SMLAWB( Y, Y, A_fb1_21 ); + out_1 = silk_ADD32( S[ 0 ], X ); + S[ 0 ] = silk_ADD32( in32, X ); + + /* Convert to Q10 */ + in32 = silk_LSHIFT( (opus_int32)in[ 2 * k + 1 ], 10 ); + + /* All-pass section for odd input sample, and add to output of previous section */ + Y = silk_SUB32( in32, S[ 1 ] ); + X = silk_SMULWB( Y, A_fb1_20 ); + out_2 = silk_ADD32( S[ 1 ], X ); + S[ 1 ] = silk_ADD32( in32, X ); + + /* Add/subtract, convert back to int16 and store to output */ + outL[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_ADD32( out_2, out_1 ), 11 ) ); + outH[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SUB32( out_2, out_1 ), 11 ) ); + } +} diff --git a/code/opus-1.0.2/silk/biquad_alt.c b/code/opus-1.0.2/silk/biquad_alt.c new file mode 100644 index 00000000..a639e21a --- /dev/null +++ b/code/opus-1.0.2/silk/biquad_alt.c @@ -0,0 +1,78 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * silk_biquad_alt.c * + * * + * Second order ARMA filter * + * Can handle slowly varying filter coefficients * + * */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Second order ARMA filter, alternative implementation */ +void silk_biquad_alt( + const opus_int16 *in, /* I input signal */ + const opus_int32 *B_Q28, /* I MA coefficients [3] */ + const opus_int32 *A_Q28, /* I AR coefficients [2] */ + opus_int32 *S, /* I/O State vector [2] */ + opus_int16 *out, /* O output signal */ + const opus_int32 len, /* I signal length (must be even) */ + opus_int stride /* I Operate on interleaved signal if > 1 */ +) +{ + /* DIRECT FORM II TRANSPOSED (uses 2 element state vector) */ + opus_int k; + opus_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 = silk_RSHIFT( -A_Q28[ 0 ], 14 ); /* upper part */ + A1_L_Q28 = ( -A_Q28[ 1 ] ) & 0x00003FFF; /* lower part */ + A1_U_Q28 = silk_RSHIFT( -A_Q28[ 1 ], 14 ); /* upper part */ + + for( k = 0; k < len; k++ ) { + /* S[ 0 ], S[ 1 ]: Q12 */ + inval = in[ k * stride ]; + out32_Q14 = silk_LSHIFT( silk_SMLAWB( S[ 0 ], B_Q28[ 0 ], inval ), 2 ); + + S[ 0 ] = S[1] + silk_RSHIFT_ROUND( silk_SMULWB( out32_Q14, A0_L_Q28 ), 14 ); + S[ 0 ] = silk_SMLAWB( S[ 0 ], out32_Q14, A0_U_Q28 ); + S[ 0 ] = silk_SMLAWB( S[ 0 ], B_Q28[ 1 ], inval); + + S[ 1 ] = silk_RSHIFT_ROUND( silk_SMULWB( out32_Q14, A1_L_Q28 ), 14 ); + S[ 1 ] = silk_SMLAWB( S[ 1 ], out32_Q14, A1_U_Q28 ); + S[ 1 ] = silk_SMLAWB( S[ 1 ], B_Q28[ 2 ], inval ); + + /* Scale back to Q0 and saturate */ + out[ k * stride ] = (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14 + (1<<14) - 1, 14 ) ); + } +} diff --git a/code/opus-1.0.2/silk/bwexpander.c b/code/opus-1.0.2/silk/bwexpander.c new file mode 100644 index 00000000..77ea1163 --- /dev/null +++ b/code/opus-1.0.2/silk/bwexpander.c @@ -0,0 +1,51 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Chirp (bandwidth expand) LP AR filter */ +void silk_bwexpander( + opus_int16 *ar, /* I/O AR filter to be expanded (without leading 1) */ + const opus_int d, /* I Length of ar */ + opus_int32 chirp_Q16 /* I Chirp factor (typically in the range 0 to 1) */ +) +{ + opus_int i; + opus_int32 chirp_minus_one_Q16 = chirp_Q16 - 65536; + + /* NB: Dont use silk_SMULWB, instead of silk_RSHIFT_ROUND( silk_MUL(), 16 ), below. */ + /* Bias in silk_SMULWB can lead to unstable filters */ + for( i = 0; i < d - 1; i++ ) { + ar[ i ] = (opus_int16)silk_RSHIFT_ROUND( silk_MUL( chirp_Q16, ar[ i ] ), 16 ); + chirp_Q16 += silk_RSHIFT_ROUND( silk_MUL( chirp_Q16, chirp_minus_one_Q16 ), 16 ); + } + ar[ d - 1 ] = (opus_int16)silk_RSHIFT_ROUND( silk_MUL( chirp_Q16, ar[ d - 1 ] ), 16 ); +} diff --git a/code/opus-1.0.2/silk/bwexpander_32.c b/code/opus-1.0.2/silk/bwexpander_32.c new file mode 100644 index 00000000..5ad92dd4 --- /dev/null +++ b/code/opus-1.0.2/silk/bwexpander_32.c @@ -0,0 +1,50 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Chirp (bandwidth expand) LP AR filter */ +void silk_bwexpander_32( + opus_int32 *ar, /* I/O AR filter to be expanded (without leading 1) */ + const opus_int d, /* I Length of ar */ + opus_int32 chirp_Q16 /* I Chirp factor in Q16 */ +) +{ + opus_int i; + opus_int32 chirp_minus_one_Q16 = chirp_Q16 - 65536; + + for( i = 0; i < d - 1; i++ ) { + ar[ i ] = silk_SMULWW( chirp_Q16, ar[ i ] ); + chirp_Q16 += silk_RSHIFT_ROUND( silk_MUL( chirp_Q16, chirp_minus_one_Q16 ), 16 ); + } + ar[ d - 1 ] = silk_SMULWW( chirp_Q16, ar[ d - 1 ] ); +} + diff --git a/code/opus-1.0.2/silk/check_control_input.c b/code/opus-1.0.2/silk/check_control_input.c new file mode 100644 index 00000000..972a480d --- /dev/null +++ b/code/opus-1.0.2/silk/check_control_input.c @@ -0,0 +1,106 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "control.h" +#include "errors.h" + +/* Check encoder control struct */ +opus_int check_control_input( + silk_EncControlStruct *encControl /* I Control structure */ +) +{ + silk_assert( encControl != NULL ); + + 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->desiredInternalSampleRate != 8000 ) && + ( encControl->desiredInternalSampleRate != 12000 ) && + ( encControl->desiredInternalSampleRate != 16000 ) ) || + ( ( encControl->maxInternalSampleRate != 8000 ) && + ( encControl->maxInternalSampleRate != 12000 ) && + ( encControl->maxInternalSampleRate != 16000 ) ) || + ( ( encControl->minInternalSampleRate != 8000 ) && + ( encControl->minInternalSampleRate != 12000 ) && + ( encControl->minInternalSampleRate != 16000 ) ) || + ( encControl->minInternalSampleRate > encControl->desiredInternalSampleRate ) || + ( encControl->maxInternalSampleRate < encControl->desiredInternalSampleRate ) || + ( encControl->minInternalSampleRate > encControl->maxInternalSampleRate ) ) { + silk_assert( 0 ); + return SILK_ENC_FS_NOT_SUPPORTED; + } + if( encControl->payloadSize_ms != 10 && + encControl->payloadSize_ms != 20 && + encControl->payloadSize_ms != 40 && + encControl->payloadSize_ms != 60 ) { + silk_assert( 0 ); + return SILK_ENC_PACKET_SIZE_NOT_SUPPORTED; + } + if( encControl->packetLossPercentage < 0 || encControl->packetLossPercentage > 100 ) { + silk_assert( 0 ); + return SILK_ENC_INVALID_LOSS_RATE; + } + if( encControl->useDTX < 0 || encControl->useDTX > 1 ) { + silk_assert( 0 ); + return SILK_ENC_INVALID_DTX_SETTING; + } + if( encControl->useCBR < 0 || encControl->useCBR > 1 ) { + silk_assert( 0 ); + return SILK_ENC_INVALID_CBR_SETTING; + } + if( encControl->useInBandFEC < 0 || encControl->useInBandFEC > 1 ) { + silk_assert( 0 ); + return SILK_ENC_INVALID_INBAND_FEC_SETTING; + } + if( encControl->nChannelsAPI < 1 || encControl->nChannelsAPI > ENCODER_NUM_CHANNELS ) { + silk_assert( 0 ); + return SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR; + } + if( encControl->nChannelsInternal < 1 || encControl->nChannelsInternal > ENCODER_NUM_CHANNELS ) { + silk_assert( 0 ); + return SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR; + } + if( encControl->nChannelsInternal > encControl->nChannelsAPI ) { + silk_assert( 0 ); + return SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR; + } + if( encControl->complexity < 0 || encControl->complexity > 10 ) { + silk_assert( 0 ); + return SILK_ENC_INVALID_COMPLEXITY_SETTING; + } + + return SILK_NO_ERROR; +} diff --git a/code/opus-1.0.2/silk/code_signs.c b/code/opus-1.0.2/silk/code_signs.c new file mode 100644 index 00000000..9893cdd8 --- /dev/null +++ b/code/opus-1.0.2/silk/code_signs.c @@ -0,0 +1,115 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/*#define silk_enc_map(a) ((a) > 0 ? 1 : 0)*/ +/*#define silk_dec_map(a) ((a) > 0 ? 1 : -1)*/ +/* shifting avoids if-statement */ +#define silk_enc_map(a) ( silk_RSHIFT( (a), 15 ) + 1 ) +#define silk_dec_map(a) ( silk_LSHIFT( (a), 1 ) - 1 ) + +/* Encodes signs of excitation */ +void silk_encode_signs( + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + const opus_int8 pulses[], /* I pulse signal */ + opus_int length, /* I length of input */ + const opus_int signalType, /* I Signal type */ + const opus_int quantOffsetType, /* I Quantization offset type */ + const opus_int sum_pulses[ MAX_NB_SHELL_BLOCKS ] /* I Sum of absolute pulses per block */ +) +{ + opus_int i, j, p; + opus_uint8 icdf[ 2 ]; + const opus_int8 *q_ptr; + const opus_uint8 *icdf_ptr; + + icdf[ 1 ] = 0; + q_ptr = pulses; + i = silk_SMULBB( 7, silk_ADD_LSHIFT( quantOffsetType, signalType, 1 ) ); + icdf_ptr = &silk_sign_iCDF[ i ]; + length = silk_RSHIFT( length + SHELL_CODEC_FRAME_LENGTH/2, LOG2_SHELL_CODEC_FRAME_LENGTH ); + for( i = 0; i < length; i++ ) { + p = sum_pulses[ i ]; + if( p > 0 ) { + icdf[ 0 ] = icdf_ptr[ silk_min( p & 0x1F, 6 ) ]; + for( j = 0; j < SHELL_CODEC_FRAME_LENGTH; j++ ) { + if( q_ptr[ j ] != 0 ) { + ec_enc_icdf( psRangeEnc, silk_enc_map( q_ptr[ j ]), icdf, 8 ); + } + } + } + q_ptr += SHELL_CODEC_FRAME_LENGTH; + } +} + +/* Decodes signs of excitation */ +void silk_decode_signs( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int pulses[], /* I/O pulse signal */ + opus_int length, /* I length of input */ + const opus_int signalType, /* I Signal type */ + const opus_int quantOffsetType, /* I Quantization offset type */ + const opus_int sum_pulses[ MAX_NB_SHELL_BLOCKS ] /* I Sum of absolute pulses per block */ +) +{ + opus_int i, j, p; + opus_uint8 icdf[ 2 ]; + opus_int *q_ptr; + const opus_uint8 *icdf_ptr; + + icdf[ 1 ] = 0; + q_ptr = pulses; + i = silk_SMULBB( 7, silk_ADD_LSHIFT( quantOffsetType, signalType, 1 ) ); + icdf_ptr = &silk_sign_iCDF[ i ]; + length = silk_RSHIFT( length + SHELL_CODEC_FRAME_LENGTH/2, LOG2_SHELL_CODEC_FRAME_LENGTH ); + for( i = 0; i < length; i++ ) { + p = sum_pulses[ i ]; + if( p > 0 ) { + icdf[ 0 ] = icdf_ptr[ silk_min( p & 0x1F, 6 ) ]; + for( j = 0; j < SHELL_CODEC_FRAME_LENGTH; j++ ) { + if( q_ptr[ j ] > 0 ) { + /* attach sign */ +#if 0 + /* conditional implementation */ + if( ec_dec_icdf( psRangeDec, icdf, 8 ) == 0 ) { + q_ptr[ j ] = -q_ptr[ j ]; + } +#else + /* implementation with shift, subtraction, multiplication */ + q_ptr[ j ] *= silk_dec_map( ec_dec_icdf( psRangeDec, icdf, 8 ) ); +#endif + } + } + } + q_ptr += SHELL_CODEC_FRAME_LENGTH; + } +} diff --git a/code/opus-1.0.2/silk/control.h b/code/opus-1.0.2/silk/control.h new file mode 100644 index 00000000..c52ec3fe --- /dev/null +++ b/code/opus-1.0.2/silk/control.h @@ -0,0 +1,139 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (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 SILK_CONTROL_H +#define SILK_CONTROL_H + +#include "typedef.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Decoder API flags */ +#define FLAG_DECODE_NORMAL 0 +#define FLAG_PACKET_LOST 1 +#define FLAG_DECODE_LBRR 2 + +/***********************************************/ +/* Structure for controlling encoder operation */ +/***********************************************/ +typedef struct { + /* I: Number of channels; 1/2 */ + opus_int32 nChannelsAPI; + + /* I: Number of channels; 1/2 */ + opus_int32 nChannelsInternal; + + /* I: Input signal sampling rate in Hertz; 8000/12000/16000/24000/32000/44100/48000 */ + opus_int32 API_sampleRate; + + /* I: Maximum internal sampling rate in Hertz; 8000/12000/16000 */ + opus_int32 maxInternalSampleRate; + + /* I: Minimum internal sampling rate in Hertz; 8000/12000/16000 */ + opus_int32 minInternalSampleRate; + + /* I: Soft request for internal sampling rate in Hertz; 8000/12000/16000 */ + opus_int32 desiredInternalSampleRate; + + /* I: Number of samples per packet in milliseconds; 10/20/40/60 */ + opus_int payloadSize_ms; + + /* I: Bitrate during active speech in bits/second; internally limited */ + opus_int32 bitRate; + + /* I: Uplink packet loss in percent (0-100) */ + opus_int packetLossPercentage; + + /* I: Complexity mode; 0 is lowest, 10 is highest complexity */ + opus_int complexity; + + /* I: Flag to enable in-band Forward Error Correction (FEC); 0/1 */ + opus_int useInBandFEC; + + /* I: Flag to enable discontinuous transmission (DTX); 0/1 */ + opus_int useDTX; + + /* I: Flag to use constant bitrate */ + opus_int useCBR; + + /* I: Maximum number of bits allowed for the frame */ + opus_int maxBits; + + /* I: Causes a smooth downmix to mono */ + opus_int toMono; + + /* I: Opus encoder is allowing us to switch bandwidth */ + opus_int opusCanSwitch; + + /* O: Internal sampling rate used, in Hertz; 8000/12000/16000 */ + opus_int32 internalSampleRate; + + /* O: Flag that bandwidth switching is allowed (because low voice activity) */ + opus_int allowBandwidthSwitch; + + /* O: Flag that SILK runs in WB mode without variable LP filter (use for switching between WB/SWB/FB) */ + opus_int inWBmodeWithoutVariableLP; + + /* O: Stereo width */ + opus_int stereoWidth_Q14; + + /* O: Tells the Opus encoder we're ready to switch */ + opus_int switchReady; + +} silk_EncControlStruct; + +/**************************************************************************/ +/* Structure for controlling decoder operation and reading decoder status */ +/**************************************************************************/ +typedef struct { + /* I: Number of channels; 1/2 */ + opus_int32 nChannelsAPI; + + /* I: Number of channels; 1/2 */ + opus_int32 nChannelsInternal; + + /* I: Output signal sampling rate in Hertz; 8000/12000/16000/24000/32000/44100/48000 */ + opus_int32 API_sampleRate; + + /* I: Internal sampling rate used, in Hertz; 8000/12000/16000 */ + opus_int32 internalSampleRate; + + /* I: Number of samples per packet in milliseconds; 10/20/40/60 */ + opus_int payloadSize_ms; + + /* O: Pitch lag of previous frame (0 if unvoiced), measured in samples at 48 kHz */ + opus_int prevPitchLag; +} silk_DecControlStruct; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/code/opus-1.0.2/silk/control_SNR.c b/code/opus-1.0.2/silk/control_SNR.c new file mode 100644 index 00000000..08e4e1a1 --- /dev/null +++ b/code/opus-1.0.2/silk/control_SNR.c @@ -0,0 +1,81 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "tuning_parameters.h" + +/* Control SNR of redidual quantizer */ +opus_int silk_control_SNR( + silk_encoder_state *psEncC, /* I/O Pointer to Silk encoder state */ + opus_int32 TargetRate_bps /* I Target max bitrate (bps) */ +) +{ + opus_int k, ret = SILK_NO_ERROR; + opus_int32 frac_Q6; + const opus_int32 *rateTable; + + /* Set bitrate/coding quality */ + TargetRate_bps = silk_LIMIT( TargetRate_bps, MIN_TARGET_RATE_BPS, MAX_TARGET_RATE_BPS ); + if( TargetRate_bps != psEncC->TargetRate_bps ) { + psEncC->TargetRate_bps = TargetRate_bps; + + /* If new TargetRate_bps, translate to SNR_dB value */ + if( psEncC->fs_kHz == 8 ) { + rateTable = silk_TargetRate_table_NB; + } else if( psEncC->fs_kHz == 12 ) { + rateTable = silk_TargetRate_table_MB; + } else { + rateTable = silk_TargetRate_table_WB; + } + + /* Reduce bitrate for 10 ms modes in these calculations */ + if( psEncC->nb_subfr == 2 ) { + TargetRate_bps -= REDUCE_BITRATE_10_MS_BPS; + } + + /* Find bitrate interval in table and interpolate */ + for( k = 1; k < TARGET_RATE_TAB_SZ; k++ ) { + if( TargetRate_bps <= rateTable[ k ] ) { + frac_Q6 = silk_DIV32( silk_LSHIFT( TargetRate_bps - rateTable[ k - 1 ], 6 ), + rateTable[ k ] - rateTable[ k - 1 ] ); + psEncC->SNR_dB_Q7 = silk_LSHIFT( silk_SNR_table_Q1[ k - 1 ], 6 ) + silk_MUL( frac_Q6, silk_SNR_table_Q1[ k ] - silk_SNR_table_Q1[ k - 1 ] ); + break; + } + } + + /* Reduce coding quality whenever LBRR is enabled, to free up some bits */ + if( psEncC->LBRR_enabled ) { + psEncC->SNR_dB_Q7 = silk_SMLABB( psEncC->SNR_dB_Q7, 12 - psEncC->LBRR_GainIncreases, SILK_FIX_CONST( -0.25, 7 ) ); + } + } + + return ret; +} diff --git a/code/opus-1.0.2/silk/control_audio_bandwidth.c b/code/opus-1.0.2/silk/control_audio_bandwidth.c new file mode 100644 index 00000000..b645dd57 --- /dev/null +++ b/code/opus-1.0.2/silk/control_audio_bandwidth.c @@ -0,0 +1,123 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "tuning_parameters.h" + +/* Control internal sampling rate */ +opus_int silk_control_audio_bandwidth( + silk_encoder_state *psEncC, /* I/O Pointer to Silk encoder state */ + silk_EncControlStruct *encControl /* I Control structure */ +) +{ + opus_int fs_kHz; + opus_int32 fs_Hz; + + fs_kHz = psEncC->fs_kHz; + fs_Hz = silk_SMULBB( fs_kHz, 1000 ); + if( fs_Hz == 0 ) { + /* Encoder has just been initialized */ + fs_Hz = silk_min( psEncC->desiredInternal_fs_Hz, psEncC->API_fs_Hz ); + fs_kHz = silk_DIV32_16( fs_Hz, 1000 ); + } else if( fs_Hz > psEncC->API_fs_Hz || fs_Hz > psEncC->maxInternal_fs_Hz || fs_Hz < psEncC->minInternal_fs_Hz ) { + /* Make sure internal rate is not higher than external rate or maximum allowed, or lower than minimum allowed */ + fs_Hz = psEncC->API_fs_Hz; + fs_Hz = silk_min( fs_Hz, psEncC->maxInternal_fs_Hz ); + fs_Hz = silk_max( fs_Hz, psEncC->minInternal_fs_Hz ); + fs_kHz = silk_DIV32_16( fs_Hz, 1000 ); + } else { + /* State machine for the internal sampling rate switching */ + if( psEncC->sLP.transition_frame_no >= TRANSITION_FRAMES ) { + /* Stop transition phase */ + psEncC->sLP.mode = 0; + } + if( psEncC->allow_bandwidth_switch || encControl->opusCanSwitch ) { + /* Check if we should switch down */ + if( silk_SMULBB( psEncC->fs_kHz, 1000 ) > psEncC->desiredInternal_fs_Hz ) + { + /* Switch down */ + if( psEncC->sLP.mode == 0 ) { + /* New transition */ + psEncC->sLP.transition_frame_no = TRANSITION_FRAMES; + + /* Reset transition filter state */ + silk_memset( psEncC->sLP.In_LP_State, 0, sizeof( psEncC->sLP.In_LP_State ) ); + } + if( encControl->opusCanSwitch ) { + /* Stop transition phase */ + psEncC->sLP.mode = 0; + + /* Switch to a lower sample frequency */ + fs_kHz = psEncC->fs_kHz == 16 ? 12 : 8; + } else { + if( psEncC->sLP.transition_frame_no <= 0 ) { + encControl->switchReady = 1; + /* Make room for redundancy */ + encControl->maxBits -= encControl->maxBits * 5 / ( encControl->payloadSize_ms + 5 ); + } else { + /* Direction: down (at double speed) */ + psEncC->sLP.mode = -2; + } + } + } + else + /* Check if we should switch up */ + if( silk_SMULBB( psEncC->fs_kHz, 1000 ) < psEncC->desiredInternal_fs_Hz ) + { + /* Switch up */ + if( encControl->opusCanSwitch ) { + /* Switch to a higher sample frequency */ + fs_kHz = psEncC->fs_kHz == 8 ? 12 : 16; + + /* New transition */ + psEncC->sLP.transition_frame_no = 0; + + /* Reset transition filter state */ + silk_memset( psEncC->sLP.In_LP_State, 0, sizeof( psEncC->sLP.In_LP_State ) ); + + /* Direction: up */ + psEncC->sLP.mode = 1; + } else { + if( psEncC->sLP.mode == 0 ) { + encControl->switchReady = 1; + /* Make room for redundancy */ + encControl->maxBits -= encControl->maxBits * 5 / ( encControl->payloadSize_ms + 5 ); + } else { + /* Direction: up */ + psEncC->sLP.mode = 1; + } + } + } + } + } + + return fs_kHz; +} diff --git a/code/opus-1.0.2/silk/control_codec.c b/code/opus-1.0.2/silk/control_codec.c new file mode 100644 index 00000000..ecc338ce --- /dev/null +++ b/code/opus-1.0.2/silk/control_codec.c @@ -0,0 +1,411 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef FIXED_POINT +#include "main_FIX.h" +#define silk_encoder_state_Fxx silk_encoder_state_FIX +#else +#include "main_FLP.h" +#define silk_encoder_state_Fxx silk_encoder_state_FLP +#endif +#include "tuning_parameters.h" +#include "pitch_est_defines.h" + +static opus_int silk_setup_resamplers( + silk_encoder_state_Fxx *psEnc, /* I/O */ + opus_int fs_kHz /* I */ +); + +static opus_int silk_setup_fs( + silk_encoder_state_Fxx *psEnc, /* I/O */ + opus_int fs_kHz, /* I */ + opus_int PacketSize_ms /* I */ +); + +static opus_int silk_setup_complexity( + silk_encoder_state *psEncC, /* I/O */ + opus_int Complexity /* I */ +); + +static inline opus_int silk_setup_LBRR( + silk_encoder_state *psEncC, /* I/O */ + const opus_int32 TargetRate_bps /* I */ +); + + +/* Control encoder */ +opus_int silk_control_encoder( + silk_encoder_state_Fxx *psEnc, /* I/O Pointer to Silk encoder state */ + silk_EncControlStruct *encControl, /* I Control structure */ + const opus_int32 TargetRate_bps, /* I Target max bitrate (bps) */ + const opus_int allow_bw_switch, /* I Flag to allow switching audio bandwidth */ + const opus_int channelNb, /* I Channel number */ + const opus_int force_fs_kHz +) +{ + opus_int fs_kHz, ret = 0; + + psEnc->sCmn.useDTX = encControl->useDTX; + psEnc->sCmn.useCBR = encControl->useCBR; + psEnc->sCmn.API_fs_Hz = encControl->API_sampleRate; + psEnc->sCmn.maxInternal_fs_Hz = encControl->maxInternalSampleRate; + psEnc->sCmn.minInternal_fs_Hz = encControl->minInternalSampleRate; + psEnc->sCmn.desiredInternal_fs_Hz = encControl->desiredInternalSampleRate; + psEnc->sCmn.useInBandFEC = encControl->useInBandFEC; + psEnc->sCmn.nChannelsAPI = encControl->nChannelsAPI; + psEnc->sCmn.nChannelsInternal = encControl->nChannelsInternal; + psEnc->sCmn.allow_bandwidth_switch = allow_bw_switch; + psEnc->sCmn.channelNb = channelNb; + + if( psEnc->sCmn.controlled_since_last_payload != 0 && psEnc->sCmn.prefillFlag == 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 += silk_setup_resamplers( psEnc, psEnc->sCmn.fs_kHz ); + } + return ret; + } + + /* Beyond this point we know that there are no previously coded frames in the payload buffer */ + + /********************************************/ + /* Determine internal sampling rate */ + /********************************************/ + fs_kHz = silk_control_audio_bandwidth( &psEnc->sCmn, encControl ); + if( force_fs_kHz ) { + fs_kHz = force_fs_kHz; + } + /********************************************/ + /* Prepare resampler and buffered data */ + /********************************************/ + ret += silk_setup_resamplers( psEnc, fs_kHz ); + + /********************************************/ + /* Set internal sampling frequency */ + /********************************************/ + ret += silk_setup_fs( psEnc, fs_kHz, encControl->payloadSize_ms ); + + /********************************************/ + /* Set encoding complexity */ + /********************************************/ + ret += silk_setup_complexity( &psEnc->sCmn, encControl->complexity ); + + /********************************************/ + /* Set packet loss rate measured by farend */ + /********************************************/ + psEnc->sCmn.PacketLoss_perc = encControl->packetLossPercentage; + + /********************************************/ + /* Set LBRR usage */ + /********************************************/ + ret += silk_setup_LBRR( &psEnc->sCmn, TargetRate_bps ); + + psEnc->sCmn.controlled_since_last_payload = 1; + + return ret; +} + +static opus_int silk_setup_resamplers( + silk_encoder_state_Fxx *psEnc, /* I/O */ + opus_int fs_kHz /* I */ +) +{ + opus_int ret = SILK_NO_ERROR; + opus_int32 nSamples_temp; + + 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 += silk_resampler_init( &psEnc->sCmn.resampler_state, psEnc->sCmn.API_fs_Hz, fs_kHz * 1000, 1 ); + } else { + /* Allocate worst case space for temporary upsampling, 8 to 48 kHz, so a factor 6 */ + opus_int16 x_buf_API_fs_Hz[ ( 2 * MAX_FRAME_LENGTH_MS + LA_SHAPE_MS ) * MAX_API_FS_KHZ ]; + silk_resampler_state_struct temp_resampler_state; +#ifdef FIXED_POINT + opus_int16 *x_bufFIX = psEnc->x_buf; +#else + opus_int16 x_bufFIX[ 2 * MAX_FRAME_LENGTH + LA_SHAPE_MAX ]; +#endif + + nSamples_temp = silk_LSHIFT( psEnc->sCmn.frame_length, 1 ) + LA_SHAPE_MS * psEnc->sCmn.fs_kHz; + +#ifndef FIXED_POINT + silk_float2short_array( x_bufFIX, psEnc->x_buf, nSamples_temp ); +#endif + + /* Initialize resampler for temporary resampling of x_buf data to API_fs_Hz */ + ret += silk_resampler_init( &temp_resampler_state, silk_SMULBB( psEnc->sCmn.fs_kHz, 1000 ), psEnc->sCmn.API_fs_Hz, 0 ); + + /* Temporary resampling of x_buf data to API_fs_Hz */ + ret += silk_resampler( &temp_resampler_state, x_buf_API_fs_Hz, x_bufFIX, nSamples_temp ); + + /* Calculate number of samples that has been temporarily upsampled */ + nSamples_temp = silk_DIV32_16( nSamples_temp * psEnc->sCmn.API_fs_Hz, silk_SMULBB( psEnc->sCmn.fs_kHz, 1000 ) ); + + /* Initialize the resampler for enc_API.c preparing resampling from API_fs_Hz to fs_kHz */ + ret += silk_resampler_init( &psEnc->sCmn.resampler_state, psEnc->sCmn.API_fs_Hz, silk_SMULBB( fs_kHz, 1000 ), 1 ); + + /* Correct resampler state by resampling buffered data from API_fs_Hz to fs_kHz */ + ret += silk_resampler( &psEnc->sCmn.resampler_state, x_bufFIX, x_buf_API_fs_Hz, nSamples_temp ); + +#ifndef FIXED_POINT + silk_short2float_array( psEnc->x_buf, x_bufFIX, ( 2 * MAX_FRAME_LENGTH_MS + LA_SHAPE_MS ) * fs_kHz ); +#endif + } + } + + psEnc->sCmn.prev_API_fs_Hz = psEnc->sCmn.API_fs_Hz; + + return ret; +} + +static opus_int silk_setup_fs( + silk_encoder_state_Fxx *psEnc, /* I/O */ + opus_int fs_kHz, /* I */ + opus_int PacketSize_ms /* I */ +) +{ + opus_int ret = SILK_NO_ERROR; + + /* Set packet size */ + if( PacketSize_ms != psEnc->sCmn.PacketSize_ms ) { + if( ( PacketSize_ms != 10 ) && + ( PacketSize_ms != 20 ) && + ( PacketSize_ms != 40 ) && + ( PacketSize_ms != 60 ) ) { + ret = SILK_ENC_PACKET_SIZE_NOT_SUPPORTED; + } + if( PacketSize_ms <= 10 ) { + psEnc->sCmn.nFramesPerPacket = 1; + psEnc->sCmn.nb_subfr = PacketSize_ms == 10 ? 2 : 1; + psEnc->sCmn.frame_length = silk_SMULBB( PacketSize_ms, fs_kHz ); + psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS_2_SF, fs_kHz ); + if( psEnc->sCmn.fs_kHz == 8 ) { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_NB_iCDF; + } else { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_iCDF; + } + } else { + psEnc->sCmn.nFramesPerPacket = silk_DIV32_16( PacketSize_ms, MAX_FRAME_LENGTH_MS ); + psEnc->sCmn.nb_subfr = MAX_NB_SUBFR; + psEnc->sCmn.frame_length = silk_SMULBB( 20, fs_kHz ); + psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS, fs_kHz ); + if( psEnc->sCmn.fs_kHz == 8 ) { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_NB_iCDF; + } else { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_iCDF; + } + } + psEnc->sCmn.PacketSize_ms = PacketSize_ms; + psEnc->sCmn.TargetRate_bps = 0; /* trigger new SNR computation */ + } + + /* Set internal sampling frequency */ + silk_assert( fs_kHz == 8 || fs_kHz == 12 || fs_kHz == 16 ); + silk_assert( psEnc->sCmn.nb_subfr == 2 || psEnc->sCmn.nb_subfr == 4 ); + if( psEnc->sCmn.fs_kHz != fs_kHz ) { + /* reset part of the state */ + silk_memset( &psEnc->sShape, 0, sizeof( psEnc->sShape ) ); + silk_memset( &psEnc->sPrefilt, 0, sizeof( psEnc->sPrefilt ) ); + silk_memset( &psEnc->sCmn.sNSQ, 0, sizeof( psEnc->sCmn.sNSQ ) ); + silk_memset( psEnc->sCmn.prev_NLSFq_Q15, 0, sizeof( psEnc->sCmn.prev_NLSFq_Q15 ) ); + silk_memset( &psEnc->sCmn.sLP.In_LP_State, 0, sizeof( psEnc->sCmn.sLP.In_LP_State ) ); + psEnc->sCmn.inputBufIx = 0; + psEnc->sCmn.nFramesEncoded = 0; + psEnc->sCmn.TargetRate_bps = 0; /* trigger new SNR computation */ + + /* Initialize non-zero parameters */ + psEnc->sCmn.prevLag = 100; + psEnc->sCmn.first_frame_after_reset = 1; + psEnc->sPrefilt.lagPrev = 100; + psEnc->sShape.LastGainIndex = 10; + psEnc->sCmn.sNSQ.lagPrev = 100; + psEnc->sCmn.sNSQ.prev_gain_Q16 = 65536; + psEnc->sCmn.prevSignalType = TYPE_NO_VOICE_ACTIVITY; + + psEnc->sCmn.fs_kHz = fs_kHz; + if( psEnc->sCmn.fs_kHz == 8 ) { + if( psEnc->sCmn.nb_subfr == MAX_NB_SUBFR ) { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_NB_iCDF; + } else { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_NB_iCDF; + } + } else { + if( psEnc->sCmn.nb_subfr == MAX_NB_SUBFR ) { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_iCDF; + } else { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_iCDF; + } + } + if( psEnc->sCmn.fs_kHz == 8 || psEnc->sCmn.fs_kHz == 12 ) { + psEnc->sCmn.predictLPCOrder = MIN_LPC_ORDER; + psEnc->sCmn.psNLSF_CB = &silk_NLSF_CB_NB_MB; + } else { + psEnc->sCmn.predictLPCOrder = MAX_LPC_ORDER; + psEnc->sCmn.psNLSF_CB = &silk_NLSF_CB_WB; + } + psEnc->sCmn.subfr_length = SUB_FRAME_LENGTH_MS * fs_kHz; + psEnc->sCmn.frame_length = silk_SMULBB( psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr ); + psEnc->sCmn.ltp_mem_length = silk_SMULBB( LTP_MEM_LENGTH_MS, fs_kHz ); + psEnc->sCmn.la_pitch = silk_SMULBB( LA_PITCH_MS, fs_kHz ); + psEnc->sCmn.max_pitch_lag = silk_SMULBB( 18, fs_kHz ); + if( psEnc->sCmn.nb_subfr == MAX_NB_SUBFR ) { + psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS, fs_kHz ); + } else { + psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS_2_SF, fs_kHz ); + } + if( psEnc->sCmn.fs_kHz == 16 ) { + psEnc->sCmn.mu_LTP_Q9 = SILK_FIX_CONST( MU_LTP_QUANT_WB, 9 ); + psEnc->sCmn.pitch_lag_low_bits_iCDF = silk_uniform8_iCDF; + } else if( psEnc->sCmn.fs_kHz == 12 ) { + psEnc->sCmn.mu_LTP_Q9 = SILK_FIX_CONST( MU_LTP_QUANT_MB, 9 ); + psEnc->sCmn.pitch_lag_low_bits_iCDF = silk_uniform6_iCDF; + } else { + psEnc->sCmn.mu_LTP_Q9 = SILK_FIX_CONST( MU_LTP_QUANT_NB, 9 ); + psEnc->sCmn.pitch_lag_low_bits_iCDF = silk_uniform4_iCDF; + } + } + + /* Check that settings are valid */ + silk_assert( ( psEnc->sCmn.subfr_length * psEnc->sCmn.nb_subfr ) == psEnc->sCmn.frame_length ); + + return ret; +} + +static opus_int silk_setup_complexity( + silk_encoder_state *psEncC, /* I/O */ + opus_int Complexity /* I */ +) +{ + opus_int ret = 0; + + /* Set encoding complexity */ + silk_assert( Complexity >= 0 && Complexity <= 10 ); + if( Complexity < 2 ) { + psEncC->pitchEstimationComplexity = SILK_PE_MIN_COMPLEX; + psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.8, 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 = 2; + psEncC->warping_Q16 = 0; + } else if( Complexity < 4 ) { + psEncC->pitchEstimationComplexity = SILK_PE_MID_COMPLEX; + psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.76, 16 ); + psEncC->pitchEstimationLPCOrder = 8; + psEncC->shapingLPCOrder = 10; + psEncC->la_shape = 5 * psEncC->fs_kHz; + psEncC->nStatesDelayedDecision = 1; + psEncC->useInterpolatedNLSFs = 0; + psEncC->LTPQuantLowComplexity = 0; + psEncC->NLSF_MSVQ_Survivors = 4; + psEncC->warping_Q16 = 0; + } else if( Complexity < 6 ) { + psEncC->pitchEstimationComplexity = SILK_PE_MID_COMPLEX; + psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.74, 16 ); + psEncC->pitchEstimationLPCOrder = 10; + psEncC->shapingLPCOrder = 12; + psEncC->la_shape = 5 * psEncC->fs_kHz; + psEncC->nStatesDelayedDecision = 2; + psEncC->useInterpolatedNLSFs = 1; + psEncC->LTPQuantLowComplexity = 0; + psEncC->NLSF_MSVQ_Survivors = 8; + psEncC->warping_Q16 = psEncC->fs_kHz * SILK_FIX_CONST( WARPING_MULTIPLIER, 16 ); + } else if( Complexity < 8 ) { + psEncC->pitchEstimationComplexity = SILK_PE_MID_COMPLEX; + psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.72, 16 ); + psEncC->pitchEstimationLPCOrder = 12; + psEncC->shapingLPCOrder = 14; + psEncC->la_shape = 5 * psEncC->fs_kHz; + psEncC->nStatesDelayedDecision = 3; + psEncC->useInterpolatedNLSFs = 1; + psEncC->LTPQuantLowComplexity = 0; + psEncC->NLSF_MSVQ_Survivors = 16; + psEncC->warping_Q16 = psEncC->fs_kHz * SILK_FIX_CONST( WARPING_MULTIPLIER, 16 ); + } else { + psEncC->pitchEstimationComplexity = SILK_PE_MAX_COMPLEX; + psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.7, 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 = 32; + psEncC->warping_Q16 = psEncC->fs_kHz * SILK_FIX_CONST( WARPING_MULTIPLIER, 16 ); + } + + /* Do not allow higher pitch estimation LPC order than predict LPC order */ + psEncC->pitchEstimationLPCOrder = silk_min_int( psEncC->pitchEstimationLPCOrder, psEncC->predictLPCOrder ); + psEncC->shapeWinLength = SUB_FRAME_LENGTH_MS * psEncC->fs_kHz + 2 * psEncC->la_shape; + psEncC->Complexity = Complexity; + + silk_assert( psEncC->pitchEstimationLPCOrder <= MAX_FIND_PITCH_LPC_ORDER ); + silk_assert( psEncC->shapingLPCOrder <= MAX_SHAPE_LPC_ORDER ); + silk_assert( psEncC->nStatesDelayedDecision <= MAX_DEL_DEC_STATES ); + silk_assert( psEncC->warping_Q16 <= 32767 ); + silk_assert( psEncC->la_shape <= LA_SHAPE_MAX ); + silk_assert( psEncC->shapeWinLength <= SHAPE_LPC_WIN_MAX ); + silk_assert( psEncC->NLSF_MSVQ_Survivors <= NLSF_VQ_MAX_SURVIVORS ); + + return ret; +} + +static inline opus_int silk_setup_LBRR( + silk_encoder_state *psEncC, /* I/O */ + const opus_int32 TargetRate_bps /* I */ +) +{ + opus_int ret = SILK_NO_ERROR; + opus_int32 LBRR_rate_thres_bps; + + psEncC->LBRR_enabled = 0; + if( psEncC->useInBandFEC && psEncC->PacketLoss_perc > 0 ) { + if( psEncC->fs_kHz == 8 ) { + LBRR_rate_thres_bps = LBRR_NB_MIN_RATE_BPS; + } else if( psEncC->fs_kHz == 12 ) { + LBRR_rate_thres_bps = LBRR_MB_MIN_RATE_BPS; + } else { + LBRR_rate_thres_bps = LBRR_WB_MIN_RATE_BPS; + } + LBRR_rate_thres_bps = silk_SMULWB( silk_MUL( LBRR_rate_thres_bps, 125 - silk_min( psEncC->PacketLoss_perc, 25 ) ), SILK_FIX_CONST( 0.01, 16 ) ); + + if( TargetRate_bps > LBRR_rate_thres_bps ) { + /* Set gain increase for coding LBRR excitation */ + psEncC->LBRR_enabled = 1; + psEncC->LBRR_GainIncreases = silk_max_int( 7 - silk_SMULWB( (opus_int32)psEncC->PacketLoss_perc, SILK_FIX_CONST( 0.4, 16 ) ), 2 ); + } + } + + return ret; +} diff --git a/code/opus-1.0.2/silk/debug.c b/code/opus-1.0.2/silk/debug.c new file mode 100644 index 00000000..9aa16cc8 --- /dev/null +++ b/code/opus-1.0.2/silk/debug.c @@ -0,0 +1,170 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "debug.h" +#include "SigProc_FIX.h" + +#if SILK_TIC_TOC + +#ifdef _WIN32 + +#if (defined(_WIN32) || defined(_WINCE)) +#include /* timer */ +#else /* Linux or Mac*/ +#include +#endif + +unsigned long silk_GetHighResolutionTime(void) /* O time in usec*/ +{ + /* Returns a time counter in microsec */ + /* the resolution is platform dependent */ + /* but is typically 1.62 us resolution */ + LARGE_INTEGER lpPerformanceCount; + LARGE_INTEGER lpFrequency; + QueryPerformanceCounter(&lpPerformanceCount); + QueryPerformanceFrequency(&lpFrequency); + return (unsigned long)((1000000*(lpPerformanceCount.QuadPart)) / lpFrequency.QuadPart); +} +#else /* Linux or Mac*/ +unsigned long GetHighResolutionTime(void) /* O time in usec*/ +{ + struct timeval tv; + gettimeofday(&tv, 0); + return((tv.tv_sec*1000000)+(tv.tv_usec)); +} +#endif + +int silk_Timer_nTimers = 0; +int silk_Timer_depth_ctr = 0; +char silk_Timer_tags[silk_NUM_TIMERS_MAX][silk_NUM_TIMERS_MAX_TAG_LEN]; +#ifdef WIN32 +LARGE_INTEGER silk_Timer_start[silk_NUM_TIMERS_MAX]; +#else +unsigned long silk_Timer_start[silk_NUM_TIMERS_MAX]; +#endif +unsigned int silk_Timer_cnt[silk_NUM_TIMERS_MAX]; +opus_int64 silk_Timer_min[silk_NUM_TIMERS_MAX]; +opus_int64 silk_Timer_sum[silk_NUM_TIMERS_MAX]; +opus_int64 silk_Timer_max[silk_NUM_TIMERS_MAX]; +opus_int64 silk_Timer_depth[silk_NUM_TIMERS_MAX]; + +#ifdef WIN32 +void silk_TimerSave(char *file_name) +{ + if( silk_Timer_nTimers > 0 ) + { + int k; + FILE *fp; + LARGE_INTEGER lpFrequency; + LARGE_INTEGER lpPerformanceCount1, lpPerformanceCount2; + int del = 0x7FFFFFFF; + double avg, sum_avg; + /* estimate overhead of calling performance counters */ + for( k = 0; k < 1000; k++ ) { + QueryPerformanceCounter(&lpPerformanceCount1); + QueryPerformanceCounter(&lpPerformanceCount2); + lpPerformanceCount2.QuadPart -= lpPerformanceCount1.QuadPart; + if( (int)lpPerformanceCount2.LowPart < del ) + del = lpPerformanceCount2.LowPart; + } + QueryPerformanceFrequency(&lpFrequency); + /* print results to file */ + sum_avg = 0.0f; + for( k = 0; k < silk_Timer_nTimers; k++ ) { + if (silk_Timer_depth[k] == 0) { + sum_avg += (1e6 * silk_Timer_sum[k] / silk_Timer_cnt[k] - del) / lpFrequency.QuadPart * silk_Timer_cnt[k]; + } + } + fp = fopen(file_name, "w"); + fprintf(fp, " min avg %% max count\n"); + for( k = 0; k < silk_Timer_nTimers; k++ ) { + if (silk_Timer_depth[k] == 0) { + fprintf(fp, "%-28s", silk_Timer_tags[k]); + } else if (silk_Timer_depth[k] == 1) { + fprintf(fp, " %-27s", silk_Timer_tags[k]); + } else if (silk_Timer_depth[k] == 2) { + fprintf(fp, " %-26s", silk_Timer_tags[k]); + } else if (silk_Timer_depth[k] == 3) { + fprintf(fp, " %-25s", silk_Timer_tags[k]); + } else { + fprintf(fp, " %-24s", silk_Timer_tags[k]); + } + avg = (1e6 * silk_Timer_sum[k] / silk_Timer_cnt[k] - del) / lpFrequency.QuadPart; + fprintf(fp, "%8.2f", (1e6 * (silk_max_64(silk_Timer_min[k] - del, 0))) / lpFrequency.QuadPart); + fprintf(fp, "%12.2f %6.2f", avg, 100.0 * avg / sum_avg * silk_Timer_cnt[k]); + fprintf(fp, "%12.2f", (1e6 * (silk_max_64(silk_Timer_max[k] - del, 0))) / lpFrequency.QuadPart); + fprintf(fp, "%10d\n", silk_Timer_cnt[k]); + } + fprintf(fp, " microseconds\n"); + fclose(fp); + } +} +#else +void silk_TimerSave(char *file_name) +{ + if( silk_Timer_nTimers > 0 ) + { + int k; + FILE *fp; + /* print results to file */ + fp = fopen(file_name, "w"); + fprintf(fp, " min avg max count\n"); + for( k = 0; k < silk_Timer_nTimers; k++ ) + { + if (silk_Timer_depth[k] == 0) { + fprintf(fp, "%-28s", silk_Timer_tags[k]); + } else if (silk_Timer_depth[k] == 1) { + fprintf(fp, " %-27s", silk_Timer_tags[k]); + } else if (silk_Timer_depth[k] == 2) { + fprintf(fp, " %-26s", silk_Timer_tags[k]); + } else if (silk_Timer_depth[k] == 3) { + fprintf(fp, " %-25s", silk_Timer_tags[k]); + } else { + fprintf(fp, " %-24s", silk_Timer_tags[k]); + } + fprintf(fp, "%d ", silk_Timer_min[k]); + fprintf(fp, "%f ", (double)silk_Timer_sum[k] / (double)silk_Timer_cnt[k]); + fprintf(fp, "%d ", silk_Timer_max[k]); + fprintf(fp, "%10d\n", silk_Timer_cnt[k]); + } + fprintf(fp, " microseconds\n"); + fclose(fp); + } +} +#endif + +#endif /* SILK_TIC_TOC */ + +#if SILK_DEBUG +FILE *silk_debug_store_fp[ silk_NUM_STORES_MAX ]; +int silk_debug_store_count = 0; +#endif /* SILK_DEBUG */ + diff --git a/code/opus-1.0.2/silk/debug.h b/code/opus-1.0.2/silk/debug.h new file mode 100644 index 00000000..8ae7094f --- /dev/null +++ b/code/opus-1.0.2/silk/debug.h @@ -0,0 +1,284 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (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 SILK_DEBUG_H +#define SILK_DEBUG_H + +#ifdef _WIN32 +#define _CRT_SECURE_NO_DEPRECATE 1 +#endif + +#include "typedef.h" +#include /* file writing */ +#include /* strcpy, strcmp */ + +#ifdef __cplusplus +extern "C" +{ +#endif + +unsigned long GetHighResolutionTime(void); /* O time in usec*/ + +/* make SILK_DEBUG dependent on compiler's _DEBUG */ +#if defined _WIN32 + #ifdef _DEBUG + #define SILK_DEBUG 1 + #else + #define SILK_DEBUG 0 + #endif + + /* overrule the above */ + #if 0 + /* #define NO_ASSERTS*/ + #undef SILK_DEBUG + #define SILK_DEBUG 1 + #endif +#else + #define SILK_DEBUG 0 +#endif + +/* Flag for using timers */ +#define SILK_TIC_TOC 0 + + +#if SILK_TIC_TOC + +#if (defined(_WIN32) || defined(_WINCE)) +#include /* timer */ +#pragma warning( disable : 4996 ) /* stop bitching about strcpy in TIC()*/ +#else /* Linux or Mac*/ +#include +#endif + +/*********************************/ +/* timer functions for profiling */ +/*********************************/ +/* example: */ +/* */ +/* TIC(LPC) */ +/* do_LPC(in_vec, order, acoef); // do LPC analysis */ +/* TOC(LPC) */ +/* */ +/* and call the following just before exiting (from main) */ +/* */ +/* silk_TimerSave("silk_TimingData.txt"); */ +/* */ +/* results are now in silk_TimingData.txt */ + +void silk_TimerSave(char *file_name); + +/* max number of timers (in different locations) */ +#define silk_NUM_TIMERS_MAX 50 +/* max length of name tags in TIC(..), TOC(..) */ +#define silk_NUM_TIMERS_MAX_TAG_LEN 30 + +extern int silk_Timer_nTimers; +extern int silk_Timer_depth_ctr; +extern char silk_Timer_tags[silk_NUM_TIMERS_MAX][silk_NUM_TIMERS_MAX_TAG_LEN]; +#ifdef _WIN32 +extern LARGE_INTEGER silk_Timer_start[silk_NUM_TIMERS_MAX]; +#else +extern unsigned long silk_Timer_start[silk_NUM_TIMERS_MAX]; +#endif +extern unsigned int silk_Timer_cnt[silk_NUM_TIMERS_MAX]; +extern opus_int64 silk_Timer_sum[silk_NUM_TIMERS_MAX]; +extern opus_int64 silk_Timer_max[silk_NUM_TIMERS_MAX]; +extern opus_int64 silk_Timer_min[silk_NUM_TIMERS_MAX]; +extern opus_int64 silk_Timer_depth[silk_NUM_TIMERS_MAX]; + +/* WARNING: TIC()/TOC can measure only up to 0.1 seconds at a time */ +#ifdef _WIN32 +#define TIC(TAG_NAME) { \ + static int init = 0; \ + static int ID = -1; \ + if( init == 0 ) \ + { \ + int k; \ + init = 1; \ + for( k = 0; k < silk_Timer_nTimers; k++ ) { \ + if( strcmp(silk_Timer_tags[k], #TAG_NAME) == 0 ) { \ + ID = k; \ + break; \ + } \ + } \ + if (ID == -1) { \ + ID = silk_Timer_nTimers; \ + silk_Timer_nTimers++; \ + silk_Timer_depth[ID] = silk_Timer_depth_ctr; \ + strcpy(silk_Timer_tags[ID], #TAG_NAME); \ + silk_Timer_cnt[ID] = 0; \ + silk_Timer_sum[ID] = 0; \ + silk_Timer_min[ID] = 0xFFFFFFFF; \ + silk_Timer_max[ID] = 0; \ + } \ + } \ + silk_Timer_depth_ctr++; \ + QueryPerformanceCounter(&silk_Timer_start[ID]); \ +} +#else +#define TIC(TAG_NAME) { \ + static int init = 0; \ + static int ID = -1; \ + if( init == 0 ) \ + { \ + int k; \ + init = 1; \ + for( k = 0; k < silk_Timer_nTimers; k++ ) { \ + if( strcmp(silk_Timer_tags[k], #TAG_NAME) == 0 ) { \ + ID = k; \ + break; \ + } \ + } \ + if (ID == -1) { \ + ID = silk_Timer_nTimers; \ + silk_Timer_nTimers++; \ + silk_Timer_depth[ID] = silk_Timer_depth_ctr; \ + strcpy(silk_Timer_tags[ID], #TAG_NAME); \ + silk_Timer_cnt[ID] = 0; \ + silk_Timer_sum[ID] = 0; \ + silk_Timer_min[ID] = 0xFFFFFFFF; \ + silk_Timer_max[ID] = 0; \ + } \ + } \ + silk_Timer_depth_ctr++; \ + silk_Timer_start[ID] = GetHighResolutionTime(); \ +} +#endif + +#ifdef _WIN32 +#define TOC(TAG_NAME) { \ + LARGE_INTEGER lpPerformanceCount; \ + static int init = 0; \ + static int ID = 0; \ + if( init == 0 ) \ + { \ + int k; \ + init = 1; \ + for( k = 0; k < silk_Timer_nTimers; k++ ) { \ + if( strcmp(silk_Timer_tags[k], #TAG_NAME) == 0 ) { \ + ID = k; \ + break; \ + } \ + } \ + } \ + QueryPerformanceCounter(&lpPerformanceCount); \ + lpPerformanceCount.QuadPart -= silk_Timer_start[ID].QuadPart; \ + if((lpPerformanceCount.QuadPart < 100000000) && \ + (lpPerformanceCount.QuadPart >= 0)) { \ + silk_Timer_cnt[ID]++; \ + silk_Timer_sum[ID] += lpPerformanceCount.QuadPart; \ + if( lpPerformanceCount.QuadPart > silk_Timer_max[ID] ) \ + silk_Timer_max[ID] = lpPerformanceCount.QuadPart; \ + if( lpPerformanceCount.QuadPart < silk_Timer_min[ID] ) \ + silk_Timer_min[ID] = lpPerformanceCount.QuadPart; \ + } \ + silk_Timer_depth_ctr--; \ +} +#else +#define TOC(TAG_NAME) { \ + unsigned long endTime; \ + static int init = 0; \ + static int ID = 0; \ + if( init == 0 ) \ + { \ + int k; \ + init = 1; \ + for( k = 0; k < silk_Timer_nTimers; k++ ) { \ + if( strcmp(silk_Timer_tags[k], #TAG_NAME) == 0 ) { \ + ID = k; \ + break; \ + } \ + } \ + } \ + endTime = GetHighResolutionTime(); \ + endTime -= silk_Timer_start[ID]; \ + if((endTime < 100000000) && \ + (endTime >= 0)) { \ + silk_Timer_cnt[ID]++; \ + silk_Timer_sum[ID] += endTime; \ + if( endTime > silk_Timer_max[ID] ) \ + silk_Timer_max[ID] = endTime; \ + if( endTime < silk_Timer_min[ID] ) \ + silk_Timer_min[ID] = endTime; \ + } \ + silk_Timer_depth_ctr--; \ +} +#endif + +#else /* SILK_TIC_TOC */ + +/* define macros as empty strings */ +#define TIC(TAG_NAME) +#define TOC(TAG_NAME) +#define silk_TimerSave(FILE_NAME) + +#endif /* SILK_TIC_TOC */ + + +#if SILK_DEBUG +/************************************/ +/* write data to file for debugging */ +/************************************/ +/* Example: DEBUG_STORE_DATA(testfile.pcm, &RIN[0], 160*sizeof(opus_int16)); */ + +#define silk_NUM_STORES_MAX 100 +extern FILE *silk_debug_store_fp[ silk_NUM_STORES_MAX ]; +extern int silk_debug_store_count; + +/* Faster way of storing the data */ +#define DEBUG_STORE_DATA( FILE_NAME, DATA_PTR, N_BYTES ) { \ + static opus_int init = 0, cnt = 0; \ + static FILE **fp; \ + if (init == 0) { \ + init = 1; \ + cnt = silk_debug_store_count++; \ + silk_debug_store_fp[ cnt ] = fopen(#FILE_NAME, "wb"); \ + } \ + fwrite((DATA_PTR), (N_BYTES), 1, silk_debug_store_fp[ cnt ]); \ +} + +/* Call this at the end of main() */ +#define SILK_DEBUG_STORE_CLOSE_FILES { \ + opus_int i; \ + for( i = 0; i < silk_debug_store_count; i++ ) { \ + fclose( silk_debug_store_fp[ i ] ); \ + } \ +} + +#else /* SILK_DEBUG */ + +/* define macros as empty strings */ +#define DEBUG_STORE_DATA(FILE_NAME, DATA_PTR, N_BYTES) +#define SILK_DEBUG_STORE_CLOSE_FILES + +#endif /* SILK_DEBUG */ + +#ifdef __cplusplus +} +#endif + +#endif /* SILK_DEBUG_H */ diff --git a/code/opus-1.0.2/silk/dec_API.c b/code/opus-1.0.2/silk/dec_API.c new file mode 100644 index 00000000..68403b7c --- /dev/null +++ b/code/opus-1.0.2/silk/dec_API.c @@ -0,0 +1,392 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "API.h" +#include "main.h" +#include "stack_alloc.h" + +/************************/ +/* Decoder Super Struct */ +/************************/ +typedef struct { + silk_decoder_state channel_state[ DECODER_NUM_CHANNELS ]; + stereo_dec_state sStereo; + opus_int nChannelsAPI; + opus_int nChannelsInternal; + opus_int prev_decode_only_middle; +} silk_decoder; + +/*********************/ +/* Decoder functions */ +/*********************/ + +opus_int silk_Get_Decoder_Size( /* O Returns error code */ + opus_int *decSizeBytes /* O Number of bytes in SILK decoder state */ +) +{ + opus_int ret = SILK_NO_ERROR; + + *decSizeBytes = sizeof( silk_decoder ); + + return ret; +} + +/* Reset decoder state */ +opus_int silk_InitDecoder( /* O Returns error code */ + void *decState /* I/O State */ +) +{ + opus_int n, ret = SILK_NO_ERROR; + silk_decoder_state *channel_state = ((silk_decoder *)decState)->channel_state; + + for( n = 0; n < DECODER_NUM_CHANNELS; n++ ) { + ret = silk_init_decoder( &channel_state[ n ] ); + } + + return ret; +} + +/* Decode a frame */ +opus_int silk_Decode( /* O Returns error code */ + void* decState, /* I/O State */ + silk_DecControlStruct* decControl, /* I/O Control Structure */ + opus_int lostFlag, /* I 0: no loss, 1 loss, 2 decode fec */ + opus_int newPacketFlag, /* I Indicates first decoder call for this packet */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int16 *samplesOut, /* O Decoded output speech vector */ + opus_int32 *nSamplesOut /* O Number of samples decoded */ +) +{ + opus_int i, n, decode_only_middle = 0, ret = SILK_NO_ERROR; + opus_int32 nSamplesOutDec, LBRR_symbol; + opus_int16 *samplesOut1_tmp[ 2 ]; + VARDECL( opus_int16, samplesOut1_tmp_storage ); + VARDECL( opus_int16, samplesOut2_tmp ); + opus_int32 MS_pred_Q13[ 2 ] = { 0 }; + opus_int16 *resample_out_ptr; + silk_decoder *psDec = ( silk_decoder * )decState; + silk_decoder_state *channel_state = psDec->channel_state; + opus_int has_side; + opus_int stereo_to_mono; + SAVE_STACK; + + /**********************************/ + /* Test if first frame in payload */ + /**********************************/ + if( newPacketFlag ) { + for( n = 0; n < decControl->nChannelsInternal; n++ ) { + channel_state[ n ].nFramesDecoded = 0; /* Used to count frames in packet */ + } + } + + /* If Mono -> Stereo transition in bitstream: init state of second channel */ + if( decControl->nChannelsInternal > psDec->nChannelsInternal ) { + ret += silk_init_decoder( &channel_state[ 1 ] ); + } + + stereo_to_mono = decControl->nChannelsInternal == 1 && psDec->nChannelsInternal == 2 && + ( decControl->internalSampleRate == 1000*channel_state[ 0 ].fs_kHz ); + + if( channel_state[ 0 ].nFramesDecoded == 0 ) { + for( n = 0; n < decControl->nChannelsInternal; n++ ) { + opus_int fs_kHz_dec; + if( decControl->payloadSize_ms == 0 ) { + /* Assuming packet loss, use 10 ms */ + channel_state[ n ].nFramesPerPacket = 1; + channel_state[ n ].nb_subfr = 2; + } else if( decControl->payloadSize_ms == 10 ) { + channel_state[ n ].nFramesPerPacket = 1; + channel_state[ n ].nb_subfr = 2; + } else if( decControl->payloadSize_ms == 20 ) { + channel_state[ n ].nFramesPerPacket = 1; + channel_state[ n ].nb_subfr = 4; + } else if( decControl->payloadSize_ms == 40 ) { + channel_state[ n ].nFramesPerPacket = 2; + channel_state[ n ].nb_subfr = 4; + } else if( decControl->payloadSize_ms == 60 ) { + channel_state[ n ].nFramesPerPacket = 3; + channel_state[ n ].nb_subfr = 4; + } else { + silk_assert( 0 ); + RESTORE_STACK; + return SILK_DEC_INVALID_FRAME_SIZE; + } + fs_kHz_dec = ( decControl->internalSampleRate >> 10 ) + 1; + if( fs_kHz_dec != 8 && fs_kHz_dec != 12 && fs_kHz_dec != 16 ) { + silk_assert( 0 ); + RESTORE_STACK; + return SILK_DEC_INVALID_SAMPLING_FREQUENCY; + } + ret += silk_decoder_set_fs( &channel_state[ n ], fs_kHz_dec, decControl->API_sampleRate ); + } + } + + if( decControl->nChannelsAPI == 2 && decControl->nChannelsInternal == 2 && ( psDec->nChannelsAPI == 1 || psDec->nChannelsInternal == 1 ) ) { + silk_memset( psDec->sStereo.pred_prev_Q13, 0, sizeof( psDec->sStereo.pred_prev_Q13 ) ); + silk_memset( psDec->sStereo.sSide, 0, sizeof( psDec->sStereo.sSide ) ); + silk_memcpy( &channel_state[ 1 ].resampler_state, &channel_state[ 0 ].resampler_state, sizeof( silk_resampler_state_struct ) ); + } + psDec->nChannelsAPI = decControl->nChannelsAPI; + psDec->nChannelsInternal = decControl->nChannelsInternal; + + if( decControl->API_sampleRate > (opus_int32)MAX_API_FS_KHZ * 1000 || decControl->API_sampleRate < 8000 ) { + ret = SILK_DEC_INVALID_SAMPLING_FREQUENCY; + RESTORE_STACK; + return( ret ); + } + + if( lostFlag != FLAG_PACKET_LOST && channel_state[ 0 ].nFramesDecoded == 0 ) { + /* First decoder call for this payload */ + /* Decode VAD flags and LBRR flag */ + for( n = 0; n < decControl->nChannelsInternal; n++ ) { + for( i = 0; i < channel_state[ n ].nFramesPerPacket; i++ ) { + channel_state[ n ].VAD_flags[ i ] = ec_dec_bit_logp(psRangeDec, 1); + } + channel_state[ n ].LBRR_flag = ec_dec_bit_logp(psRangeDec, 1); + } + /* Decode LBRR flags */ + for( n = 0; n < decControl->nChannelsInternal; n++ ) { + silk_memset( channel_state[ n ].LBRR_flags, 0, sizeof( channel_state[ n ].LBRR_flags ) ); + if( channel_state[ n ].LBRR_flag ) { + if( channel_state[ n ].nFramesPerPacket == 1 ) { + channel_state[ n ].LBRR_flags[ 0 ] = 1; + } else { + LBRR_symbol = ec_dec_icdf( psRangeDec, silk_LBRR_flags_iCDF_ptr[ channel_state[ n ].nFramesPerPacket - 2 ], 8 ) + 1; + for( i = 0; i < channel_state[ n ].nFramesPerPacket; i++ ) { + channel_state[ n ].LBRR_flags[ i ] = silk_RSHIFT( LBRR_symbol, i ) & 1; + } + } + } + } + + if( lostFlag == FLAG_DECODE_NORMAL ) { + /* Regular decoding: skip all LBRR data */ + for( i = 0; i < channel_state[ 0 ].nFramesPerPacket; i++ ) { + for( n = 0; n < decControl->nChannelsInternal; n++ ) { + if( channel_state[ n ].LBRR_flags[ i ] ) { + opus_int pulses[ MAX_FRAME_LENGTH ]; + opus_int condCoding; + + if( decControl->nChannelsInternal == 2 && n == 0 ) { + silk_stereo_decode_pred( psRangeDec, MS_pred_Q13 ); + if( channel_state[ 1 ].LBRR_flags[ i ] == 0 ) { + silk_stereo_decode_mid_only( psRangeDec, &decode_only_middle ); + } + } + /* Use conditional coding if previous frame available */ + if( i > 0 && channel_state[ n ].LBRR_flags[ i - 1 ] ) { + condCoding = CODE_CONDITIONALLY; + } else { + condCoding = CODE_INDEPENDENTLY; + } + silk_decode_indices( &channel_state[ n ], psRangeDec, i, 1, condCoding ); + silk_decode_pulses( psRangeDec, pulses, channel_state[ n ].indices.signalType, + channel_state[ n ].indices.quantOffsetType, channel_state[ n ].frame_length ); + } + } + } + } + } + + /* Get MS predictor index */ + if( decControl->nChannelsInternal == 2 ) { + if( lostFlag == FLAG_DECODE_NORMAL || + ( lostFlag == FLAG_DECODE_LBRR && channel_state[ 0 ].LBRR_flags[ channel_state[ 0 ].nFramesDecoded ] == 1 ) ) + { + silk_stereo_decode_pred( psRangeDec, MS_pred_Q13 ); + /* For LBRR data, decode mid-only flag only if side-channel's LBRR flag is false */ + if( ( lostFlag == FLAG_DECODE_NORMAL && channel_state[ 1 ].VAD_flags[ channel_state[ 0 ].nFramesDecoded ] == 0 ) || + ( lostFlag == FLAG_DECODE_LBRR && channel_state[ 1 ].LBRR_flags[ channel_state[ 0 ].nFramesDecoded ] == 0 ) ) + { + silk_stereo_decode_mid_only( psRangeDec, &decode_only_middle ); + } else { + decode_only_middle = 0; + } + } else { + for( n = 0; n < 2; n++ ) { + MS_pred_Q13[ n ] = psDec->sStereo.pred_prev_Q13[ n ]; + } + } + } + + /* Reset side channel decoder prediction memory for first frame with side coding */ + if( decControl->nChannelsInternal == 2 && decode_only_middle == 0 && psDec->prev_decode_only_middle == 1 ) { + silk_memset( psDec->channel_state[ 1 ].outBuf, 0, sizeof(psDec->channel_state[ 1 ].outBuf) ); + silk_memset( psDec->channel_state[ 1 ].sLPC_Q14_buf, 0, sizeof(psDec->channel_state[ 1 ].sLPC_Q14_buf) ); + psDec->channel_state[ 1 ].lagPrev = 100; + psDec->channel_state[ 1 ].LastGainIndex = 10; + psDec->channel_state[ 1 ].prevSignalType = TYPE_NO_VOICE_ACTIVITY; + psDec->channel_state[ 1 ].first_frame_after_reset = 1; + } + + ALLOC( samplesOut1_tmp_storage, + decControl->nChannelsInternal*( + channel_state[ 0 ].frame_length + 2 ), + opus_int16 ); + samplesOut1_tmp[ 0 ] = samplesOut1_tmp_storage; + samplesOut1_tmp[ 1 ] = samplesOut1_tmp_storage + + channel_state[ 0 ].frame_length + 2; + + if( lostFlag == FLAG_DECODE_NORMAL ) { + has_side = !decode_only_middle; + } else { + has_side = !psDec->prev_decode_only_middle + || (decControl->nChannelsInternal == 2 && lostFlag == FLAG_DECODE_LBRR && channel_state[1].LBRR_flags[ channel_state[1].nFramesDecoded ] == 1 ); + } + /* Call decoder for one frame */ + for( n = 0; n < decControl->nChannelsInternal; n++ ) { + if( n == 0 || has_side ) { + opus_int FrameIndex; + opus_int condCoding; + + FrameIndex = channel_state[ 0 ].nFramesDecoded - n; + /* Use independent coding if no previous frame available */ + if( FrameIndex <= 0 ) { + condCoding = CODE_INDEPENDENTLY; + } else if( lostFlag == FLAG_DECODE_LBRR ) { + condCoding = channel_state[ n ].LBRR_flags[ FrameIndex - 1 ] ? CODE_CONDITIONALLY : CODE_INDEPENDENTLY; + } else if( n > 0 && psDec->prev_decode_only_middle ) { + /* If we skipped a side frame in this packet, we don't + need LTP scaling; the LTP state is well-defined. */ + condCoding = CODE_INDEPENDENTLY_NO_LTP_SCALING; + } else { + condCoding = CODE_CONDITIONALLY; + } + ret += silk_decode_frame( &channel_state[ n ], psRangeDec, &samplesOut1_tmp[ n ][ 2 ], &nSamplesOutDec, lostFlag, condCoding); + } else { + silk_memset( &samplesOut1_tmp[ n ][ 2 ], 0, nSamplesOutDec * sizeof( opus_int16 ) ); + } + channel_state[ n ].nFramesDecoded++; + } + + if( decControl->nChannelsAPI == 2 && decControl->nChannelsInternal == 2 ) { + /* Convert Mid/Side to Left/Right */ + silk_stereo_MS_to_LR( &psDec->sStereo, samplesOut1_tmp[ 0 ], samplesOut1_tmp[ 1 ], MS_pred_Q13, channel_state[ 0 ].fs_kHz, nSamplesOutDec ); + } else { + /* Buffering */ + silk_memcpy( samplesOut1_tmp[ 0 ], psDec->sStereo.sMid, 2 * sizeof( opus_int16 ) ); + silk_memcpy( psDec->sStereo.sMid, &samplesOut1_tmp[ 0 ][ nSamplesOutDec ], 2 * sizeof( opus_int16 ) ); + } + + /* Number of output samples */ + *nSamplesOut = silk_DIV32( nSamplesOutDec * decControl->API_sampleRate, silk_SMULBB( channel_state[ 0 ].fs_kHz, 1000 ) ); + + /* Set up pointers to temp buffers */ + ALLOC( samplesOut2_tmp, + decControl->nChannelsAPI == 2 ? *nSamplesOut : 0, opus_int16 ); + if( decControl->nChannelsAPI == 2 ) { + resample_out_ptr = samplesOut2_tmp; + } else { + resample_out_ptr = samplesOut; + } + + for( n = 0; n < silk_min( decControl->nChannelsAPI, decControl->nChannelsInternal ); n++ ) { + + /* Resample decoded signal to API_sampleRate */ + ret += silk_resampler( &channel_state[ n ].resampler_state, resample_out_ptr, &samplesOut1_tmp[ n ][ 1 ], nSamplesOutDec ); + + /* Interleave if stereo output and stereo stream */ + if( decControl->nChannelsAPI == 2 ) { + for( i = 0; i < *nSamplesOut; i++ ) { + samplesOut[ n + 2 * i ] = resample_out_ptr[ i ]; + } + } + } + + /* Create two channel output from mono stream */ + if( decControl->nChannelsAPI == 2 && decControl->nChannelsInternal == 1 ) { + if ( stereo_to_mono ){ + /* Resample right channel for newly collapsed stereo just in case + we weren't doing collapsing when switching to mono */ + ret += silk_resampler( &channel_state[ 1 ].resampler_state, resample_out_ptr, &samplesOut1_tmp[ 0 ][ 1 ], nSamplesOutDec ); + + for( i = 0; i < *nSamplesOut; i++ ) { + samplesOut[ 1 + 2 * i ] = resample_out_ptr[ i ]; + } + } else { + for( i = 0; i < *nSamplesOut; i++ ) { + samplesOut[ 1 + 2 * i ] = samplesOut[ 0 + 2 * i ]; + } + } + } + + /* Export pitch lag, measured at 48 kHz sampling rate */ + if( channel_state[ 0 ].prevSignalType == TYPE_VOICED ) { + int mult_tab[ 3 ] = { 6, 4, 3 }; + decControl->prevPitchLag = channel_state[ 0 ].lagPrev * mult_tab[ ( channel_state[ 0 ].fs_kHz - 8 ) >> 2 ]; + } else { + decControl->prevPitchLag = 0; + } + + if( lostFlag == FLAG_PACKET_LOST ) { + /* On packet loss, remove the gain clamping to prevent having the energy "bounce back" + if we lose packets when the energy is going down */ + for ( i = 0; i < psDec->nChannelsInternal; i++ ) + psDec->channel_state[ i ].LastGainIndex = 10; + } else { + psDec->prev_decode_only_middle = decode_only_middle; + } + RESTORE_STACK; + return ret; +} + +#if 0 +/* Getting table of contents for a packet */ +opus_int silk_get_TOC( + const opus_uint8 *payload, /* I Payload data */ + const opus_int nBytesIn, /* I Number of input bytes */ + const opus_int nFramesPerPayload, /* I Number of SILK frames per payload */ + silk_TOC_struct *Silk_TOC /* O Type of content */ +) +{ + opus_int i, flags, ret = SILK_NO_ERROR; + + if( nBytesIn < 1 ) { + return -1; + } + if( nFramesPerPayload < 0 || nFramesPerPayload > 3 ) { + return -1; + } + + silk_memset( Silk_TOC, 0, sizeof( *Silk_TOC ) ); + + /* For stereo, extract the flags for the mid channel */ + flags = silk_RSHIFT( payload[ 0 ], 7 - nFramesPerPayload ) & ( silk_LSHIFT( 1, nFramesPerPayload + 1 ) - 1 ); + + Silk_TOC->inbandFECFlag = flags & 1; + for( i = nFramesPerPayload - 1; i >= 0 ; i-- ) { + flags = silk_RSHIFT( flags, 1 ); + Silk_TOC->VADFlags[ i ] = flags & 1; + Silk_TOC->VADFlag |= flags & 1; + } + + return ret; +} +#endif diff --git a/code/opus-1.0.2/silk/decode_core.c b/code/opus-1.0.2/silk/decode_core.c new file mode 100644 index 00000000..0365ffdf --- /dev/null +++ b/code/opus-1.0.2/silk/decode_core.c @@ -0,0 +1,238 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "stack_alloc.h" + +/**********************************************************/ +/* Core decoder. Performs inverse NSQ operation LTP + LPC */ +/**********************************************************/ +void silk_decode_core( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I Decoder control */ + opus_int16 xq[], /* O Decoded speech */ + const opus_int pulses[ MAX_FRAME_LENGTH ] /* I Pulse signal */ +) +{ + opus_int i, k, lag = 0, start_idx, sLTP_buf_idx, NLSF_interpolation_flag, signalType; + opus_int16 *A_Q12, *B_Q14, *pxq, A_Q12_tmp[ MAX_LPC_ORDER ]; + VARDECL( opus_int16, sLTP ); + VARDECL( opus_int32, sLTP_Q15 ); + opus_int32 LTP_pred_Q13, LPC_pred_Q10, Gain_Q10, inv_gain_Q31, gain_adj_Q16, rand_seed, offset_Q10; + opus_int32 *pred_lag_ptr, *pexc_Q14, *pres_Q14; + VARDECL( opus_int32, res_Q14 ); + VARDECL( opus_int32, sLPC_Q14 ); + SAVE_STACK; + + silk_assert( psDec->prev_gain_Q16 != 0 ); + + ALLOC( sLTP, psDec->ltp_mem_length, opus_int16 ); + ALLOC( sLTP_Q15, psDec->ltp_mem_length + psDec->frame_length, opus_int32 ); + ALLOC( res_Q14, psDec->subfr_length, opus_int32 ); + ALLOC( sLPC_Q14, psDec->subfr_length + MAX_LPC_ORDER, opus_int32 ); + + offset_Q10 = silk_Quantization_Offsets_Q10[ psDec->indices.signalType >> 1 ][ psDec->indices.quantOffsetType ]; + + if( psDec->indices.NLSFInterpCoef_Q2 < 1 << 2 ) { + NLSF_interpolation_flag = 1; + } else { + NLSF_interpolation_flag = 0; + } + + /* Decode excitation */ + rand_seed = psDec->indices.Seed; + for( i = 0; i < psDec->frame_length; i++ ) { + rand_seed = silk_RAND( rand_seed ); + psDec->exc_Q14[ i ] = silk_LSHIFT( (opus_int32)pulses[ i ], 14 ); + if( psDec->exc_Q14[ i ] > 0 ) { + psDec->exc_Q14[ i ] -= QUANT_LEVEL_ADJUST_Q10 << 4; + } else + if( psDec->exc_Q14[ i ] < 0 ) { + psDec->exc_Q14[ i ] += QUANT_LEVEL_ADJUST_Q10 << 4; + } + psDec->exc_Q14[ i ] += offset_Q10 << 4; + if( rand_seed < 0 ) { + psDec->exc_Q14[ i ] = -psDec->exc_Q14[ i ]; + } + + rand_seed = silk_ADD32_ovflw( rand_seed, pulses[ i ] ); + } + + /* Copy LPC state */ + silk_memcpy( sLPC_Q14, psDec->sLPC_Q14_buf, MAX_LPC_ORDER * sizeof( opus_int32 ) ); + + pexc_Q14 = psDec->exc_Q14; + pxq = xq; + sLTP_buf_idx = psDec->ltp_mem_length; + /* Loop over subframes */ + for( k = 0; k < psDec->nb_subfr; k++ ) { + pres_Q14 = res_Q14; + A_Q12 = psDecCtrl->PredCoef_Q12[ k >> 1 ]; + + /* Preload LPC coeficients to array on stack. Gives small performance gain */ + silk_memcpy( A_Q12_tmp, A_Q12, psDec->LPC_order * sizeof( opus_int16 ) ); + B_Q14 = &psDecCtrl->LTPCoef_Q14[ k * LTP_ORDER ]; + signalType = psDec->indices.signalType; + + Gain_Q10 = silk_RSHIFT( psDecCtrl->Gains_Q16[ k ], 6 ); + inv_gain_Q31 = silk_INVERSE32_varQ( psDecCtrl->Gains_Q16[ k ], 47 ); + + /* Calculate gain adjustment factor */ + if( psDecCtrl->Gains_Q16[ k ] != psDec->prev_gain_Q16 ) { + gain_adj_Q16 = silk_DIV32_varQ( psDec->prev_gain_Q16, psDecCtrl->Gains_Q16[ k ], 16 ); + + /* Scale short term state */ + for( i = 0; i < MAX_LPC_ORDER; i++ ) { + sLPC_Q14[ i ] = silk_SMULWW( gain_adj_Q16, sLPC_Q14[ i ] ); + } + } else { + gain_adj_Q16 = (opus_int32)1 << 16; + } + + /* Save inv_gain */ + silk_assert( inv_gain_Q31 != 0 ); + psDec->prev_gain_Q16 = psDecCtrl->Gains_Q16[ k ]; + + /* Avoid abrupt transition from voiced PLC to unvoiced normal decoding */ + if( psDec->lossCnt && psDec->prevSignalType == TYPE_VOICED && + psDec->indices.signalType != TYPE_VOICED && k < MAX_NB_SUBFR/2 ) { + + silk_memset( B_Q14, 0, LTP_ORDER * sizeof( opus_int16 ) ); + B_Q14[ LTP_ORDER/2 ] = SILK_FIX_CONST( 0.25, 14 ); + + signalType = TYPE_VOICED; + psDecCtrl->pitchL[ k ] = psDec->lagPrev; + } + + if( signalType == TYPE_VOICED ) { + /* Voiced */ + lag = psDecCtrl->pitchL[ k ]; + + /* Re-whitening */ + if( k == 0 || ( k == 2 && NLSF_interpolation_flag ) ) { + /* Rewhiten with new A coefs */ + start_idx = psDec->ltp_mem_length - lag - psDec->LPC_order - LTP_ORDER / 2; + silk_assert( start_idx > 0 ); + + if( k == 2 ) { + silk_memcpy( &psDec->outBuf[ psDec->ltp_mem_length ], xq, 2 * psDec->subfr_length * sizeof( opus_int16 ) ); + } + + silk_LPC_analysis_filter( &sLTP[ start_idx ], &psDec->outBuf[ start_idx + k * psDec->subfr_length ], + A_Q12, psDec->ltp_mem_length - start_idx, psDec->LPC_order ); + + /* After rewhitening the LTP state is unscaled */ + if( k == 0 ) { + /* Do LTP downscaling to reduce inter-packet dependency */ + inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, psDecCtrl->LTP_scale_Q14 ), 2 ); + } + for( i = 0; i < lag + LTP_ORDER/2; i++ ) { + sLTP_Q15[ sLTP_buf_idx - i - 1 ] = silk_SMULWB( inv_gain_Q31, sLTP[ psDec->ltp_mem_length - i - 1 ] ); + } + } else { + /* Update LTP state when Gain changes */ + if( gain_adj_Q16 != (opus_int32)1 << 16 ) { + for( i = 0; i < lag + LTP_ORDER/2; i++ ) { + sLTP_Q15[ sLTP_buf_idx - i - 1 ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ sLTP_buf_idx - i - 1 ] ); + } + } + } + } + + /* Long-term prediction */ + if( signalType == TYPE_VOICED ) { + /* Set up pointer */ + pred_lag_ptr = &sLTP_Q15[ sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + for( i = 0; i < psDec->subfr_length; i++ ) { + /* Unrolled loop */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LTP_pred_Q13 = 2; + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ 0 ], B_Q14[ 0 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -1 ], B_Q14[ 1 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -2 ], B_Q14[ 2 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -3 ], B_Q14[ 3 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -4 ], B_Q14[ 4 ] ); + pred_lag_ptr++; + + /* Generate LPC excitation */ + pres_Q14[ i ] = silk_ADD_LSHIFT32( pexc_Q14[ i ], LTP_pred_Q13, 1 ); + + /* Update states */ + sLTP_Q15[ sLTP_buf_idx ] = silk_LSHIFT( pres_Q14[ i ], 1 ); + sLTP_buf_idx++; + } + } else { + pres_Q14 = pexc_Q14; + } + + for( i = 0; i < psDec->subfr_length; i++ ) { + /* Short-term prediction */ + silk_assert( psDec->LPC_order == 10 || psDec->LPC_order == 16 ); + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LPC_pred_Q10 = silk_RSHIFT( psDec->LPC_order, 1 ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 1 ], A_Q12_tmp[ 0 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 2 ], A_Q12_tmp[ 1 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 3 ], A_Q12_tmp[ 2 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 4 ], A_Q12_tmp[ 3 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 5 ], A_Q12_tmp[ 4 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 6 ], A_Q12_tmp[ 5 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 7 ], A_Q12_tmp[ 6 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 8 ], A_Q12_tmp[ 7 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 9 ], A_Q12_tmp[ 8 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 10 ], A_Q12_tmp[ 9 ] ); + if( psDec->LPC_order == 16 ) { + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 11 ], A_Q12_tmp[ 10 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 12 ], A_Q12_tmp[ 11 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 13 ], A_Q12_tmp[ 12 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 14 ], A_Q12_tmp[ 13 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 15 ], A_Q12_tmp[ 14 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 16 ], A_Q12_tmp[ 15 ] ); + } + + /* Add prediction to LPC excitation */ + sLPC_Q14[ MAX_LPC_ORDER + i ] = silk_ADD_LSHIFT32( pres_Q14[ i ], LPC_pred_Q10, 4 ); + + /* Scale with gain */ + pxq[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( sLPC_Q14[ MAX_LPC_ORDER + i ], Gain_Q10 ), 8 ) ); + } + + /* DEBUG_STORE_DATA( dec.pcm, pxq, psDec->subfr_length * sizeof( opus_int16 ) ) */ + + /* Update LPC filter state */ + silk_memcpy( sLPC_Q14, &sLPC_Q14[ psDec->subfr_length ], MAX_LPC_ORDER * sizeof( opus_int32 ) ); + pexc_Q14 += psDec->subfr_length; + pxq += psDec->subfr_length; + } + + /* Save LPC state */ + silk_memcpy( psDec->sLPC_Q14_buf, sLPC_Q14, MAX_LPC_ORDER * sizeof( opus_int32 ) ); + RESTORE_STACK; +} diff --git a/code/opus-1.0.2/silk/decode_frame.c b/code/opus-1.0.2/silk/decode_frame.c new file mode 100644 index 00000000..3e4a6e2b --- /dev/null +++ b/code/opus-1.0.2/silk/decode_frame.c @@ -0,0 +1,128 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" +#include "stack_alloc.h" +#include "PLC.h" + +/****************/ +/* Decode frame */ +/****************/ +opus_int silk_decode_frame( + silk_decoder_state *psDec, /* I/O Pointer to Silk decoder state */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int16 pOut[], /* O Pointer to output speech frame */ + opus_int32 *pN, /* O Pointer to size of output frame */ + opus_int lostFlag, /* I 0: no loss, 1 loss, 2 decode fec */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + VARDECL( silk_decoder_control, psDecCtrl ); + opus_int L, mv_len, ret = 0; + VARDECL( opus_int, pulses ); + SAVE_STACK; + + L = psDec->frame_length; + ALLOC( psDecCtrl, 1, silk_decoder_control ); + ALLOC( pulses, (L + SHELL_CODEC_FRAME_LENGTH - 1) & + ~(SHELL_CODEC_FRAME_LENGTH - 1), opus_int ); + psDecCtrl->LTP_scale_Q14 = 0; + + /* Safety checks */ + silk_assert( L > 0 && L <= MAX_FRAME_LENGTH ); + + if( lostFlag == FLAG_DECODE_NORMAL || + ( lostFlag == FLAG_DECODE_LBRR && psDec->LBRR_flags[ psDec->nFramesDecoded ] == 1 ) ) + { + /*********************************************/ + /* Decode quantization indices of side info */ + /*********************************************/ + silk_decode_indices( psDec, psRangeDec, psDec->nFramesDecoded, lostFlag, condCoding ); + + /*********************************************/ + /* Decode quantization indices of excitation */ + /*********************************************/ + silk_decode_pulses( psRangeDec, pulses, psDec->indices.signalType, + psDec->indices.quantOffsetType, psDec->frame_length ); + + /********************************************/ + /* Decode parameters and pulse signal */ + /********************************************/ + silk_decode_parameters( psDec, psDecCtrl, condCoding ); + + /********************************************************/ + /* Run inverse NSQ */ + /********************************************************/ + silk_decode_core( psDec, psDecCtrl, pOut, pulses ); + + /********************************************************/ + /* Update PLC state */ + /********************************************************/ + silk_PLC( psDec, psDecCtrl, pOut, 0 ); + + psDec->lossCnt = 0; + psDec->prevSignalType = psDec->indices.signalType; + silk_assert( psDec->prevSignalType >= 0 && psDec->prevSignalType <= 2 ); + + /* A frame has been decoded without errors */ + psDec->first_frame_after_reset = 0; + } else { + /* Handle packet loss by extrapolation */ + silk_PLC( psDec, psDecCtrl, pOut, 1 ); + } + + /*************************/ + /* Update output buffer. */ + /*************************/ + silk_assert( psDec->ltp_mem_length >= psDec->frame_length ); + mv_len = psDec->ltp_mem_length - psDec->frame_length; + silk_memmove( psDec->outBuf, &psDec->outBuf[ psDec->frame_length ], mv_len * sizeof(opus_int16) ); + silk_memcpy( &psDec->outBuf[ mv_len ], pOut, psDec->frame_length * sizeof( opus_int16 ) ); + + /****************************************************************/ + /* Ensure smooth connection of extrapolated and good frames */ + /****************************************************************/ + silk_PLC_glue_frames( psDec, pOut, L ); + + /************************************************/ + /* Comfort noise generation / estimation */ + /************************************************/ + silk_CNG( psDec, psDecCtrl, pOut, L ); + + /* Update some decoder state variables */ + psDec->lagPrev = psDecCtrl->pitchL[ psDec->nb_subfr - 1 ]; + + /* Set output frame length */ + *pN = L; + + RESTORE_STACK; + return ret; +} diff --git a/code/opus-1.0.2/silk/decode_indices.c b/code/opus-1.0.2/silk/decode_indices.c new file mode 100644 index 00000000..69172102 --- /dev/null +++ b/code/opus-1.0.2/silk/decode_indices.c @@ -0,0 +1,151 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Decode side-information parameters from payload */ +void silk_decode_indices( + silk_decoder_state *psDec, /* I/O State */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int FrameIndex, /* I Frame number */ + opus_int decode_LBRR, /* I Flag indicating LBRR data is being decoded */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + opus_int i, k, Ix; + opus_int decode_absolute_lagIndex, delta_lagIndex; + opus_int16 ec_ix[ MAX_LPC_ORDER ]; + opus_uint8 pred_Q8[ MAX_LPC_ORDER ]; + + /*******************************************/ + /* Decode signal type and quantizer offset */ + /*******************************************/ + if( decode_LBRR || psDec->VAD_flags[ FrameIndex ] ) { + Ix = ec_dec_icdf( psRangeDec, silk_type_offset_VAD_iCDF, 8 ) + 2; + } else { + Ix = ec_dec_icdf( psRangeDec, silk_type_offset_no_VAD_iCDF, 8 ); + } + psDec->indices.signalType = (opus_int8)silk_RSHIFT( Ix, 1 ); + psDec->indices.quantOffsetType = (opus_int8)( Ix & 1 ); + + /****************/ + /* Decode gains */ + /****************/ + /* First subframe */ + if( condCoding == CODE_CONDITIONALLY ) { + /* Conditional coding */ + psDec->indices.GainsIndices[ 0 ] = (opus_int8)ec_dec_icdf( psRangeDec, silk_delta_gain_iCDF, 8 ); + } else { + /* Independent coding, in two stages: MSB bits followed by 3 LSBs */ + psDec->indices.GainsIndices[ 0 ] = (opus_int8)silk_LSHIFT( ec_dec_icdf( psRangeDec, silk_gain_iCDF[ psDec->indices.signalType ], 8 ), 3 ); + psDec->indices.GainsIndices[ 0 ] += (opus_int8)ec_dec_icdf( psRangeDec, silk_uniform8_iCDF, 8 ); + } + + /* Remaining subframes */ + for( i = 1; i < psDec->nb_subfr; i++ ) { + psDec->indices.GainsIndices[ i ] = (opus_int8)ec_dec_icdf( psRangeDec, silk_delta_gain_iCDF, 8 ); + } + + /**********************/ + /* Decode LSF Indices */ + /**********************/ + psDec->indices.NLSFIndices[ 0 ] = (opus_int8)ec_dec_icdf( psRangeDec, &psDec->psNLSF_CB->CB1_iCDF[ ( psDec->indices.signalType >> 1 ) * psDec->psNLSF_CB->nVectors ], 8 ); + silk_NLSF_unpack( ec_ix, pred_Q8, psDec->psNLSF_CB, psDec->indices.NLSFIndices[ 0 ] ); + silk_assert( psDec->psNLSF_CB->order == psDec->LPC_order ); + for( i = 0; i < psDec->psNLSF_CB->order; i++ ) { + Ix = ec_dec_icdf( psRangeDec, &psDec->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 ); + if( Ix == 0 ) { + Ix -= ec_dec_icdf( psRangeDec, silk_NLSF_EXT_iCDF, 8 ); + } else if( Ix == 2 * NLSF_QUANT_MAX_AMPLITUDE ) { + Ix += ec_dec_icdf( psRangeDec, silk_NLSF_EXT_iCDF, 8 ); + } + psDec->indices.NLSFIndices[ i+1 ] = (opus_int8)( Ix - NLSF_QUANT_MAX_AMPLITUDE ); + } + + /* Decode LSF interpolation factor */ + if( psDec->nb_subfr == MAX_NB_SUBFR ) { + psDec->indices.NLSFInterpCoef_Q2 = (opus_int8)ec_dec_icdf( psRangeDec, silk_NLSF_interpolation_factor_iCDF, 8 ); + } else { + psDec->indices.NLSFInterpCoef_Q2 = 4; + } + + if( psDec->indices.signalType == TYPE_VOICED ) + { + /*********************/ + /* Decode pitch lags */ + /*********************/ + /* Get lag index */ + decode_absolute_lagIndex = 1; + if( condCoding == CODE_CONDITIONALLY && psDec->ec_prevSignalType == TYPE_VOICED ) { + /* Decode Delta index */ + delta_lagIndex = (opus_int16)ec_dec_icdf( psRangeDec, silk_pitch_delta_iCDF, 8 ); + if( delta_lagIndex > 0 ) { + delta_lagIndex = delta_lagIndex - 9; + psDec->indices.lagIndex = (opus_int16)( psDec->ec_prevLagIndex + delta_lagIndex ); + decode_absolute_lagIndex = 0; + } + } + if( decode_absolute_lagIndex ) { + /* Absolute decoding */ + psDec->indices.lagIndex = (opus_int16)ec_dec_icdf( psRangeDec, silk_pitch_lag_iCDF, 8 ) * silk_RSHIFT( psDec->fs_kHz, 1 ); + psDec->indices.lagIndex += (opus_int16)ec_dec_icdf( psRangeDec, psDec->pitch_lag_low_bits_iCDF, 8 ); + } + psDec->ec_prevLagIndex = psDec->indices.lagIndex; + + /* Get countour index */ + psDec->indices.contourIndex = (opus_int8)ec_dec_icdf( psRangeDec, psDec->pitch_contour_iCDF, 8 ); + + /********************/ + /* Decode LTP gains */ + /********************/ + /* Decode PERIndex value */ + psDec->indices.PERIndex = (opus_int8)ec_dec_icdf( psRangeDec, silk_LTP_per_index_iCDF, 8 ); + + for( k = 0; k < psDec->nb_subfr; k++ ) { + psDec->indices.LTPIndex[ k ] = (opus_int8)ec_dec_icdf( psRangeDec, silk_LTP_gain_iCDF_ptrs[ psDec->indices.PERIndex ], 8 ); + } + + /**********************/ + /* Decode LTP scaling */ + /**********************/ + if( condCoding == CODE_INDEPENDENTLY ) { + psDec->indices.LTP_scaleIndex = (opus_int8)ec_dec_icdf( psRangeDec, silk_LTPscale_iCDF, 8 ); + } else { + psDec->indices.LTP_scaleIndex = 0; + } + } + psDec->ec_prevSignalType = psDec->indices.signalType; + + /***************/ + /* Decode seed */ + /***************/ + psDec->indices.Seed = (opus_int8)ec_dec_icdf( psRangeDec, silk_uniform4_iCDF, 8 ); +} diff --git a/code/opus-1.0.2/silk/decode_parameters.c b/code/opus-1.0.2/silk/decode_parameters.c new file mode 100644 index 00000000..e4c7e7a4 --- /dev/null +++ b/code/opus-1.0.2/silk/decode_parameters.c @@ -0,0 +1,115 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Decode parameters from payload */ +void silk_decode_parameters( + silk_decoder_state *psDec, /* I/O State */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + opus_int i, k, Ix; + opus_int16 pNLSF_Q15[ MAX_LPC_ORDER ], pNLSF0_Q15[ MAX_LPC_ORDER ]; + const opus_int8 *cbk_ptr_Q7; + + /* Dequant Gains */ + silk_gains_dequant( psDecCtrl->Gains_Q16, psDec->indices.GainsIndices, + &psDec->LastGainIndex, condCoding == CODE_CONDITIONALLY, psDec->nb_subfr ); + + /****************/ + /* Decode NLSFs */ + /****************/ + silk_NLSF_decode( pNLSF_Q15, psDec->indices.NLSFIndices, psDec->psNLSF_CB ); + + /* Convert NLSF parameters to AR prediction filter coefficients */ + silk_NLSF2A( psDecCtrl->PredCoef_Q12[ 1 ], pNLSF_Q15, psDec->LPC_order ); + + /* 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 ) { + psDec->indices.NLSFInterpCoef_Q2 = 4; + } + + if( psDec->indices.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 ] + silk_RSHIFT( silk_MUL( psDec->indices.NLSFInterpCoef_Q2, + pNLSF_Q15[ i ] - psDec->prevNLSF_Q15[ i ] ), 2 ); + } + + /* Convert NLSF parameters to AR prediction filter coefficients */ + silk_NLSF2A( psDecCtrl->PredCoef_Q12[ 0 ], pNLSF0_Q15, psDec->LPC_order ); + } else { + /* Copy LPC coefficients for first half from second half */ + silk_memcpy( psDecCtrl->PredCoef_Q12[ 0 ], psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order * sizeof( opus_int16 ) ); + } + + silk_memcpy( psDec->prevNLSF_Q15, pNLSF_Q15, psDec->LPC_order * sizeof( opus_int16 ) ); + + /* After a packet loss do BWE of LPC coefs */ + if( psDec->lossCnt ) { + silk_bwexpander( psDecCtrl->PredCoef_Q12[ 0 ], psDec->LPC_order, BWE_AFTER_LOSS_Q16 ); + silk_bwexpander( psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order, BWE_AFTER_LOSS_Q16 ); + } + + if( psDec->indices.signalType == TYPE_VOICED ) { + /*********************/ + /* Decode pitch lags */ + /*********************/ + + /* Decode pitch values */ + silk_decode_pitch( psDec->indices.lagIndex, psDec->indices.contourIndex, psDecCtrl->pitchL, psDec->fs_kHz, psDec->nb_subfr ); + + /* Decode Codebook Index */ + cbk_ptr_Q7 = silk_LTP_vq_ptrs_Q7[ psDec->indices.PERIndex ]; /* set pointer to start of codebook */ + + for( k = 0; k < psDec->nb_subfr; k++ ) { + Ix = psDec->indices.LTPIndex[ k ]; + for( i = 0; i < LTP_ORDER; i++ ) { + psDecCtrl->LTPCoef_Q14[ k * LTP_ORDER + i ] = silk_LSHIFT( cbk_ptr_Q7[ Ix * LTP_ORDER + i ], 7 ); + } + } + + /**********************/ + /* Decode LTP scaling */ + /**********************/ + Ix = psDec->indices.LTP_scaleIndex; + psDecCtrl->LTP_scale_Q14 = silk_LTPScales_table_Q14[ Ix ]; + } else { + silk_memset( psDecCtrl->pitchL, 0, psDec->nb_subfr * sizeof( opus_int ) ); + silk_memset( psDecCtrl->LTPCoef_Q14, 0, LTP_ORDER * psDec->nb_subfr * sizeof( opus_int16 ) ); + psDec->indices.PERIndex = 0; + psDecCtrl->LTP_scale_Q14 = 0; + } +} diff --git a/code/opus-1.0.2/silk/decode_pitch.c b/code/opus-1.0.2/silk/decode_pitch.c new file mode 100644 index 00000000..80fb4d9f --- /dev/null +++ b/code/opus-1.0.2/silk/decode_pitch.c @@ -0,0 +1,77 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/*********************************************************** +* Pitch analyser function +********************************************************** */ +#include "SigProc_FIX.h" +#include "pitch_est_defines.h" + +void silk_decode_pitch( + opus_int16 lagIndex, /* I */ + opus_int8 contourIndex, /* O */ + opus_int pitch_lags[], /* O 4 pitch values */ + const opus_int Fs_kHz, /* I sampling frequency (kHz) */ + const opus_int nb_subfr /* I number of sub frames */ +) +{ + opus_int lag, k, min_lag, max_lag, cbk_size; + const opus_int8 *Lag_CB_ptr; + + if( Fs_kHz == 8 ) { + if( nb_subfr == PE_MAX_NB_SUBFR ) { + Lag_CB_ptr = &silk_CB_lags_stage2[ 0 ][ 0 ]; + cbk_size = PE_NB_CBKS_STAGE2_EXT; + } else { + silk_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1 ); + Lag_CB_ptr = &silk_CB_lags_stage2_10_ms[ 0 ][ 0 ]; + cbk_size = PE_NB_CBKS_STAGE2_10MS; + } + } else { + if( nb_subfr == PE_MAX_NB_SUBFR ) { + Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ]; + cbk_size = PE_NB_CBKS_STAGE3_MAX; + } else { + silk_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1 ); + Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ]; + cbk_size = PE_NB_CBKS_STAGE3_10MS; + } + } + + min_lag = silk_SMULBB( PE_MIN_LAG_MS, Fs_kHz ); + max_lag = silk_SMULBB( PE_MAX_LAG_MS, Fs_kHz ); + lag = min_lag + lagIndex; + + for( k = 0; k < nb_subfr; k++ ) { + pitch_lags[ k ] = lag + matrix_ptr( Lag_CB_ptr, k, contourIndex, cbk_size ); + pitch_lags[ k ] = silk_LIMIT( pitch_lags[ k ], min_lag, max_lag ); + } +} diff --git a/code/opus-1.0.2/silk/decode_pulses.c b/code/opus-1.0.2/silk/decode_pulses.c new file mode 100644 index 00000000..1c781a0b --- /dev/null +++ b/code/opus-1.0.2/silk/decode_pulses.c @@ -0,0 +1,115 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/*********************************************/ +/* Decode quantization indices of excitation */ +/*********************************************/ +void silk_decode_pulses( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int pulses[], /* O Excitation signal */ + const opus_int signalType, /* I Sigtype */ + const opus_int quantOffsetType, /* I quantOffsetType */ + const opus_int frame_length /* I Frame length */ +) +{ + opus_int i, j, k, iter, abs_q, nLS, RateLevelIndex; + opus_int sum_pulses[ MAX_NB_SHELL_BLOCKS ], nLshifts[ MAX_NB_SHELL_BLOCKS ]; + opus_int *pulses_ptr; + const opus_uint8 *cdf_ptr; + + /*********************/ + /* Decode rate level */ + /*********************/ + RateLevelIndex = ec_dec_icdf( psRangeDec, silk_rate_levels_iCDF[ signalType >> 1 ], 8 ); + + /* Calculate number of shell blocks */ + silk_assert( 1 << LOG2_SHELL_CODEC_FRAME_LENGTH == SHELL_CODEC_FRAME_LENGTH ); + iter = silk_RSHIFT( frame_length, LOG2_SHELL_CODEC_FRAME_LENGTH ); + if( iter * SHELL_CODEC_FRAME_LENGTH < frame_length ) { + silk_assert( frame_length == 12 * 10 ); /* Make sure only happens for 10 ms @ 12 kHz */ + iter++; + } + + /***************************************************/ + /* Sum-Weighted-Pulses Decoding */ + /***************************************************/ + cdf_ptr = silk_pulses_per_block_iCDF[ RateLevelIndex ]; + for( i = 0; i < iter; i++ ) { + nLshifts[ i ] = 0; + sum_pulses[ i ] = ec_dec_icdf( psRangeDec, cdf_ptr, 8 ); + + /* LSB indication */ + while( sum_pulses[ i ] == MAX_PULSES + 1 ) { + nLshifts[ i ]++; + /* When we've already got 10 LSBs, we shift the table to not allow (MAX_PULSES + 1) */ + sum_pulses[ i ] = ec_dec_icdf( psRangeDec, + silk_pulses_per_block_iCDF[ N_RATE_LEVELS - 1] + ( nLshifts[ i ] == 10 ), 8 ); + } + } + + /***************************************************/ + /* Shell decoding */ + /***************************************************/ + for( i = 0; i < iter; i++ ) { + if( sum_pulses[ i ] > 0 ) { + silk_shell_decoder( &pulses[ silk_SMULBB( i, SHELL_CODEC_FRAME_LENGTH ) ], psRangeDec, sum_pulses[ i ] ); + } else { + silk_memset( &pulses[ silk_SMULBB( i, SHELL_CODEC_FRAME_LENGTH ) ], 0, SHELL_CODEC_FRAME_LENGTH * sizeof( opus_int ) ); + } + } + + /***************************************************/ + /* LSB Decoding */ + /***************************************************/ + for( i = 0; i < iter; i++ ) { + if( nLshifts[ i ] > 0 ) { + nLS = nLshifts[ i ]; + pulses_ptr = &pulses[ silk_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 = silk_LSHIFT( abs_q, 1 ); + abs_q += ec_dec_icdf( psRangeDec, silk_lsb_iCDF, 8 ); + } + pulses_ptr[ k ] = abs_q; + } + /* Mark the number of pulses non-zero for sign decoding. */ + sum_pulses[ i ] |= nLS << 5; + } + } + + /****************************************/ + /* Decode and add signs to pulse signal */ + /****************************************/ + silk_decode_signs( psRangeDec, pulses, frame_length, signalType, quantOffsetType, sum_pulses ); +} diff --git a/code/opus-1.0.2/silk/decoder_set_fs.c b/code/opus-1.0.2/silk/decoder_set_fs.c new file mode 100644 index 00000000..38ac249c --- /dev/null +++ b/code/opus-1.0.2/silk/decoder_set_fs.c @@ -0,0 +1,108 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Set decoder sampling rate */ +opus_int silk_decoder_set_fs( + silk_decoder_state *psDec, /* I/O Decoder state pointer */ + opus_int fs_kHz, /* I Sampling frequency (kHz) */ + opus_int32 fs_API_Hz /* I API Sampling frequency (Hz) */ +) +{ + opus_int frame_length, ret = 0; + + silk_assert( fs_kHz == 8 || fs_kHz == 12 || fs_kHz == 16 ); + silk_assert( psDec->nb_subfr == MAX_NB_SUBFR || psDec->nb_subfr == MAX_NB_SUBFR/2 ); + + /* New (sub)frame length */ + psDec->subfr_length = silk_SMULBB( SUB_FRAME_LENGTH_MS, fs_kHz ); + frame_length = silk_SMULBB( psDec->nb_subfr, psDec->subfr_length ); + + /* Initialize resampler when switching internal or external sampling frequency */ + if( psDec->fs_kHz != fs_kHz || psDec->fs_API_hz != fs_API_Hz ) { + /* Initialize the resampler for dec_API.c preparing resampling from fs_kHz to API_fs_Hz */ + ret += silk_resampler_init( &psDec->resampler_state, silk_SMULBB( fs_kHz, 1000 ), fs_API_Hz, 0 ); + + psDec->fs_API_hz = fs_API_Hz; + } + + if( psDec->fs_kHz != fs_kHz || frame_length != psDec->frame_length ) { + if( fs_kHz == 8 ) { + if( psDec->nb_subfr == MAX_NB_SUBFR ) { + psDec->pitch_contour_iCDF = silk_pitch_contour_NB_iCDF; + } else { + psDec->pitch_contour_iCDF = silk_pitch_contour_10_ms_NB_iCDF; + } + } else { + if( psDec->nb_subfr == MAX_NB_SUBFR ) { + psDec->pitch_contour_iCDF = silk_pitch_contour_iCDF; + } else { + psDec->pitch_contour_iCDF = silk_pitch_contour_10_ms_iCDF; + } + } + if( psDec->fs_kHz != fs_kHz ) { + psDec->ltp_mem_length = silk_SMULBB( LTP_MEM_LENGTH_MS, fs_kHz ); + if( fs_kHz == 8 || fs_kHz == 12 ) { + psDec->LPC_order = MIN_LPC_ORDER; + psDec->psNLSF_CB = &silk_NLSF_CB_NB_MB; + } else { + psDec->LPC_order = MAX_LPC_ORDER; + psDec->psNLSF_CB = &silk_NLSF_CB_WB; + } + if( fs_kHz == 16 ) { + psDec->pitch_lag_low_bits_iCDF = silk_uniform8_iCDF; + } else if( fs_kHz == 12 ) { + psDec->pitch_lag_low_bits_iCDF = silk_uniform6_iCDF; + } else if( fs_kHz == 8 ) { + psDec->pitch_lag_low_bits_iCDF = silk_uniform4_iCDF; + } else { + /* unsupported sampling rate */ + silk_assert( 0 ); + } + psDec->first_frame_after_reset = 1; + psDec->lagPrev = 100; + psDec->LastGainIndex = 10; + psDec->prevSignalType = TYPE_NO_VOICE_ACTIVITY; + silk_memset( psDec->outBuf, 0, sizeof(psDec->outBuf)); + silk_memset( psDec->sLPC_Q14_buf, 0, sizeof(psDec->sLPC_Q14_buf) ); + } + + psDec->fs_kHz = fs_kHz; + psDec->frame_length = frame_length; + } + + /* Check that settings are valid */ + silk_assert( psDec->frame_length > 0 && psDec->frame_length <= MAX_FRAME_LENGTH ); + + return ret; +} + diff --git a/code/opus-1.0.2/silk/define.h b/code/opus-1.0.2/silk/define.h new file mode 100644 index 00000000..f74f4869 --- /dev/null +++ b/code/opus-1.0.2/silk/define.h @@ -0,0 +1,235 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (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 SILK_DEFINE_H +#define SILK_DEFINE_H + +#include "errors.h" +#include "typedef.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Max number of encoder channels (1/2) */ +#define ENCODER_NUM_CHANNELS 2 +/* Number of decoder channels (1/2) */ +#define DECODER_NUM_CHANNELS 2 + +#define MAX_FRAMES_PER_PACKET 3 + +/* Limits on bitrate */ +#define MIN_TARGET_RATE_BPS 5000 +#define MAX_TARGET_RATE_BPS 80000 +#define TARGET_RATE_TAB_SZ 8 + +/* LBRR thresholds */ +#define LBRR_NB_MIN_RATE_BPS 12000 +#define LBRR_MB_MIN_RATE_BPS 14000 +#define LBRR_WB_MIN_RATE_BPS 16000 + +/* DTX settings */ +#define NB_SPEECH_FRAMES_BEFORE_DTX 10 /* eq 200 ms */ +#define MAX_CONSECUTIVE_DTX 20 /* eq 400 ms */ + +/* Maximum sampling frequency */ +#define MAX_FS_KHZ 16 +#define MAX_API_FS_KHZ 48 + +/* Signal types */ +#define TYPE_NO_VOICE_ACTIVITY 0 +#define TYPE_UNVOICED 1 +#define TYPE_VOICED 2 + +/* Conditional coding types */ +#define CODE_INDEPENDENTLY 0 +#define CODE_INDEPENDENTLY_NO_LTP_SCALING 1 +#define CODE_CONDITIONALLY 2 + +/* Settings for stereo processing */ +#define STEREO_QUANT_TAB_SIZE 16 +#define STEREO_QUANT_SUB_STEPS 5 +#define STEREO_INTERP_LEN_MS 8 /* must be even */ +#define STEREO_RATIO_SMOOTH_COEF 0.01 /* smoothing coef for signal norms and stereo width */ + +/* Range of pitch lag estimates */ +#define PITCH_EST_MIN_LAG_MS 2 /* 2 ms -> 500 Hz */ +#define PITCH_EST_MAX_LAG_MS 18 /* 18 ms -> 56 Hz */ + +/* Maximum number of subframes */ +#define MAX_NB_SUBFR 4 + +/* Number of samples per frame */ +#define LTP_MEM_LENGTH_MS 20 +#define SUB_FRAME_LENGTH_MS 5 +#define MAX_SUB_FRAME_LENGTH ( SUB_FRAME_LENGTH_MS * MAX_FS_KHZ ) +#define MAX_FRAME_LENGTH_MS ( SUB_FRAME_LENGTH_MS * MAX_NB_SUBFR ) +#define MAX_FRAME_LENGTH ( MAX_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 ) + +/* Order of LPC used in find pitch */ +#define MAX_FIND_PITCH_LPC_ORDER 16 + +/* Length of LPC window used in find pitch */ +#define FIND_PITCH_LPC_WIN_MS ( 20 + (LA_PITCH_MS << 1) ) +#define FIND_PITCH_LPC_WIN_MS_2_SF ( 10 + (LA_PITCH_MS << 1) ) +#define FIND_PITCH_LPC_WIN_MAX ( FIND_PITCH_LPC_WIN_MS * MAX_FS_KHZ ) + +/* Milliseconds of lookahead for noise shape analysis */ +#define LA_SHAPE_MS 5 +#define LA_SHAPE_MAX ( LA_SHAPE_MS * MAX_FS_KHZ ) + +/* Maximum length of LPC window used in noise shape analysis */ +#define SHAPE_LPC_WIN_MAX ( 15 * MAX_FS_KHZ ) + +/* dB level of lowest gain quantization level */ +#define MIN_QGAIN_DB 2 +/* dB level of highest gain quantization level */ +#define MAX_QGAIN_DB 88 +/* Number of gain quantization levels */ +#define N_LEVELS_QGAIN 64 +/* Max increase in gain quantization index */ +#define MAX_DELTA_GAIN_QUANT 36 +/* 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 240 + +#define QUANT_LEVEL_ADJUST_Q10 80 + +/* Maximum numbers of iterations used to stabilize an LPC vector */ +#define MAX_LPC_STABILIZE_ITERATIONS 16 +#define MAX_PREDICTION_POWER_GAIN 1e4f +#define MAX_PREDICTION_POWER_GAIN_AFTER_RESET 1e2f + +#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 + +/* 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 LOG2_SHELL_CODEC_FRAME_LENGTH 4 +#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 16 + +#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 + +/***************************/ +/* 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 + +/* Size of the piecewise linear cosine approximation table for the LSFs */ +#define LSF_COS_TAB_SZ_FIX 128 + +/******************/ +/* NLSF quantizer */ +/******************/ +#define NLSF_W_Q 2 +#define NLSF_VQ_MAX_VECTORS 32 +#define NLSF_VQ_MAX_SURVIVORS 32 +#define NLSF_QUANT_MAX_AMPLITUDE 4 +#define NLSF_QUANT_MAX_AMPLITUDE_EXT 10 +#define NLSF_QUANT_LEVEL_ADJ 0.1 +#define NLSF_QUANT_DEL_DEC_STATES_LOG2 2 +#define NLSF_QUANT_DEL_DEC_STATES ( 1 << NLSF_QUANT_DEL_DEC_STATES_LOG2 ) + +/* Transition filtering for mode switching */ +#define TRANSITION_TIME_MS 5120 /* 5120 = 64 * FRAME_LENGTH_MS * ( TRANSITION_INT_NUM - 1 ) = 64*(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 ( TRANSITION_TIME_MS / MAX_FRAME_LENGTH_MS ) +#define TRANSITION_INT_STEPS ( TRANSITION_FRAMES / ( TRANSITION_INT_NUM - 1 ) ) + +/* 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/code/opus-1.0.2/silk/enc_API.c b/code/opus-1.0.2/silk/enc_API.c new file mode 100644 index 00000000..ec7915ce --- /dev/null +++ b/code/opus-1.0.2/silk/enc_API.c @@ -0,0 +1,538 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "define.h" +#include "API.h" +#include "control.h" +#include "typedef.h" +#include "structs.h" +#include "tuning_parameters.h" +#ifdef FIXED_POINT +#include "main_FIX.h" +#else +#include "main_FLP.h" +#endif + +/***************************************/ +/* Read control structure from encoder */ +/***************************************/ +static opus_int silk_QueryEncoder( /* O Returns error code */ + const void *encState, /* I State */ + silk_EncControlStruct *encStatus /* O Encoder Status */ +); + +/****************************************/ +/* Encoder functions */ +/****************************************/ + +opus_int silk_Get_Encoder_Size( /* O Returns error code */ + opus_int *encSizeBytes /* O Number of bytes in SILK encoder state */ +) +{ + opus_int ret = SILK_NO_ERROR; + + *encSizeBytes = sizeof( silk_encoder ); + + return ret; +} + +/*************************/ +/* Init or Reset encoder */ +/*************************/ +opus_int silk_InitEncoder( /* O Returns error code */ + void *encState, /* I/O State */ + silk_EncControlStruct *encStatus /* O Encoder Status */ +) +{ + silk_encoder *psEnc; + opus_int n, ret = SILK_NO_ERROR; + + psEnc = (silk_encoder *)encState; + + /* Reset encoder */ + silk_memset( psEnc, 0, sizeof( silk_encoder ) ); + for( n = 0; n < ENCODER_NUM_CHANNELS; n++ ) { + if( ret += silk_init_encoder( &psEnc->state_Fxx[ n ] ) ) { + silk_assert( 0 ); + } + } + + psEnc->nChannelsAPI = 1; + psEnc->nChannelsInternal = 1; + + /* Read control structure */ + if( ret += silk_QueryEncoder( encState, encStatus ) ) { + silk_assert( 0 ); + } + + return ret; +} + +/***************************************/ +/* Read control structure from encoder */ +/***************************************/ +static opus_int silk_QueryEncoder( /* O Returns error code */ + const void *encState, /* I State */ + silk_EncControlStruct *encStatus /* O Encoder Status */ +) +{ + opus_int ret = SILK_NO_ERROR; + silk_encoder_state_Fxx *state_Fxx; + silk_encoder *psEnc = (silk_encoder *)encState; + + state_Fxx = psEnc->state_Fxx; + + encStatus->nChannelsAPI = psEnc->nChannelsAPI; + encStatus->nChannelsInternal = psEnc->nChannelsInternal; + encStatus->API_sampleRate = state_Fxx[ 0 ].sCmn.API_fs_Hz; + encStatus->maxInternalSampleRate = state_Fxx[ 0 ].sCmn.maxInternal_fs_Hz; + encStatus->minInternalSampleRate = state_Fxx[ 0 ].sCmn.minInternal_fs_Hz; + encStatus->desiredInternalSampleRate = state_Fxx[ 0 ].sCmn.desiredInternal_fs_Hz; + encStatus->payloadSize_ms = state_Fxx[ 0 ].sCmn.PacketSize_ms; + encStatus->bitRate = state_Fxx[ 0 ].sCmn.TargetRate_bps; + encStatus->packetLossPercentage = state_Fxx[ 0 ].sCmn.PacketLoss_perc; + encStatus->complexity = state_Fxx[ 0 ].sCmn.Complexity; + encStatus->useInBandFEC = state_Fxx[ 0 ].sCmn.useInBandFEC; + encStatus->useDTX = state_Fxx[ 0 ].sCmn.useDTX; + encStatus->useCBR = state_Fxx[ 0 ].sCmn.useCBR; + encStatus->internalSampleRate = silk_SMULBB( state_Fxx[ 0 ].sCmn.fs_kHz, 1000 ); + encStatus->allowBandwidthSwitch = state_Fxx[ 0 ].sCmn.allow_bandwidth_switch; + encStatus->inWBmodeWithoutVariableLP = state_Fxx[ 0 ].sCmn.fs_kHz == 16 && state_Fxx[ 0 ].sCmn.sLP.mode == 0; + + return ret; +} + + +/**************************/ +/* Encode frame with Silk */ +/**************************/ +/* Note: if prefillFlag is set, the input must contain 10 ms of audio, irrespective of what */ +/* encControl->payloadSize_ms is set to */ +opus_int silk_Encode( /* O Returns error code */ + void *encState, /* I/O State */ + silk_EncControlStruct *encControl, /* I Control status */ + const opus_int16 *samplesIn, /* I Speech sample input vector */ + opus_int nSamplesIn, /* I Number of samples in input vector */ + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int32 *nBytesOut, /* I/O Number of bytes in payload (input: Max bytes) */ + const opus_int prefillFlag /* I Flag to indicate prefilling buffers no coding */ +) +{ + opus_int n, i, nBits, flags, tmp_payloadSize_ms = 0, tmp_complexity = 0, ret = 0; + opus_int nSamplesToBuffer, nBlocksOf10ms, nSamplesFromInput = 0; + opus_int speech_act_thr_for_switch_Q8; + opus_int32 TargetRate_bps, MStargetRates_bps[ 2 ], channelRate_bps, LBRR_symbol, sum; + silk_encoder *psEnc = ( silk_encoder * )encState; + opus_int16 buf[ MAX_FRAME_LENGTH_MS * MAX_API_FS_KHZ ]; + opus_int transition, curr_block, tot_blocks; + + psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded = psEnc->state_Fxx[ 1 ].sCmn.nFramesEncoded = 0; + + /* Check values in encoder control structure */ + if( ( ret = check_control_input( encControl ) != 0 ) ) { + silk_assert( 0 ); + return ret; + } + + encControl->switchReady = 0; + + if( encControl->nChannelsInternal > psEnc->nChannelsInternal ) { + /* Mono -> Stereo transition: init state of second channel and stereo state */ + ret += silk_init_encoder( &psEnc->state_Fxx[ 1 ] ); + silk_memset( psEnc->sStereo.pred_prev_Q13, 0, sizeof( psEnc->sStereo.pred_prev_Q13 ) ); + silk_memset( psEnc->sStereo.sSide, 0, sizeof( psEnc->sStereo.sSide ) ); + psEnc->sStereo.mid_side_amp_Q0[ 0 ] = 0; + psEnc->sStereo.mid_side_amp_Q0[ 1 ] = 1; + psEnc->sStereo.mid_side_amp_Q0[ 2 ] = 0; + psEnc->sStereo.mid_side_amp_Q0[ 3 ] = 1; + psEnc->sStereo.width_prev_Q14 = 0; + psEnc->sStereo.smth_width_Q14 = SILK_FIX_CONST( 1, 14 ); + if( psEnc->nChannelsAPI == 2 ) { + silk_memcpy( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state, &psEnc->state_Fxx[ 0 ].sCmn.resampler_state, sizeof( silk_resampler_state_struct ) ); + silk_memcpy( &psEnc->state_Fxx[ 1 ].sCmn.In_HP_State, &psEnc->state_Fxx[ 0 ].sCmn.In_HP_State, sizeof( psEnc->state_Fxx[ 1 ].sCmn.In_HP_State ) ); + } + } + + transition = (encControl->payloadSize_ms != psEnc->state_Fxx[ 0 ].sCmn.PacketSize_ms) || (psEnc->nChannelsInternal != encControl->nChannelsInternal); + + psEnc->nChannelsAPI = encControl->nChannelsAPI; + psEnc->nChannelsInternal = encControl->nChannelsInternal; + + nBlocksOf10ms = silk_DIV32( 100 * nSamplesIn, encControl->API_sampleRate ); + tot_blocks = ( nBlocksOf10ms > 1 ) ? nBlocksOf10ms >> 1 : 1; + curr_block = 0; + if( prefillFlag ) { + /* Only accept input length of 10 ms */ + if( nBlocksOf10ms != 1 ) { + ret = SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES; + silk_assert( 0 ); + return ret; + } + /* Reset Encoder */ + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + if( (ret = silk_init_encoder( &psEnc->state_Fxx[ n ] ) ) != 0 ) { + silk_assert( 0 ); + } + } + tmp_payloadSize_ms = encControl->payloadSize_ms; + encControl->payloadSize_ms = 10; + tmp_complexity = encControl->complexity; + encControl->complexity = 0; + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + psEnc->state_Fxx[ n ].sCmn.controlled_since_last_payload = 0; + psEnc->state_Fxx[ n ].sCmn.prefillFlag = 1; + } + } else { + /* Only accept input lengths that are a multiple of 10 ms */ + if( nBlocksOf10ms * encControl->API_sampleRate != 100 * nSamplesIn || nSamplesIn < 0 ) { + ret = SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES; + silk_assert( 0 ); + return ret; + } + /* Make sure no more than one packet can be produced */ + if( 1000 * (opus_int32)nSamplesIn > encControl->payloadSize_ms * encControl->API_sampleRate ) { + ret = SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES; + silk_assert( 0 ); + return ret; + } + } + + TargetRate_bps = silk_RSHIFT32( encControl->bitRate, encControl->nChannelsInternal - 1 ); + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + /* Force the side channel to the same rate as the mid */ + opus_int force_fs_kHz = (n==1) ? psEnc->state_Fxx[0].sCmn.fs_kHz : 0; + if( ( ret = silk_control_encoder( &psEnc->state_Fxx[ n ], encControl, TargetRate_bps, psEnc->allowBandwidthSwitch, n, force_fs_kHz ) ) != 0 ) { + silk_assert( 0 ); + return ret; + } + if( psEnc->state_Fxx[n].sCmn.first_frame_after_reset || transition ) { + for( i = 0; i < psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket; i++ ) { + psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i ] = 0; + } + } + psEnc->state_Fxx[ n ].sCmn.inDTX = psEnc->state_Fxx[ n ].sCmn.useDTX; + } + silk_assert( encControl->nChannelsInternal == 1 || psEnc->state_Fxx[ 0 ].sCmn.fs_kHz == psEnc->state_Fxx[ 1 ].sCmn.fs_kHz ); + + /* Input buffering/resampling and encoding */ + while( 1 ) { + nSamplesToBuffer = psEnc->state_Fxx[ 0 ].sCmn.frame_length - psEnc->state_Fxx[ 0 ].sCmn.inputBufIx; + nSamplesToBuffer = silk_min( nSamplesToBuffer, 10 * nBlocksOf10ms * psEnc->state_Fxx[ 0 ].sCmn.fs_kHz ); + nSamplesFromInput = silk_DIV32_16( nSamplesToBuffer * psEnc->state_Fxx[ 0 ].sCmn.API_fs_Hz, psEnc->state_Fxx[ 0 ].sCmn.fs_kHz * 1000 ); + /* Resample and write to buffer */ + if( encControl->nChannelsAPI == 2 && encControl->nChannelsInternal == 2 ) { + opus_int id = psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded; + for( n = 0; n < nSamplesFromInput; n++ ) { + buf[ n ] = samplesIn[ 2 * n ]; + } + /* Making sure to start both resamplers from the same state when switching from mono to stereo */ + if( psEnc->nPrevChannelsInternal == 1 && id==0 ) { + silk_memcpy( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state, &psEnc->state_Fxx[ 0 ].sCmn.resampler_state, sizeof(psEnc->state_Fxx[ 1 ].sCmn.resampler_state)); + } + + ret += silk_resampler( &psEnc->state_Fxx[ 0 ].sCmn.resampler_state, + &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput ); + psEnc->state_Fxx[ 0 ].sCmn.inputBufIx += nSamplesToBuffer; + + nSamplesToBuffer = psEnc->state_Fxx[ 1 ].sCmn.frame_length - psEnc->state_Fxx[ 1 ].sCmn.inputBufIx; + nSamplesToBuffer = silk_min( nSamplesToBuffer, 10 * nBlocksOf10ms * psEnc->state_Fxx[ 1 ].sCmn.fs_kHz ); + for( n = 0; n < nSamplesFromInput; n++ ) { + buf[ n ] = samplesIn[ 2 * n + 1 ]; + } + ret += silk_resampler( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state, + &psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ psEnc->state_Fxx[ 1 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput ); + + psEnc->state_Fxx[ 1 ].sCmn.inputBufIx += nSamplesToBuffer; + } else if( encControl->nChannelsAPI == 2 && encControl->nChannelsInternal == 1 ) { + /* Combine left and right channels before resampling */ + for( n = 0; n < nSamplesFromInput; n++ ) { + sum = samplesIn[ 2 * n ] + samplesIn[ 2 * n + 1 ]; + buf[ n ] = (opus_int16)silk_RSHIFT_ROUND( sum, 1 ); + } + ret += silk_resampler( &psEnc->state_Fxx[ 0 ].sCmn.resampler_state, + &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput ); + /* On the first mono frame, average the results for the two resampler states */ + if( psEnc->nPrevChannelsInternal == 2 && psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded == 0 ) { + ret += silk_resampler( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state, + &psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ psEnc->state_Fxx[ 1 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput ); + for( n = 0; n < psEnc->state_Fxx[ 0 ].sCmn.frame_length; n++ ) { + psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx+n+2 ] = + silk_RSHIFT(psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx+n+2 ] + + psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ psEnc->state_Fxx[ 1 ].sCmn.inputBufIx+n+2 ], 1); + } + } + psEnc->state_Fxx[ 0 ].sCmn.inputBufIx += nSamplesToBuffer; + } else { + silk_assert( encControl->nChannelsAPI == 1 && encControl->nChannelsInternal == 1 ); + silk_memcpy(buf, samplesIn, nSamplesFromInput*sizeof(opus_int16)); + ret += silk_resampler( &psEnc->state_Fxx[ 0 ].sCmn.resampler_state, + &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput ); + psEnc->state_Fxx[ 0 ].sCmn.inputBufIx += nSamplesToBuffer; + } + + samplesIn += nSamplesFromInput * encControl->nChannelsAPI; + nSamplesIn -= nSamplesFromInput; + + /* Default */ + psEnc->allowBandwidthSwitch = 0; + + /* Silk encoder */ + if( psEnc->state_Fxx[ 0 ].sCmn.inputBufIx >= psEnc->state_Fxx[ 0 ].sCmn.frame_length ) { + /* Enough data in input buffer, so encode */ + silk_assert( psEnc->state_Fxx[ 0 ].sCmn.inputBufIx == psEnc->state_Fxx[ 0 ].sCmn.frame_length ); + silk_assert( encControl->nChannelsInternal == 1 || psEnc->state_Fxx[ 1 ].sCmn.inputBufIx == psEnc->state_Fxx[ 1 ].sCmn.frame_length ); + + /* Deal with LBRR data */ + if( psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded == 0 && !prefillFlag ) { + /* Create space at start of payload for VAD and FEC flags */ + opus_uint8 iCDF[ 2 ] = { 0, 0 }; + iCDF[ 0 ] = 256 - silk_RSHIFT( 256, ( psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket + 1 ) * encControl->nChannelsInternal ); + ec_enc_icdf( psRangeEnc, 0, iCDF, 8 ); + + /* Encode any LBRR data from previous packet */ + /* Encode LBRR flags */ + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + LBRR_symbol = 0; + for( i = 0; i < psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket; i++ ) { + LBRR_symbol |= silk_LSHIFT( psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i ], i ); + } + psEnc->state_Fxx[ n ].sCmn.LBRR_flag = LBRR_symbol > 0 ? 1 : 0; + if( LBRR_symbol && psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket > 1 ) { + ec_enc_icdf( psRangeEnc, LBRR_symbol - 1, silk_LBRR_flags_iCDF_ptr[ psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket - 2 ], 8 ); + } + } + + /* Code LBRR indices and excitation signals */ + for( i = 0; i < psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket; i++ ) { + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + if( psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i ] ) { + opus_int condCoding; + + if( encControl->nChannelsInternal == 2 && n == 0 ) { + silk_stereo_encode_pred( psRangeEnc, psEnc->sStereo.predIx[ i ] ); + /* For LBRR data there's no need to code the mid-only flag if the side-channel LBRR flag is set */ + if( psEnc->state_Fxx[ 1 ].sCmn.LBRR_flags[ i ] == 0 ) { + silk_stereo_encode_mid_only( psRangeEnc, psEnc->sStereo.mid_only_flags[ i ] ); + } + } + /* Use conditional coding if previous frame available */ + if( i > 0 && psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i - 1 ] ) { + condCoding = CODE_CONDITIONALLY; + } else { + condCoding = CODE_INDEPENDENTLY; + } + silk_encode_indices( &psEnc->state_Fxx[ n ].sCmn, psRangeEnc, i, 1, condCoding ); + silk_encode_pulses( psRangeEnc, psEnc->state_Fxx[ n ].sCmn.indices_LBRR[i].signalType, psEnc->state_Fxx[ n ].sCmn.indices_LBRR[i].quantOffsetType, + psEnc->state_Fxx[ n ].sCmn.pulses_LBRR[ i ], psEnc->state_Fxx[ n ].sCmn.frame_length ); + } + } + } + + /* Reset LBRR flags */ + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + silk_memset( psEnc->state_Fxx[ n ].sCmn.LBRR_flags, 0, sizeof( psEnc->state_Fxx[ n ].sCmn.LBRR_flags ) ); + } + } + + silk_HP_variable_cutoff( psEnc->state_Fxx ); + + /* Total target bits for packet */ + nBits = silk_DIV32_16( silk_MUL( encControl->bitRate, encControl->payloadSize_ms ), 1000 ); + /* Subtract half of the bits already used */ + if( !prefillFlag ) { + nBits -= ec_tell( psRangeEnc ) >> 1; + } + /* Divide by number of uncoded frames left in packet */ + nBits = silk_DIV32_16( nBits, psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket - psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ); + /* Convert to bits/second */ + if( encControl->payloadSize_ms == 10 ) { + TargetRate_bps = silk_SMULBB( nBits, 100 ); + } else { + TargetRate_bps = silk_SMULBB( nBits, 50 ); + } + /* Subtract fraction of bits in excess of target in previous packets */ + TargetRate_bps -= silk_DIV32_16( silk_MUL( psEnc->nBitsExceeded, 1000 ), BITRESERVOIR_DECAY_TIME_MS ); + /* Never exceed input bitrate */ + TargetRate_bps = silk_LIMIT( TargetRate_bps, encControl->bitRate, 5000 ); + + /* Convert Left/Right to Mid/Side */ + if( encControl->nChannelsInternal == 2 ) { + silk_stereo_LR_to_MS( &psEnc->sStereo, &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ 2 ], &psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ 2 ], + psEnc->sStereo.predIx[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ], &psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ], + MStargetRates_bps, TargetRate_bps, psEnc->state_Fxx[ 0 ].sCmn.speech_activity_Q8, encControl->toMono, + psEnc->state_Fxx[ 0 ].sCmn.fs_kHz, psEnc->state_Fxx[ 0 ].sCmn.frame_length ); + if( psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] == 0 ) { + /* Reset side channel encoder memory for first frame with side coding */ + if( psEnc->prev_decode_only_middle == 1 ) { + silk_memset( &psEnc->state_Fxx[ 1 ].sShape, 0, sizeof( psEnc->state_Fxx[ 1 ].sShape ) ); + silk_memset( &psEnc->state_Fxx[ 1 ].sPrefilt, 0, sizeof( psEnc->state_Fxx[ 1 ].sPrefilt ) ); + silk_memset( &psEnc->state_Fxx[ 1 ].sCmn.sNSQ, 0, sizeof( psEnc->state_Fxx[ 1 ].sCmn.sNSQ ) ); + silk_memset( psEnc->state_Fxx[ 1 ].sCmn.prev_NLSFq_Q15, 0, sizeof( psEnc->state_Fxx[ 1 ].sCmn.prev_NLSFq_Q15 ) ); + silk_memset( &psEnc->state_Fxx[ 1 ].sCmn.sLP.In_LP_State, 0, sizeof( psEnc->state_Fxx[ 1 ].sCmn.sLP.In_LP_State ) ); + psEnc->state_Fxx[ 1 ].sCmn.prevLag = 100; + psEnc->state_Fxx[ 1 ].sCmn.sNSQ.lagPrev = 100; + psEnc->state_Fxx[ 1 ].sShape.LastGainIndex = 10; + psEnc->state_Fxx[ 1 ].sCmn.prevSignalType = TYPE_NO_VOICE_ACTIVITY; + psEnc->state_Fxx[ 1 ].sCmn.sNSQ.prev_gain_Q16 = 65536; + psEnc->state_Fxx[ 1 ].sCmn.first_frame_after_reset = 1; + } + silk_encode_do_VAD_Fxx( &psEnc->state_Fxx[ 1 ] ); + } else { + psEnc->state_Fxx[ 1 ].sCmn.VAD_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] = 0; + } + if( !prefillFlag ) { + silk_stereo_encode_pred( psRangeEnc, psEnc->sStereo.predIx[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] ); + if( psEnc->state_Fxx[ 1 ].sCmn.VAD_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] == 0 ) { + silk_stereo_encode_mid_only( psRangeEnc, psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] ); + } + } + } else { + /* Buffering */ + silk_memcpy( psEnc->state_Fxx[ 0 ].sCmn.inputBuf, psEnc->sStereo.sMid, 2 * sizeof( opus_int16 ) ); + silk_memcpy( psEnc->sStereo.sMid, &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.frame_length ], 2 * sizeof( opus_int16 ) ); + } + silk_encode_do_VAD_Fxx( &psEnc->state_Fxx[ 0 ] ); + + /* Encode */ + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + opus_int maxBits, useCBR; + + /* Handling rate constraints */ + maxBits = encControl->maxBits; + if( tot_blocks == 2 && curr_block == 0 ) { + maxBits = maxBits * 3 / 5; + } else if( tot_blocks == 3 ) { + if( curr_block == 0 ) { + maxBits = maxBits * 2 / 5; + } else if( curr_block == 1 ) { + maxBits = maxBits * 3 / 4; + } + } + useCBR = encControl->useCBR && curr_block == tot_blocks - 1; + + if( encControl->nChannelsInternal == 1 ) { + channelRate_bps = TargetRate_bps; + } else { + channelRate_bps = MStargetRates_bps[ n ]; + if( n == 0 && MStargetRates_bps[ 1 ] > 0 ) { + useCBR = 0; + /* Give mid up to 1/2 of the max bits for that frame */ + maxBits -= encControl->maxBits / ( tot_blocks * 2 ); + } + } + + if( channelRate_bps > 0 ) { + opus_int condCoding; + + silk_control_SNR( &psEnc->state_Fxx[ n ].sCmn, channelRate_bps ); + + /* Use independent coding if no previous frame available */ + if( psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded - n <= 0 ) { + condCoding = CODE_INDEPENDENTLY; + } else if( n > 0 && psEnc->prev_decode_only_middle ) { + /* If we skipped a side frame in this packet, we don't + need LTP scaling; the LTP state is well-defined. */ + condCoding = CODE_INDEPENDENTLY_NO_LTP_SCALING; + } else { + condCoding = CODE_CONDITIONALLY; + } + if( ( ret = silk_encode_frame_Fxx( &psEnc->state_Fxx[ n ], nBytesOut, psRangeEnc, condCoding, maxBits, useCBR ) ) != 0 ) { + silk_assert( 0 ); + } + } + psEnc->state_Fxx[ n ].sCmn.controlled_since_last_payload = 0; + psEnc->state_Fxx[ n ].sCmn.inputBufIx = 0; + psEnc->state_Fxx[ n ].sCmn.nFramesEncoded++; + } + psEnc->prev_decode_only_middle = psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded - 1 ]; + + /* Insert VAD and FEC flags at beginning of bitstream */ + if( *nBytesOut > 0 && psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded == psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket) { + flags = 0; + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + for( i = 0; i < psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket; i++ ) { + flags = silk_LSHIFT( flags, 1 ); + flags |= psEnc->state_Fxx[ n ].sCmn.VAD_flags[ i ]; + } + flags = silk_LSHIFT( flags, 1 ); + flags |= psEnc->state_Fxx[ n ].sCmn.LBRR_flag; + } + if( !prefillFlag ) { + ec_enc_patch_initial_bits( psRangeEnc, flags, ( psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket + 1 ) * encControl->nChannelsInternal ); + } + + /* Return zero bytes if all channels DTXed */ + if( psEnc->state_Fxx[ 0 ].sCmn.inDTX && ( encControl->nChannelsInternal == 1 || psEnc->state_Fxx[ 1 ].sCmn.inDTX ) ) { + *nBytesOut = 0; + } + + psEnc->nBitsExceeded += *nBytesOut * 8; + psEnc->nBitsExceeded -= silk_DIV32_16( silk_MUL( encControl->bitRate, encControl->payloadSize_ms ), 1000 ); + psEnc->nBitsExceeded = silk_LIMIT( psEnc->nBitsExceeded, 0, 10000 ); + + /* Update flag indicating if bandwidth switching is allowed */ + speech_act_thr_for_switch_Q8 = silk_SMLAWB( SILK_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 ), + SILK_FIX_CONST( ( 1 - SPEECH_ACTIVITY_DTX_THRES ) / MAX_BANDWIDTH_SWITCH_DELAY_MS, 16 + 8 ), psEnc->timeSinceSwitchAllowed_ms ); + if( psEnc->state_Fxx[ 0 ].sCmn.speech_activity_Q8 < speech_act_thr_for_switch_Q8 ) { + psEnc->allowBandwidthSwitch = 1; + psEnc->timeSinceSwitchAllowed_ms = 0; + } else { + psEnc->allowBandwidthSwitch = 0; + psEnc->timeSinceSwitchAllowed_ms += encControl->payloadSize_ms; + } + } + + if( nSamplesIn == 0 ) { + break; + } + } else { + break; + } + curr_block++; + } + + psEnc->nPrevChannelsInternal = encControl->nChannelsInternal; + + encControl->allowBandwidthSwitch = psEnc->allowBandwidthSwitch; + encControl->inWBmodeWithoutVariableLP = psEnc->state_Fxx[ 0 ].sCmn.fs_kHz == 16 && psEnc->state_Fxx[ 0 ].sCmn.sLP.mode == 0; + encControl->internalSampleRate = silk_SMULBB( psEnc->state_Fxx[ 0 ].sCmn.fs_kHz, 1000 ); + encControl->stereoWidth_Q14 = encControl->toMono ? 0 : psEnc->sStereo.smth_width_Q14; + if( prefillFlag ) { + encControl->payloadSize_ms = tmp_payloadSize_ms; + encControl->complexity = tmp_complexity; + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + psEnc->state_Fxx[ n ].sCmn.controlled_since_last_payload = 0; + psEnc->state_Fxx[ n ].sCmn.prefillFlag = 0; + } + } + + return ret; +} + diff --git a/code/opus-1.0.2/silk/encode_indices.c b/code/opus-1.0.2/silk/encode_indices.c new file mode 100644 index 00000000..91e28aa9 --- /dev/null +++ b/code/opus-1.0.2/silk/encode_indices.c @@ -0,0 +1,181 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Encode side-information parameters to payload */ +void silk_encode_indices( + silk_encoder_state *psEncC, /* I/O Encoder state */ + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int FrameIndex, /* I Frame number */ + opus_int encode_LBRR, /* I Flag indicating LBRR data is being encoded */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + opus_int i, k, typeOffset; + opus_int encode_absolute_lagIndex, delta_lagIndex; + opus_int16 ec_ix[ MAX_LPC_ORDER ]; + opus_uint8 pred_Q8[ MAX_LPC_ORDER ]; + const SideInfoIndices *psIndices; + + if( encode_LBRR ) { + psIndices = &psEncC->indices_LBRR[ FrameIndex ]; + } else { + psIndices = &psEncC->indices; + } + + /*******************************************/ + /* Encode signal type and quantizer offset */ + /*******************************************/ + typeOffset = 2 * psIndices->signalType + psIndices->quantOffsetType; + silk_assert( typeOffset >= 0 && typeOffset < 6 ); + silk_assert( encode_LBRR == 0 || typeOffset >= 2 ); + if( encode_LBRR || typeOffset >= 2 ) { + ec_enc_icdf( psRangeEnc, typeOffset - 2, silk_type_offset_VAD_iCDF, 8 ); + } else { + ec_enc_icdf( psRangeEnc, typeOffset, silk_type_offset_no_VAD_iCDF, 8 ); + } + + /****************/ + /* Encode gains */ + /****************/ + /* first subframe */ + if( condCoding == CODE_CONDITIONALLY ) { + /* conditional coding */ + silk_assert( psIndices->GainsIndices[ 0 ] >= 0 && psIndices->GainsIndices[ 0 ] < MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 1 ); + ec_enc_icdf( psRangeEnc, psIndices->GainsIndices[ 0 ], silk_delta_gain_iCDF, 8 ); + } else { + /* independent coding, in two stages: MSB bits followed by 3 LSBs */ + silk_assert( psIndices->GainsIndices[ 0 ] >= 0 && psIndices->GainsIndices[ 0 ] < N_LEVELS_QGAIN ); + ec_enc_icdf( psRangeEnc, silk_RSHIFT( psIndices->GainsIndices[ 0 ], 3 ), silk_gain_iCDF[ psIndices->signalType ], 8 ); + ec_enc_icdf( psRangeEnc, psIndices->GainsIndices[ 0 ] & 7, silk_uniform8_iCDF, 8 ); + } + + /* remaining subframes */ + for( i = 1; i < psEncC->nb_subfr; i++ ) { + silk_assert( psIndices->GainsIndices[ i ] >= 0 && psIndices->GainsIndices[ i ] < MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 1 ); + ec_enc_icdf( psRangeEnc, psIndices->GainsIndices[ i ], silk_delta_gain_iCDF, 8 ); + } + + /****************/ + /* Encode NLSFs */ + /****************/ + ec_enc_icdf( psRangeEnc, psIndices->NLSFIndices[ 0 ], &psEncC->psNLSF_CB->CB1_iCDF[ ( psIndices->signalType >> 1 ) * psEncC->psNLSF_CB->nVectors ], 8 ); + silk_NLSF_unpack( ec_ix, pred_Q8, psEncC->psNLSF_CB, psIndices->NLSFIndices[ 0 ] ); + silk_assert( psEncC->psNLSF_CB->order == psEncC->predictLPCOrder ); + for( i = 0; i < psEncC->psNLSF_CB->order; i++ ) { + if( psIndices->NLSFIndices[ i+1 ] >= NLSF_QUANT_MAX_AMPLITUDE ) { + ec_enc_icdf( psRangeEnc, 2 * NLSF_QUANT_MAX_AMPLITUDE, &psEncC->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 ); + ec_enc_icdf( psRangeEnc, psIndices->NLSFIndices[ i+1 ] - NLSF_QUANT_MAX_AMPLITUDE, silk_NLSF_EXT_iCDF, 8 ); + } else if( psIndices->NLSFIndices[ i+1 ] <= -NLSF_QUANT_MAX_AMPLITUDE ) { + ec_enc_icdf( psRangeEnc, 0, &psEncC->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 ); + ec_enc_icdf( psRangeEnc, -psIndices->NLSFIndices[ i+1 ] - NLSF_QUANT_MAX_AMPLITUDE, silk_NLSF_EXT_iCDF, 8 ); + } else { + ec_enc_icdf( psRangeEnc, psIndices->NLSFIndices[ i+1 ] + NLSF_QUANT_MAX_AMPLITUDE, &psEncC->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 ); + } + } + + /* Encode NLSF interpolation factor */ + if( psEncC->nb_subfr == MAX_NB_SUBFR ) { + silk_assert( psIndices->NLSFInterpCoef_Q2 >= 0 && psIndices->NLSFInterpCoef_Q2 < 5 ); + ec_enc_icdf( psRangeEnc, psIndices->NLSFInterpCoef_Q2, silk_NLSF_interpolation_factor_iCDF, 8 ); + } + + if( psIndices->signalType == TYPE_VOICED ) + { + /*********************/ + /* Encode pitch lags */ + /*********************/ + /* lag index */ + encode_absolute_lagIndex = 1; + if( condCoding == CODE_CONDITIONALLY && psEncC->ec_prevSignalType == TYPE_VOICED ) { + /* Delta Encoding */ + delta_lagIndex = psIndices->lagIndex - psEncC->ec_prevLagIndex; + if( delta_lagIndex < -8 || delta_lagIndex > 11 ) { + delta_lagIndex = 0; + } else { + delta_lagIndex = delta_lagIndex + 9; + encode_absolute_lagIndex = 0; /* Only use delta */ + } + silk_assert( delta_lagIndex >= 0 && delta_lagIndex < 21 ); + ec_enc_icdf( psRangeEnc, delta_lagIndex, silk_pitch_delta_iCDF, 8 ); + } + if( encode_absolute_lagIndex ) { + /* Absolute encoding */ + opus_int32 pitch_high_bits, pitch_low_bits; + pitch_high_bits = silk_DIV32_16( psIndices->lagIndex, silk_RSHIFT( psEncC->fs_kHz, 1 ) ); + pitch_low_bits = psIndices->lagIndex - silk_SMULBB( pitch_high_bits, silk_RSHIFT( psEncC->fs_kHz, 1 ) ); + silk_assert( pitch_low_bits < psEncC->fs_kHz / 2 ); + silk_assert( pitch_high_bits < 32 ); + ec_enc_icdf( psRangeEnc, pitch_high_bits, silk_pitch_lag_iCDF, 8 ); + ec_enc_icdf( psRangeEnc, pitch_low_bits, psEncC->pitch_lag_low_bits_iCDF, 8 ); + } + psEncC->ec_prevLagIndex = psIndices->lagIndex; + + /* Countour index */ + silk_assert( psIndices->contourIndex >= 0 ); + silk_assert( ( psIndices->contourIndex < 34 && psEncC->fs_kHz > 8 && psEncC->nb_subfr == 4 ) || + ( psIndices->contourIndex < 11 && psEncC->fs_kHz == 8 && psEncC->nb_subfr == 4 ) || + ( psIndices->contourIndex < 12 && psEncC->fs_kHz > 8 && psEncC->nb_subfr == 2 ) || + ( psIndices->contourIndex < 3 && psEncC->fs_kHz == 8 && psEncC->nb_subfr == 2 ) ); + ec_enc_icdf( psRangeEnc, psIndices->contourIndex, psEncC->pitch_contour_iCDF, 8 ); + + /********************/ + /* Encode LTP gains */ + /********************/ + /* PERIndex value */ + silk_assert( psIndices->PERIndex >= 0 && psIndices->PERIndex < 3 ); + ec_enc_icdf( psRangeEnc, psIndices->PERIndex, silk_LTP_per_index_iCDF, 8 ); + + /* Codebook Indices */ + for( k = 0; k < psEncC->nb_subfr; k++ ) { + silk_assert( psIndices->LTPIndex[ k ] >= 0 && psIndices->LTPIndex[ k ] < ( 8 << psIndices->PERIndex ) ); + ec_enc_icdf( psRangeEnc, psIndices->LTPIndex[ k ], silk_LTP_gain_iCDF_ptrs[ psIndices->PERIndex ], 8 ); + } + + /**********************/ + /* Encode LTP scaling */ + /**********************/ + if( condCoding == CODE_INDEPENDENTLY ) { + silk_assert( psIndices->LTP_scaleIndex >= 0 && psIndices->LTP_scaleIndex < 3 ); + ec_enc_icdf( psRangeEnc, psIndices->LTP_scaleIndex, silk_LTPscale_iCDF, 8 ); + } + silk_assert( !condCoding || psIndices->LTP_scaleIndex == 0 ); + } + + psEncC->ec_prevSignalType = psIndices->signalType; + + /***************/ + /* Encode seed */ + /***************/ + silk_assert( psIndices->Seed >= 0 && psIndices->Seed < 4 ); + ec_enc_icdf( psRangeEnc, psIndices->Seed, silk_uniform4_iCDF, 8 ); +} diff --git a/code/opus-1.0.2/silk/encode_pulses.c b/code/opus-1.0.2/silk/encode_pulses.c new file mode 100644 index 00000000..b01b5853 --- /dev/null +++ b/code/opus-1.0.2/silk/encode_pulses.c @@ -0,0 +1,199 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/*********************************************/ +/* Encode quantization indices of excitation */ +/*********************************************/ + +static inline opus_int combine_and_check( /* return ok */ + opus_int *pulses_comb, /* O */ + const opus_int *pulses_in, /* I */ + opus_int max_pulses, /* I max value for sum of pulses */ + opus_int len /* I number of output values */ +) +{ + opus_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 silk_encode_pulses( + ec_enc *psRangeEnc, /* I/O compressor data structure */ + const opus_int signalType, /* I Signal type */ + const opus_int quantOffsetType, /* I quantOffsetType */ + opus_int8 pulses[], /* I quantization indices */ + const opus_int frame_length /* I Frame length */ +) +{ + opus_int i, k, j, iter, bit, nLS, scale_down, RateLevelIndex = 0; + opus_int32 abs_q, minSumBits_Q5, sumBits_Q5; + opus_int abs_pulses[ MAX_FRAME_LENGTH ]; + opus_int sum_pulses[ MAX_NB_SHELL_BLOCKS ]; + opus_int nRshifts[ MAX_NB_SHELL_BLOCKS ]; + opus_int pulses_comb[ 8 ]; + opus_int *abs_pulses_ptr; + const opus_int8 *pulses_ptr; + const opus_uint8 *cdf_ptr; + const opus_uint8 *nBits_ptr; + + silk_memset( pulses_comb, 0, 8 * sizeof( opus_int ) ); /* Fixing Valgrind reported problem*/ + + /****************************/ + /* Prepare for shell coding */ + /****************************/ + /* Calculate number of shell blocks */ + silk_assert( 1 << LOG2_SHELL_CODEC_FRAME_LENGTH == SHELL_CODEC_FRAME_LENGTH ); + iter = silk_RSHIFT( frame_length, LOG2_SHELL_CODEC_FRAME_LENGTH ); + if( iter * SHELL_CODEC_FRAME_LENGTH < frame_length ) { + silk_assert( frame_length == 12 * 10 ); /* Make sure only happens for 10 ms @ 12 kHz */ + iter++; + silk_memset( &pulses[ frame_length ], 0, SHELL_CODEC_FRAME_LENGTH * sizeof(opus_int8)); + } + + /* Take the absolute value of the pulses */ + for( i = 0; i < iter * SHELL_CODEC_FRAME_LENGTH; i+=4 ) { + abs_pulses[i+0] = ( opus_int )silk_abs( pulses[ i + 0 ] ); + abs_pulses[i+1] = ( opus_int )silk_abs( pulses[ i + 1 ] ); + abs_pulses[i+2] = ( opus_int )silk_abs( pulses[ i + 2 ] ); + abs_pulses[i+3] = ( opus_int )silk_abs( pulses[ 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, silk_max_pulses_table[ 0 ], 8 ); + /* 2+2 -> 4 */ + scale_down += combine_and_check( pulses_comb, pulses_comb, silk_max_pulses_table[ 1 ], 4 ); + /* 4+4 -> 8 */ + scale_down += combine_and_check( pulses_comb, pulses_comb, silk_max_pulses_table[ 2 ], 2 ); + /* 8+8 -> 16 */ + scale_down += combine_and_check( &sum_pulses[ i ], pulses_comb, silk_max_pulses_table[ 3 ], 1 ); + + if( scale_down ) { + /* We need to downscale the quantization signal */ + nRshifts[ i ]++; + for( k = 0; k < SHELL_CODEC_FRAME_LENGTH; k++ ) { + abs_pulses_ptr[ k ] = silk_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_Q5 = silk_int32_MAX; + for( k = 0; k < N_RATE_LEVELS - 1; k++ ) { + nBits_ptr = silk_pulses_per_block_BITS_Q5[ k ]; + sumBits_Q5 = silk_rate_levels_BITS_Q5[ signalType >> 1 ][ k ]; + for( i = 0; i < iter; i++ ) { + if( nRshifts[ i ] > 0 ) { + sumBits_Q5 += nBits_ptr[ MAX_PULSES + 1 ]; + } else { + sumBits_Q5 += nBits_ptr[ sum_pulses[ i ] ]; + } + } + if( sumBits_Q5 < minSumBits_Q5 ) { + minSumBits_Q5 = sumBits_Q5; + RateLevelIndex = k; + } + } + ec_enc_icdf( psRangeEnc, RateLevelIndex, silk_rate_levels_iCDF[ signalType >> 1 ], 8 ); + + /***************************************************/ + /* Sum-Weighted-Pulses Encoding */ + /***************************************************/ + cdf_ptr = silk_pulses_per_block_iCDF[ RateLevelIndex ]; + for( i = 0; i < iter; i++ ) { + if( nRshifts[ i ] == 0 ) { + ec_enc_icdf( psRangeEnc, sum_pulses[ i ], cdf_ptr, 8 ); + } else { + ec_enc_icdf( psRangeEnc, MAX_PULSES + 1, cdf_ptr, 8 ); + for( k = 0; k < nRshifts[ i ] - 1; k++ ) { + ec_enc_icdf( psRangeEnc, MAX_PULSES + 1, silk_pulses_per_block_iCDF[ N_RATE_LEVELS - 1 ], 8 ); + } + ec_enc_icdf( psRangeEnc, sum_pulses[ i ], silk_pulses_per_block_iCDF[ N_RATE_LEVELS - 1 ], 8 ); + } + } + + /******************/ + /* Shell Encoding */ + /******************/ + for( i = 0; i < iter; i++ ) { + if( sum_pulses[ i ] > 0 ) { + silk_shell_encoder( psRangeEnc, &abs_pulses[ i * SHELL_CODEC_FRAME_LENGTH ] ); + } + } + + /****************/ + /* LSB Encoding */ + /****************/ + for( i = 0; i < iter; i++ ) { + if( nRshifts[ i ] > 0 ) { + pulses_ptr = &pulses[ i * SHELL_CODEC_FRAME_LENGTH ]; + nLS = nRshifts[ i ] - 1; + for( k = 0; k < SHELL_CODEC_FRAME_LENGTH; k++ ) { + abs_q = (opus_int8)silk_abs( pulses_ptr[ k ] ); + for( j = nLS; j > 0; j-- ) { + bit = silk_RSHIFT( abs_q, j ) & 1; + ec_enc_icdf( psRangeEnc, bit, silk_lsb_iCDF, 8 ); + } + bit = abs_q & 1; + ec_enc_icdf( psRangeEnc, bit, silk_lsb_iCDF, 8 ); + } + } + } + + /****************/ + /* Encode signs */ + /****************/ + silk_encode_signs( psRangeEnc, pulses, frame_length, signalType, quantOffsetType, sum_pulses ); +} diff --git a/code/opus-1.0.2/silk/errors.h b/code/opus-1.0.2/silk/errors.h new file mode 100644 index 00000000..0591e009 --- /dev/null +++ b/code/opus-1.0.2/silk/errors.h @@ -0,0 +1,98 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (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 SILK_ERRORS_H +#define SILK_ERRORS_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/******************/ +/* Error messages */ +/******************/ +#define SILK_NO_ERROR 0 + +/**************************/ +/* Encoder error messages */ +/**************************/ + +/* Input length is not a multiple of 10 ms, or length is longer than the packet length */ +#define SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES -101 + +/* Sampling frequency not 8000, 12000 or 16000 Hertz */ +#define SILK_ENC_FS_NOT_SUPPORTED -102 + +/* Packet size not 10, 20, 40, or 60 ms */ +#define SILK_ENC_PACKET_SIZE_NOT_SUPPORTED -103 + +/* Allocated payload buffer too short */ +#define SILK_ENC_PAYLOAD_BUF_TOO_SHORT -104 + +/* Loss rate not between 0 and 100 percent */ +#define SILK_ENC_INVALID_LOSS_RATE -105 + +/* Complexity setting not valid, use 0...10 */ +#define SILK_ENC_INVALID_COMPLEXITY_SETTING -106 + +/* Inband FEC setting not valid, use 0 or 1 */ +#define SILK_ENC_INVALID_INBAND_FEC_SETTING -107 + +/* DTX setting not valid, use 0 or 1 */ +#define SILK_ENC_INVALID_DTX_SETTING -108 + +/* CBR setting not valid, use 0 or 1 */ +#define SILK_ENC_INVALID_CBR_SETTING -109 + +/* Internal encoder error */ +#define SILK_ENC_INTERNAL_ERROR -110 + +/* Internal encoder error */ +#define SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR -111 + +/**************************/ +/* Decoder error messages */ +/**************************/ + +/* Output sampling frequency lower than internal decoded sampling frequency */ +#define SILK_DEC_INVALID_SAMPLING_FREQUENCY -200 + +/* Payload size exceeded the maximum allowed 1024 bytes */ +#define SILK_DEC_PAYLOAD_TOO_LARGE -201 + +/* Payload has bit errors */ +#define SILK_DEC_PAYLOAD_ERROR -202 + +/* Payload has bit errors */ +#define SILK_DEC_INVALID_FRAME_SIZE -203 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/code/opus-1.0.2/silk/fixed/LTP_analysis_filter_FIX.c b/code/opus-1.0.2/silk/fixed/LTP_analysis_filter_FIX.c new file mode 100644 index 00000000..a8fee555 --- /dev/null +++ b/code/opus-1.0.2/silk/fixed/LTP_analysis_filter_FIX.c @@ -0,0 +1,85 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" + +void silk_LTP_analysis_filter_FIX( + opus_int16 *LTP_res, /* O LTP residual signal of length MAX_NB_SUBFR * ( pre_length + subfr_length ) */ + const opus_int16 *x, /* I Pointer to input signal with at least max( pitchL ) preceding samples */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ],/* I LTP_ORDER LTP coefficients for each MAX_NB_SUBFR subframe */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag, one for each subframe */ + const opus_int32 invGains_Q16[ MAX_NB_SUBFR ], /* I Inverse quantization gains, one for each subframe */ + const opus_int subfr_length, /* I Length of each subframe */ + const opus_int nb_subfr, /* I Number of subframes */ + const opus_int pre_length /* I Length of the preceding samples starting at &x[0] for each subframe */ +) +{ + const opus_int16 *x_ptr, *x_lag_ptr; + opus_int16 Btmp_Q14[ LTP_ORDER ]; + opus_int16 *LTP_res_ptr; + opus_int k, i, j; + opus_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 = silk_SMULBB( x_lag_ptr[ LTP_ORDER / 2 ], Btmp_Q14[ 0 ] ); + for( j = 1; j < LTP_ORDER; j++ ) { + LTP_est = silk_SMLABB_ovflw( LTP_est, x_lag_ptr[ LTP_ORDER / 2 - j ], Btmp_Q14[ j ] ); + } + LTP_est = silk_RSHIFT_ROUND( LTP_est, 14 ); /* round and -> Q0*/ + + /* Subtract long-term prediction */ + LTP_res_ptr[ i ] = (opus_int16)silk_SAT16( (opus_int32)x_ptr[ i ] - LTP_est ); + + /* Scale residual */ + LTP_res_ptr[ i ] = silk_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/code/opus-1.0.2/silk/fixed/LTP_scale_ctrl_FIX.c b/code/opus-1.0.2/silk/fixed/LTP_scale_ctrl_FIX.c new file mode 100644 index 00000000..ac2fba17 --- /dev/null +++ b/code/opus-1.0.2/silk/fixed/LTP_scale_ctrl_FIX.c @@ -0,0 +1,53 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" + +/* Calculation of LTP state scaling */ +void silk_LTP_scale_ctrl_FIX( + silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + opus_int round_loss; + + if( condCoding == CODE_INDEPENDENTLY ) { + /* Only scale if first frame in packet */ + round_loss = psEnc->sCmn.PacketLoss_perc + psEnc->sCmn.nFramesPerPacket; + psEnc->sCmn.indices.LTP_scaleIndex = (opus_int8)silk_LIMIT( + silk_SMULWB( silk_SMULBB( round_loss, psEncCtrl->LTPredCodGain_Q7 ), SILK_FIX_CONST( 0.1, 9 ) ), 0, 2 ); + } else { + /* Default is minimum scaling */ + psEnc->sCmn.indices.LTP_scaleIndex = 0; + } + psEncCtrl->LTP_scale_Q14 = silk_LTPScales_table_Q14[ psEnc->sCmn.indices.LTP_scaleIndex ]; +} diff --git a/code/opus-1.0.2/silk/fixed/apply_sine_window_FIX.c b/code/opus-1.0.2/silk/fixed/apply_sine_window_FIX.c new file mode 100644 index 00000000..897fdc30 --- /dev/null +++ b/code/opus-1.0.2/silk/fixed/apply_sine_window_FIX.c @@ -0,0 +1,101 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "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 const opus_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, +}; + +void silk_apply_sine_window( + opus_int16 px_win[], /* O Pointer to windowed signal */ + const opus_int16 px[], /* I Pointer to input signal */ + const opus_int win_type, /* I Selects a window type */ + const opus_int length /* I Window length, multiple of 4 */ +) +{ + opus_int k, f_Q16, c_Q16; + opus_int32 S0_Q16, S1_Q16; + + silk_assert( win_type == 1 || win_type == 2 ); + + /* Length must be in a range from 16 to 120 and a multiple of 4 */ + silk_assert( length >= 16 && length <= 120 ); + silk_assert( ( length & 3 ) == 0 ); + + /* Frequency */ + k = ( length >> 2 ) - 4; + silk_assert( k >= 0 && k <= 26 ); + f_Q16 = (opus_int)freq_table_Q16[ k ]; + + /* Factor used for cosine approximation */ + c_Q16 = silk_SMULWB( (opus_int32)f_Q16, -f_Q16 ); + silk_assert( c_Q16 >= -32768 ); + + /* initialize state */ + if( win_type == 1 ) { + /* start from 0 */ + S0_Q16 = 0; + /* approximation of sin(f) */ + S1_Q16 = f_Q16 + silk_RSHIFT( length, 3 ); + } else { + /* start from 1 */ + S0_Q16 = ( (opus_int32)1 << 16 ); + /* approximation of cos(f) */ + S1_Q16 = ( (opus_int32)1 << 16 ) + silk_RSHIFT( c_Q16, 1 ) + silk_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 */ + for( k = 0; k < length; k += 4 ) { + px_win[ k ] = (opus_int16)silk_SMULWB( silk_RSHIFT( S0_Q16 + S1_Q16, 1 ), px[ k ] ); + px_win[ k + 1 ] = (opus_int16)silk_SMULWB( S1_Q16, px[ k + 1] ); + S0_Q16 = silk_SMULWB( S1_Q16, c_Q16 ) + silk_LSHIFT( S1_Q16, 1 ) - S0_Q16 + 1; + S0_Q16 = silk_min( S0_Q16, ( (opus_int32)1 << 16 ) ); + + px_win[ k + 2 ] = (opus_int16)silk_SMULWB( silk_RSHIFT( S0_Q16 + S1_Q16, 1 ), px[ k + 2] ); + px_win[ k + 3 ] = (opus_int16)silk_SMULWB( S0_Q16, px[ k + 3 ] ); + S1_Q16 = silk_SMULWB( S0_Q16, c_Q16 ) + silk_LSHIFT( S0_Q16, 1 ) - S1_Q16; + S1_Q16 = silk_min( S1_Q16, ( (opus_int32)1 << 16 ) ); + } +} diff --git a/code/opus-1.0.2/silk/fixed/autocorr_FIX.c b/code/opus-1.0.2/silk/fixed/autocorr_FIX.c new file mode 100644 index 00000000..c2ebb6a9 --- /dev/null +++ b/code/opus-1.0.2/silk/fixed/autocorr_FIX.c @@ -0,0 +1,76 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Compute autocorrelation */ +void silk_autocorr( + opus_int32 *results, /* O Result (length correlationCount) */ + opus_int *scale, /* O Scaling of the correlation vector */ + const opus_int16 *inputData, /* I Input data to correlate */ + const opus_int inputDataSize, /* I Length of input */ + const opus_int correlationCount /* I Number of correlation taps to compute */ +) +{ + opus_int i, lz, nRightShifts, corrCount; + opus_int64 corr64; + + corrCount = silk_min_int( inputDataSize, correlationCount ); + + /* compute energy (zero-lag correlation) */ + corr64 = silk_inner_prod16_aligned_64( inputData, inputData, inputDataSize ); + + /* deal with all-zero input data */ + corr64 += 1; + + /* number of leading zeros */ + lz = silk_CLZ64( corr64 ); + + /* scaling: number of right shifts applied to correlations */ + nRightShifts = 35 - lz; + *scale = nRightShifts; + + if( nRightShifts <= 0 ) { + results[ 0 ] = silk_LSHIFT( (opus_int32)silk_CHECK_FIT32( corr64 ), -nRightShifts ); + + /* compute remaining correlations based on int32 inner product */ + for( i = 1; i < corrCount; i++ ) { + results[ i ] = silk_LSHIFT( silk_inner_prod_aligned( inputData, inputData + i, inputDataSize - i ), -nRightShifts ); + } + } else { + results[ 0 ] = (opus_int32)silk_CHECK_FIT32( silk_RSHIFT64( corr64, nRightShifts ) ); + + /* compute remaining correlations based on int64 inner product */ + for( i = 1; i < corrCount; i++ ) { + results[ i ] = (opus_int32)silk_CHECK_FIT32( silk_RSHIFT64( silk_inner_prod16_aligned_64( inputData, inputData + i, inputDataSize - i ), nRightShifts ) ); + } + } +} diff --git a/code/opus-1.0.2/silk/fixed/burg_modified_FIX.c b/code/opus-1.0.2/silk/fixed/burg_modified_FIX.c new file mode 100644 index 00000000..26a66b1c --- /dev/null +++ b/code/opus-1.0.2/silk/fixed/burg_modified_FIX.c @@ -0,0 +1,269 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "define.h" +#include "tuning_parameters.h" + +#define MAX_FRAME_SIZE 384 /* subfr_length * nb_subfr = ( 0.005 * 16000 + 16 ) * 4 = 384 */ + +#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 silk_burg_modified( + opus_int32 *res_nrg, /* O Residual energy */ + opus_int *res_nrg_Q, /* O Residual energy Q value */ + opus_int32 A_Q16[], /* O Prediction coefficients (length order) */ + const opus_int16 x[], /* I Input signal, length: nb_subfr * ( D + subfr_length ) */ + const opus_int32 minInvGain_Q30, /* I Inverse of max prediction gain */ + const opus_int subfr_length, /* I Input signal subframe length (incl. D preceding samples) */ + const opus_int nb_subfr, /* I Number of subframes stacked in x */ + const opus_int D /* I Order */ +) +{ + opus_int k, n, s, lz, rshifts, rshifts_extra, reached_max_gain; + opus_int32 C0, num, nrg, rc_Q31, invGain_Q30, Atmp_QA, Atmp1, tmp1, tmp2, x1, x2; + const opus_int16 *x_ptr; + opus_int32 C_first_row[ SILK_MAX_ORDER_LPC ]; + opus_int32 C_last_row[ SILK_MAX_ORDER_LPC ]; + opus_int32 Af_QA[ SILK_MAX_ORDER_LPC ]; + opus_int32 CAf[ SILK_MAX_ORDER_LPC + 1 ]; + opus_int32 CAb[ SILK_MAX_ORDER_LPC + 1 ]; + + silk_assert( subfr_length * nb_subfr <= MAX_FRAME_SIZE ); + + /* Compute autocorrelations, added over subframes */ + silk_sum_sqr_shift( &C0, &rshifts, x, nb_subfr * subfr_length ); + if( rshifts > MAX_RSHIFTS ) { + C0 = silk_LSHIFT32( C0, rshifts - MAX_RSHIFTS ); + silk_assert( C0 > 0 ); + rshifts = MAX_RSHIFTS; + } else { + lz = silk_CLZ32( C0 ) - 1; + rshifts_extra = N_BITS_HEAD_ROOM - lz; + if( rshifts_extra > 0 ) { + rshifts_extra = silk_min( rshifts_extra, MAX_RSHIFTS - rshifts ); + C0 = silk_RSHIFT32( C0, rshifts_extra ); + } else { + rshifts_extra = silk_max( rshifts_extra, MIN_RSHIFTS - rshifts ); + C0 = silk_LSHIFT32( C0, -rshifts_extra ); + } + rshifts += rshifts_extra; + } + CAb[ 0 ] = CAf[ 0 ] = C0 + silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ) + 1; /* Q(-rshifts) */ + silk_memset( C_first_row, 0, SILK_MAX_ORDER_LPC * sizeof( opus_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 ] += (opus_int32)silk_RSHIFT64( + 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 ] += silk_LSHIFT32( + silk_inner_prod_aligned( x_ptr, x_ptr + n, subfr_length - n ), -rshifts ); + } + } + } + silk_memcpy( C_last_row, C_first_row, SILK_MAX_ORDER_LPC * sizeof( opus_int32 ) ); + + /* Initialize */ + CAb[ 0 ] = CAf[ 0 ] = C0 + silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ) + 1; /* Q(-rshifts) */ + + invGain_Q30 = (opus_int32)1 << 30; + reached_max_gain = 0; + 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 = -silk_LSHIFT32( (opus_int32)x_ptr[ n ], 16 - rshifts ); /* Q(16-rshifts) */ + x2 = -silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], 16 - rshifts ); /* Q(16-rshifts) */ + tmp1 = silk_LSHIFT32( (opus_int32)x_ptr[ n ], QA - 16 ); /* Q(QA-16) */ + tmp2 = silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], QA - 16 ); /* Q(QA-16) */ + for( k = 0; k < n; k++ ) { + C_first_row[ k ] = silk_SMLAWB( C_first_row[ k ], x1, x_ptr[ n - k - 1 ] ); /* Q( -rshifts ) */ + C_last_row[ k ] = silk_SMLAWB( C_last_row[ k ], x2, x_ptr[ subfr_length - n + k ] ); /* Q( -rshifts ) */ + Atmp_QA = Af_QA[ k ]; + tmp1 = silk_SMLAWB( tmp1, Atmp_QA, x_ptr[ n - k - 1 ] ); /* Q(QA-16) */ + tmp2 = silk_SMLAWB( tmp2, Atmp_QA, x_ptr[ subfr_length - n + k ] ); /* Q(QA-16) */ + } + tmp1 = silk_LSHIFT32( -tmp1, 32 - QA - rshifts ); /* Q(16-rshifts) */ + tmp2 = silk_LSHIFT32( -tmp2, 32 - QA - rshifts ); /* Q(16-rshifts) */ + for( k = 0; k <= n; k++ ) { + CAf[ k ] = silk_SMLAWB( CAf[ k ], tmp1, x_ptr[ n - k ] ); /* Q( -rshift ) */ + CAb[ k ] = silk_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 = -silk_LSHIFT32( (opus_int32)x_ptr[ n ], -rshifts ); /* Q( -rshifts ) */ + x2 = -silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], -rshifts ); /* Q( -rshifts ) */ + tmp1 = silk_LSHIFT32( (opus_int32)x_ptr[ n ], 17 ); /* Q17 */ + tmp2 = silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], 17 ); /* Q17 */ + for( k = 0; k < n; k++ ) { + C_first_row[ k ] = silk_MLA( C_first_row[ k ], x1, x_ptr[ n - k - 1 ] ); /* Q( -rshifts ) */ + C_last_row[ k ] = silk_MLA( C_last_row[ k ], x2, x_ptr[ subfr_length - n + k ] ); /* Q( -rshifts ) */ + Atmp1 = silk_RSHIFT_ROUND( Af_QA[ k ], QA - 17 ); /* Q17 */ + tmp1 = silk_MLA( tmp1, x_ptr[ n - k - 1 ], Atmp1 ); /* Q17 */ + tmp2 = silk_MLA( tmp2, x_ptr[ subfr_length - n + k ], Atmp1 ); /* Q17 */ + } + tmp1 = -tmp1; /* Q17 */ + tmp2 = -tmp2; /* Q17 */ + for( k = 0; k <= n; k++ ) { + CAf[ k ] = silk_SMLAWW( CAf[ k ], tmp1, + silk_LSHIFT32( (opus_int32)x_ptr[ n - k ], -rshifts - 1 ) ); /* Q( -rshift ) */ + CAb[ k ] = silk_SMLAWW( CAb[ k ], tmp2, + silk_LSHIFT32( (opus_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 = silk_ADD32( CAb[ 0 ], CAf[ 0 ] ); /* Q( 1-rshifts ) */ + for( k = 0; k < n; k++ ) { + Atmp_QA = Af_QA[ k ]; + lz = silk_CLZ32( silk_abs( Atmp_QA ) ) - 1; + lz = silk_min( 32 - QA, lz ); + Atmp1 = silk_LSHIFT32( Atmp_QA, lz ); /* Q( QA + lz ) */ + + tmp1 = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( C_last_row[ n - k - 1 ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */ + tmp2 = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( C_first_row[ n - k - 1 ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */ + num = silk_ADD_LSHIFT32( num, silk_SMMUL( CAb[ n - k ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */ + nrg = silk_ADD_LSHIFT32( nrg, silk_SMMUL( silk_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 = silk_ADD32( num, tmp2 ); /* Q( -rshifts ) */ + num = silk_LSHIFT32( -num, 1 ); /* Q( 1-rshifts ) */ + + /* Calculate the next order reflection (parcor) coefficient */ + if( silk_abs( num ) < nrg ) { + rc_Q31 = silk_DIV32_varQ( num, nrg, 31 ); + } else { + rc_Q31 = ( num > 0 ) ? silk_int32_MAX : silk_int32_MIN; + } + + /* Update inverse prediction gain */ + tmp1 = ( (opus_int32)1 << 30 ) - silk_SMMUL( rc_Q31, rc_Q31 ); + tmp1 = silk_LSHIFT( silk_SMMUL( invGain_Q30, tmp1 ), 2 ); + if( tmp1 <= minInvGain_Q30 ) { + /* Max prediction gain exceeded; set reflection coefficient such that max prediction gain is exactly hit */ + tmp2 = ( (opus_int32)1 << 30 ) - silk_DIV32_varQ( minInvGain_Q30, invGain_Q30, 30 ); /* Q30 */ + rc_Q31 = silk_SQRT_APPROX( tmp2 ); /* Q15 */ + /* Newton-Raphson iteration */ + rc_Q31 = silk_RSHIFT32( rc_Q31 + silk_DIV32( tmp2, rc_Q31 ), 1 ); /* Q15 */ + rc_Q31 = silk_LSHIFT32( rc_Q31, 16 ); /* Q31 */ + if( num < 0 ) { + /* Ensure adjusted reflection coefficients has the original sign */ + rc_Q31 = -rc_Q31; + } + invGain_Q30 = minInvGain_Q30; + reached_max_gain = 1; + } else { + invGain_Q30 = tmp1; + } + + /* 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 ] = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( tmp2, rc_Q31 ), 1 ); /* QA */ + Af_QA[ n - k - 1 ] = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( tmp1, rc_Q31 ), 1 ); /* QA */ + } + Af_QA[ n ] = silk_RSHIFT32( rc_Q31, 31 - QA ); /* QA */ + + if( reached_max_gain ) { + /* Reached max prediction gain; set remaining coefficients to zero and exit loop */ + for( k = n + 1; k < D; k++ ) { + Af_QA[ k ] = 0; + } + break; + } + + /* 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 ] = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( tmp2, rc_Q31 ), 1 ); /* Q( -rshifts ) */ + CAb[ n - k + 1 ] = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( tmp1, rc_Q31 ), 1 ); /* Q( -rshifts ) */ + } + } + + if( reached_max_gain ) { + for( k = 0; k < D; k++ ) { + /* Scale coefficients */ + A_Q16[ k ] = -silk_RSHIFT_ROUND( Af_QA[ k ], QA - 16 ); + } + /* Subtract energy of preceding samples from C0 */ + if( rshifts > 0 ) { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + C0 -= (opus_int32)silk_RSHIFT64( silk_inner_prod16_aligned_64( x_ptr, x_ptr, D ), rshifts ); + } + } else { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + C0 -= silk_LSHIFT32( silk_inner_prod_aligned( x_ptr, x_ptr, D ), -rshifts ); + } + } + /* Approximate residual energy */ + *res_nrg = silk_LSHIFT( silk_SMMUL( invGain_Q30, C0 ), 2 ); + *res_nrg_Q = -rshifts; + } else { + /* Return residual energy */ + nrg = CAf[ 0 ]; /* Q( -rshifts ) */ + tmp1 = (opus_int32)1 << 16; /* Q16 */ + for( k = 0; k < D; k++ ) { + Atmp1 = silk_RSHIFT_ROUND( Af_QA[ k ], QA - 16 ); /* Q16 */ + nrg = silk_SMLAWW( nrg, CAf[ k + 1 ], Atmp1 ); /* Q( -rshifts ) */ + tmp1 = silk_SMLAWW( tmp1, Atmp1, Atmp1 ); /* Q16 */ + A_Q16[ k ] = -Atmp1; + } + *res_nrg = silk_SMLAWW( nrg, silk_SMMUL( FIND_LPC_COND_FAC, C0 ), -tmp1 ); /* Q( -rshifts ) */ + *res_nrg_Q = -rshifts; + } +} diff --git a/code/opus-1.0.2/silk/fixed/corrMatrix_FIX.c b/code/opus-1.0.2/silk/fixed/corrMatrix_FIX.c new file mode 100644 index 00000000..21502499 --- /dev/null +++ b/code/opus-1.0.2/silk/fixed/corrMatrix_FIX.c @@ -0,0 +1,156 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/********************************************************************** + * Correlation Matrix Computations for LS estimate. + **********************************************************************/ + +#include "main_FIX.h" + +/* Calculates correlation vector X'*t */ +void silk_corrVector_FIX( + const opus_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */ + const opus_int16 *t, /* I Target vector [L] */ + const opus_int L, /* I Length of vectors */ + const opus_int order, /* I Max lag for correlation */ + opus_int32 *Xt, /* O Pointer to X'*t correlation vector [order] */ + const opus_int rshifts /* I Right shifts of correlations */ +) +{ + opus_int lag, i; + const opus_int16 *ptr1, *ptr2; + opus_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 += silk_RSHIFT32( silk_SMULBB( ptr1[ i ], ptr2[i] ), rshifts ); + } + Xt[ lag ] = inner_prod; /* X[:,lag]'*t */ + ptr1--; /* Go to next column of X */ + } + } else { + silk_assert( rshifts == 0 ); + for( lag = 0; lag < order; lag++ ) { + Xt[ lag ] = silk_inner_prod_aligned( ptr1, ptr2, L ); /* X[:,lag]'*t */ + ptr1--; /* Go to next column of X */ + } + } +} + +/* Calculates correlation matrix X'*X */ +void silk_corrMatrix_FIX( + const opus_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */ + const opus_int L, /* I Length of vectors */ + const opus_int order, /* I Max lag for correlation */ + const opus_int head_room, /* I Desired headroom */ + opus_int32 *XX, /* O Pointer to X'*X correlation matrix [ order x order ] */ + opus_int *rshifts /* I/O Right shifts of correlations */ +) +{ + opus_int i, j, lag, rshifts_local, head_room_rshifts; + opus_int32 energy; + const opus_int16 *ptr1, *ptr2; + + /* Calculate energy to find shift used to fit in 32 bits */ + silk_sum_sqr_shift( &energy, &rshifts_local, x, L + order - 1 ); + /* Add shifts to get the desired head room */ + head_room_rshifts = silk_max( head_room - silk_CLZ32( energy ), 0 ); + + energy = silk_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 -= silk_RSHIFT32( silk_SMULBB( x[ i ], x[ i ] ), rshifts_local ); + } + if( rshifts_local < *rshifts ) { + /* Adjust energy */ + energy = silk_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 = silk_SUB32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ L - j ], ptr1[ L - j ] ), rshifts_local ) ); + energy = silk_ADD32( energy, silk_RSHIFT32( silk_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 += silk_RSHIFT32( silk_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 = silk_SUB32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ L - j ], ptr2[ L - j ] ), rshifts_local ) ); + energy = silk_ADD32( energy, silk_RSHIFT32( silk_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 = 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 = silk_SUB32( energy, silk_SMULBB( ptr1[ L - j ], ptr2[ L - j ] ) ); + energy = silk_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/code/opus-1.0.2/silk/fixed/encode_frame_FIX.c b/code/opus-1.0.2/silk/fixed/encode_frame_FIX.c new file mode 100644 index 00000000..a37a9f21 --- /dev/null +++ b/code/opus-1.0.2/silk/fixed/encode_frame_FIX.c @@ -0,0 +1,372 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" +#include "tuning_parameters.h" + +/* Low Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode with lower bitrate */ +static inline void silk_LBRR_encode_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O Pointer to Silk FIX encoder control struct */ + const opus_int32 xfw_Q3[], /* I Input signal */ + opus_int condCoding /* I The type of conditional coding used so far for this frame */ +); + +void silk_encode_do_VAD_FIX( + silk_encoder_state_FIX *psEnc /* I/O Pointer to Silk FIX encoder state */ +) +{ + /****************************/ + /* Voice Activity Detection */ + /****************************/ + silk_VAD_GetSA_Q8( &psEnc->sCmn, psEnc->sCmn.inputBuf + 1 ); + + /**************************************************/ + /* Convert speech activity into VAD and DTX flags */ + /**************************************************/ + if( psEnc->sCmn.speech_activity_Q8 < SILK_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 ) ) { + psEnc->sCmn.indices.signalType = TYPE_NO_VOICE_ACTIVITY; + psEnc->sCmn.noSpeechCounter++; + if( psEnc->sCmn.noSpeechCounter < NB_SPEECH_FRAMES_BEFORE_DTX ) { + psEnc->sCmn.inDTX = 0; + } else if( psEnc->sCmn.noSpeechCounter > MAX_CONSECUTIVE_DTX + NB_SPEECH_FRAMES_BEFORE_DTX ) { + psEnc->sCmn.noSpeechCounter = NB_SPEECH_FRAMES_BEFORE_DTX; + psEnc->sCmn.inDTX = 0; + } + psEnc->sCmn.VAD_flags[ psEnc->sCmn.nFramesEncoded ] = 0; + } else { + psEnc->sCmn.noSpeechCounter = 0; + psEnc->sCmn.inDTX = 0; + psEnc->sCmn.indices.signalType = TYPE_UNVOICED; + psEnc->sCmn.VAD_flags[ psEnc->sCmn.nFramesEncoded ] = 1; + } +} + +/****************/ +/* Encode frame */ +/****************/ +opus_int silk_encode_frame_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */ + opus_int32 *pnBytesOut, /* O Pointer to number of payload bytes; */ + ec_enc *psRangeEnc, /* I/O compressor data structure */ + opus_int condCoding, /* I The type of conditional coding to use */ + opus_int maxBits, /* I If > 0: maximum number of output bits */ + opus_int useCBR /* I Flag to force constant-bitrate operation */ +) +{ + silk_encoder_control_FIX sEncCtrl; + opus_int i, iter, maxIter, found_upper, found_lower, ret = 0; + opus_int16 *x_frame, *res_pitch_frame; + opus_int32 xfw_Q3[ MAX_FRAME_LENGTH ]; + opus_int16 res_pitch[ 2 * MAX_FRAME_LENGTH + LA_PITCH_MAX ]; + ec_enc sRangeEnc_copy, sRangeEnc_copy2; + silk_nsq_state sNSQ_copy, sNSQ_copy2; + opus_int32 seed_copy, nBits, nBits_lower, nBits_upper, gainMult_lower, gainMult_upper; + opus_int32 gainsID, gainsID_lower, gainsID_upper; + opus_int16 gainMult_Q8; + opus_int16 ec_prevLagIndex_copy; + opus_int ec_prevSignalType_copy; + opus_int8 LastGainIndex_copy2; + opus_uint8 ec_buf_copy[ 1275 ]; + + /* This is totally unnecessary but many compilers (including gcc) are too dumb to realise it */ + LastGainIndex_copy2 = nBits_lower = nBits_upper = gainMult_lower = gainMult_upper = 0; + + psEnc->sCmn.indices.Seed = psEnc->sCmn.frameCounter++ & 3; + + /**************************************************************/ + /* Set up Input Pointers, and insert frame in input buffer */ + /*************************************************************/ + /* pointers aligned with start of frame to encode */ + x_frame = psEnc->x_buf + psEnc->sCmn.ltp_mem_length; /* start of frame to encode */ + res_pitch_frame = res_pitch + psEnc->sCmn.ltp_mem_length; /* start of pitch LPC residual frame */ + + /***************************************/ + /* Ensure smooth bandwidth transitions */ + /***************************************/ + silk_LP_variable_cutoff( &psEnc->sCmn.sLP, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length ); + + /*******************************************/ + /* Copy new frame to front of input buffer */ + /*******************************************/ + silk_memcpy( x_frame + LA_SHAPE_MS * psEnc->sCmn.fs_kHz, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length * sizeof( opus_int16 ) ); + + if( !psEnc->sCmn.prefillFlag ) { + /*****************************************/ + /* Find pitch lags, initial LPC analysis */ + /*****************************************/ + silk_find_pitch_lags_FIX( psEnc, &sEncCtrl, res_pitch, x_frame ); + + /************************/ + /* Noise shape analysis */ + /************************/ + silk_noise_shape_analysis_FIX( psEnc, &sEncCtrl, res_pitch_frame, x_frame ); + + /***************************************************/ + /* Find linear prediction coefficients (LPC + LTP) */ + /***************************************************/ + silk_find_pred_coefs_FIX( psEnc, &sEncCtrl, res_pitch, x_frame, condCoding ); + + /****************************************/ + /* Process gains */ + /****************************************/ + silk_process_gains_FIX( psEnc, &sEncCtrl, condCoding ); + + /*****************************************/ + /* Prefiltering for noise shaper */ + /*****************************************/ + silk_prefilter_FIX( psEnc, &sEncCtrl, xfw_Q3, x_frame ); + + /****************************************/ + /* Low Bitrate Redundant Encoding */ + /****************************************/ + silk_LBRR_encode_FIX( psEnc, &sEncCtrl, xfw_Q3, condCoding ); + + /* Loop over quantizer and entropy coding to control bitrate */ + maxIter = 6; + gainMult_Q8 = SILK_FIX_CONST( 1, 8 ); + found_lower = 0; + found_upper = 0; + gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr ); + gainsID_lower = -1; + gainsID_upper = -1; + /* Copy part of the input state */ + silk_memcpy( &sRangeEnc_copy, psRangeEnc, sizeof( ec_enc ) ); + silk_memcpy( &sNSQ_copy, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) ); + seed_copy = psEnc->sCmn.indices.Seed; + ec_prevLagIndex_copy = psEnc->sCmn.ec_prevLagIndex; + ec_prevSignalType_copy = psEnc->sCmn.ec_prevSignalType; + for( iter = 0; ; iter++ ) { + if( gainsID == gainsID_lower ) { + nBits = nBits_lower; + } else if( gainsID == gainsID_upper ) { + nBits = nBits_upper; + } else { + /* Restore part of the input state */ + if( iter > 0 ) { + silk_memcpy( psRangeEnc, &sRangeEnc_copy, sizeof( ec_enc ) ); + silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy, sizeof( silk_nsq_state ) ); + psEnc->sCmn.indices.Seed = seed_copy; + psEnc->sCmn.ec_prevLagIndex = ec_prevLagIndex_copy; + psEnc->sCmn.ec_prevSignalType = ec_prevSignalType_copy; + } + + /*****************************************/ + /* Noise shaping quantization */ + /*****************************************/ + if( psEnc->sCmn.nStatesDelayedDecision > 1 || psEnc->sCmn.warping_Q16 > 0 ) { + silk_NSQ_del_dec( &psEnc->sCmn, &psEnc->sCmn.sNSQ, &psEnc->sCmn.indices, xfw_Q3, psEnc->sCmn.pulses, + sEncCtrl.PredCoef_Q12[ 0 ], sEncCtrl.LTPCoef_Q14, sEncCtrl.AR2_Q13, sEncCtrl.HarmShapeGain_Q14, + sEncCtrl.Tilt_Q14, sEncCtrl.LF_shp_Q14, sEncCtrl.Gains_Q16, sEncCtrl.pitchL, sEncCtrl.Lambda_Q10, sEncCtrl.LTP_scale_Q14 ); + } else { + silk_NSQ( &psEnc->sCmn, &psEnc->sCmn.sNSQ, &psEnc->sCmn.indices, xfw_Q3, psEnc->sCmn.pulses, + sEncCtrl.PredCoef_Q12[ 0 ], sEncCtrl.LTPCoef_Q14, sEncCtrl.AR2_Q13, sEncCtrl.HarmShapeGain_Q14, + sEncCtrl.Tilt_Q14, sEncCtrl.LF_shp_Q14, sEncCtrl.Gains_Q16, sEncCtrl.pitchL, sEncCtrl.Lambda_Q10, sEncCtrl.LTP_scale_Q14 ); + } + + /****************************************/ + /* Encode Parameters */ + /****************************************/ + silk_encode_indices( &psEnc->sCmn, psRangeEnc, psEnc->sCmn.nFramesEncoded, 0, condCoding ); + + /****************************************/ + /* Encode Excitation Signal */ + /****************************************/ + silk_encode_pulses( psRangeEnc, psEnc->sCmn.indices.signalType, psEnc->sCmn.indices.quantOffsetType, + psEnc->sCmn.pulses, psEnc->sCmn.frame_length ); + + nBits = ec_tell( psRangeEnc ); + + if( useCBR == 0 && iter == 0 && nBits <= maxBits ) { + break; + } + } + + if( iter == maxIter ) { + if( found_lower && ( gainsID == gainsID_lower || nBits > maxBits ) ) { + /* Restore output state from earlier iteration that did meet the bitrate budget */ + silk_memcpy( psRangeEnc, &sRangeEnc_copy2, sizeof( ec_enc ) ); + silk_assert( sRangeEnc_copy2.offs <= 1275 ); + silk_memcpy( psRangeEnc->buf, ec_buf_copy, sRangeEnc_copy2.offs ); + silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy2, sizeof( silk_nsq_state ) ); + psEnc->sShape.LastGainIndex = LastGainIndex_copy2; + } + break; + } + + if( nBits > maxBits ) { + if( found_lower == 0 && iter >= 2 ) { + /* Adjust the quantizer's rate/distortion tradeoff and discard previous "upper" results */ + sEncCtrl.Lambda_Q10 = silk_ADD_RSHIFT32( sEncCtrl.Lambda_Q10, sEncCtrl.Lambda_Q10, 1 ); + found_upper = 0; + gainsID_upper = -1; + } else { + found_upper = 1; + nBits_upper = nBits; + gainMult_upper = gainMult_Q8; + gainsID_upper = gainsID; + } + } else if( nBits < maxBits - 5 ) { + found_lower = 1; + nBits_lower = nBits; + gainMult_lower = gainMult_Q8; + if( gainsID != gainsID_lower ) { + gainsID_lower = gainsID; + /* Copy part of the output state */ + silk_memcpy( &sRangeEnc_copy2, psRangeEnc, sizeof( ec_enc ) ); + silk_assert( psRangeEnc->offs <= 1275 ); + silk_memcpy( ec_buf_copy, psRangeEnc->buf, psRangeEnc->offs ); + silk_memcpy( &sNSQ_copy2, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) ); + LastGainIndex_copy2 = psEnc->sShape.LastGainIndex; + } + } else { + /* Within 5 bits of budget: close enough */ + break; + } + + if( ( found_lower & found_upper ) == 0 ) { + /* Adjust gain according to high-rate rate/distortion curve */ + opus_int32 gain_factor_Q16; + gain_factor_Q16 = silk_log2lin( silk_LSHIFT( nBits - maxBits, 7 ) / psEnc->sCmn.frame_length + SILK_FIX_CONST( 16, 7 ) ); + gain_factor_Q16 = silk_min_32( gain_factor_Q16, SILK_FIX_CONST( 2, 16 ) ); + if( nBits > maxBits ) { + gain_factor_Q16 = silk_max_32( gain_factor_Q16, SILK_FIX_CONST( 1.3, 16 ) ); + } + gainMult_Q8 = silk_SMULWB( gain_factor_Q16, gainMult_Q8 ); + } else { + /* Adjust gain by interpolating */ + gainMult_Q8 = gainMult_lower + silk_DIV32_16( silk_MUL( gainMult_upper - gainMult_lower, maxBits - nBits_lower ), nBits_upper - nBits_lower ); + /* New gain multplier must be between 25% and 75% of old range (note that gainMult_upper < gainMult_lower) */ + if( gainMult_Q8 > silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 ) ) { + gainMult_Q8 = silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 ); + } else + if( gainMult_Q8 < silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 ) ) { + gainMult_Q8 = silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 ); + } + } + + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + sEncCtrl.Gains_Q16[ i ] = silk_LSHIFT_SAT32( silk_SMULWB( sEncCtrl.GainsUnq_Q16[ i ], gainMult_Q8 ), 8 ); + } + + /* Quantize gains */ + psEnc->sShape.LastGainIndex = sEncCtrl.lastGainIndexPrev; + silk_gains_quant( psEnc->sCmn.indices.GainsIndices, sEncCtrl.Gains_Q16, + &psEnc->sShape.LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr ); + + /* Unique identifier of gains vector */ + gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr ); + } + } + + /* Update input buffer */ + silk_memmove( psEnc->x_buf, &psEnc->x_buf[ psEnc->sCmn.frame_length ], + ( psEnc->sCmn.ltp_mem_length + LA_SHAPE_MS * psEnc->sCmn.fs_kHz ) * sizeof( opus_int16 ) ); + + /* Parameters needed for next frame */ + psEnc->sCmn.prevLag = sEncCtrl.pitchL[ psEnc->sCmn.nb_subfr - 1 ]; + psEnc->sCmn.prevSignalType = psEnc->sCmn.indices.signalType; + + /* Exit without entropy coding */ + if( psEnc->sCmn.prefillFlag ) { + /* No payload */ + *pnBytesOut = 0; + return ret; + } + + /****************************************/ + /* Finalize payload */ + /****************************************/ + psEnc->sCmn.first_frame_after_reset = 0; + /* Payload size */ + *pnBytesOut = silk_RSHIFT( ec_tell( psRangeEnc ) + 7, 3 ); + + return ret; +} + +/* Low-Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode excitation at lower bitrate */ +static inline void silk_LBRR_encode_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O Pointer to Silk FIX encoder control struct */ + const opus_int32 xfw_Q3[], /* I Input signal */ + opus_int condCoding /* I The type of conditional coding used so far for this frame */ +) +{ + opus_int32 TempGains_Q16[ MAX_NB_SUBFR ]; + SideInfoIndices *psIndices_LBRR = &psEnc->sCmn.indices_LBRR[ psEnc->sCmn.nFramesEncoded ]; + silk_nsq_state sNSQ_LBRR; + + /*******************************************/ + /* Control use of inband LBRR */ + /*******************************************/ + if( psEnc->sCmn.LBRR_enabled && psEnc->sCmn.speech_activity_Q8 > SILK_FIX_CONST( LBRR_SPEECH_ACTIVITY_THRES, 8 ) ) { + psEnc->sCmn.LBRR_flags[ psEnc->sCmn.nFramesEncoded ] = 1; + + /* Copy noise shaping quantizer state and quantization indices from regular encoding */ + silk_memcpy( &sNSQ_LBRR, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) ); + silk_memcpy( psIndices_LBRR, &psEnc->sCmn.indices, sizeof( SideInfoIndices ) ); + + /* Save original gains */ + silk_memcpy( TempGains_Q16, psEncCtrl->Gains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) ); + + if( psEnc->sCmn.nFramesEncoded == 0 || psEnc->sCmn.LBRR_flags[ psEnc->sCmn.nFramesEncoded - 1 ] == 0 ) { + /* First frame in packet or previous frame not LBRR coded */ + psEnc->sCmn.LBRRprevLastGainIndex = psEnc->sShape.LastGainIndex; + + /* Increase Gains to get target LBRR rate */ + psIndices_LBRR->GainsIndices[ 0 ] = psIndices_LBRR->GainsIndices[ 0 ] + psEnc->sCmn.LBRR_GainIncreases; + psIndices_LBRR->GainsIndices[ 0 ] = silk_min_int( psIndices_LBRR->GainsIndices[ 0 ], N_LEVELS_QGAIN - 1 ); + } + + /* Decode to get gains in sync with decoder */ + /* Overwrite unquantized gains with quantized gains */ + silk_gains_dequant( psEncCtrl->Gains_Q16, psIndices_LBRR->GainsIndices, + &psEnc->sCmn.LBRRprevLastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr ); + + /*****************************************/ + /* Noise shaping quantization */ + /*****************************************/ + if( psEnc->sCmn.nStatesDelayedDecision > 1 || psEnc->sCmn.warping_Q16 > 0 ) { + silk_NSQ_del_dec( &psEnc->sCmn, &sNSQ_LBRR, psIndices_LBRR, xfw_Q3, + psEnc->sCmn.pulses_LBRR[ psEnc->sCmn.nFramesEncoded ], psEncCtrl->PredCoef_Q12[ 0 ], psEncCtrl->LTPCoef_Q14, + psEncCtrl->AR2_Q13, psEncCtrl->HarmShapeGain_Q14, psEncCtrl->Tilt_Q14, psEncCtrl->LF_shp_Q14, + psEncCtrl->Gains_Q16, psEncCtrl->pitchL, psEncCtrl->Lambda_Q10, psEncCtrl->LTP_scale_Q14 ); + } else { + silk_NSQ( &psEnc->sCmn, &sNSQ_LBRR, psIndices_LBRR, xfw_Q3, + psEnc->sCmn.pulses_LBRR[ psEnc->sCmn.nFramesEncoded ], psEncCtrl->PredCoef_Q12[ 0 ], psEncCtrl->LTPCoef_Q14, + psEncCtrl->AR2_Q13, psEncCtrl->HarmShapeGain_Q14, psEncCtrl->Tilt_Q14, psEncCtrl->LF_shp_Q14, + psEncCtrl->Gains_Q16, psEncCtrl->pitchL, psEncCtrl->Lambda_Q10, psEncCtrl->LTP_scale_Q14 ); + } + + /* Restore original gains */ + silk_memcpy( psEncCtrl->Gains_Q16, TempGains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) ); + } +} diff --git a/code/opus-1.0.2/silk/fixed/find_LPC_FIX.c b/code/opus-1.0.2/silk/fixed/find_LPC_FIX.c new file mode 100644 index 00000000..0ed7e846 --- /dev/null +++ b/code/opus-1.0.2/silk/fixed/find_LPC_FIX.c @@ -0,0 +1,145 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" +#include "tuning_parameters.h" + +/* Finds LPC vector from correlations, and converts to NLSF */ +void silk_find_LPC_FIX( + silk_encoder_state *psEncC, /* I/O Encoder state */ + opus_int16 NLSF_Q15[], /* O NLSFs */ + const opus_int16 x[], /* I Input signal */ + const opus_int32 minInvGain_Q30 /* I Inverse of max prediction gain */ +) +{ + opus_int k, subfr_length; + opus_int32 a_Q16[ MAX_LPC_ORDER ]; + opus_int isInterpLower, shift; + opus_int32 res_nrg0, res_nrg1; + opus_int rshift0, rshift1; + + /* Used only for LSF interpolation */ + opus_int32 a_tmp_Q16[ MAX_LPC_ORDER ], res_nrg_interp, res_nrg, res_tmp_nrg; + opus_int res_nrg_interp_Q, res_nrg_Q, res_tmp_nrg_Q; + opus_int16 a_tmp_Q12[ MAX_LPC_ORDER ]; + opus_int16 NLSF0_Q15[ MAX_LPC_ORDER ]; + opus_int16 LPC_res[ MAX_FRAME_LENGTH + MAX_NB_SUBFR * MAX_LPC_ORDER ]; + + subfr_length = psEncC->subfr_length + psEncC->predictLPCOrder; + + /* Default: no interpolation */ + psEncC->indices.NLSFInterpCoef_Q2 = 4; + + /* Burg AR analysis for the full frame */ + silk_burg_modified( &res_nrg, &res_nrg_Q, a_Q16, x, minInvGain_Q30, subfr_length, psEncC->nb_subfr, psEncC->predictLPCOrder ); + + if( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) { + /* Optimal solution for last 10 ms */ + silk_burg_modified( &res_tmp_nrg, &res_tmp_nrg_Q, a_tmp_Q16, x + 2 * subfr_length, minInvGain_Q30, subfr_length, 2, psEncC->predictLPCOrder ); + + /* 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 - silk_RSHIFT( res_tmp_nrg, shift ); + } + } else { + silk_assert( shift > -32 ); + res_nrg = silk_RSHIFT( res_nrg, -shift ) - res_tmp_nrg; + res_nrg_Q = res_tmp_nrg_Q; + } + + /* Convert to NLSFs */ + silk_A2NLSF( NLSF_Q15, a_tmp_Q16, psEncC->predictLPCOrder ); + + /* Search over interpolation indices to find the one with lowest residual energy */ + for( k = 3; k >= 0; k-- ) { + /* Interpolate NLSFs for first half */ + silk_interpolate( NLSF0_Q15, psEncC->prev_NLSFq_Q15, NLSF_Q15, k, psEncC->predictLPCOrder ); + + /* Convert to LPC for residual energy evaluation */ + silk_NLSF2A( a_tmp_Q12, NLSF0_Q15, psEncC->predictLPCOrder ); + + /* Calculate residual energy with NLSF interpolation */ + silk_LPC_analysis_filter( LPC_res, x, a_tmp_Q12, 2 * subfr_length, psEncC->predictLPCOrder ); + + silk_sum_sqr_shift( &res_nrg0, &rshift0, LPC_res + psEncC->predictLPCOrder, subfr_length - psEncC->predictLPCOrder ); + silk_sum_sqr_shift( &res_nrg1, &rshift1, LPC_res + psEncC->predictLPCOrder + subfr_length, subfr_length - psEncC->predictLPCOrder ); + + /* Add subframe energies from first half frame */ + shift = rshift0 - rshift1; + if( shift >= 0 ) { + res_nrg1 = silk_RSHIFT( res_nrg1, shift ); + res_nrg_interp_Q = -rshift0; + } else { + res_nrg0 = silk_RSHIFT( res_nrg0, -shift ); + res_nrg_interp_Q = -rshift1; + } + res_nrg_interp = silk_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( silk_RSHIFT( res_nrg_interp, shift ) < res_nrg ) { + isInterpLower = silk_TRUE; + } else { + isInterpLower = silk_FALSE; + } + } else { + if( -shift < 32 ) { + if( res_nrg_interp < silk_RSHIFT( res_nrg, -shift ) ) { + isInterpLower = silk_TRUE; + } else { + isInterpLower = silk_FALSE; + } + } else { + isInterpLower = silk_FALSE; + } + } + + /* Determine whether current interpolated NLSFs are best so far */ + if( isInterpLower == silk_TRUE ) { + /* Interpolation has lower residual energy */ + res_nrg = res_nrg_interp; + res_nrg_Q = res_nrg_interp_Q; + psEncC->indices.NLSFInterpCoef_Q2 = (opus_int8)k; + } + } + } + + if( psEncC->indices.NLSFInterpCoef_Q2 == 4 ) { + /* NLSF interpolation is currently inactive, calculate NLSFs from full frame AR coefficients */ + silk_A2NLSF( NLSF_Q15, a_Q16, psEncC->predictLPCOrder ); + } + + silk_assert( psEncC->indices.NLSFInterpCoef_Q2 == 4 || ( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) ); +} diff --git a/code/opus-1.0.2/silk/fixed/find_LTP_FIX.c b/code/opus-1.0.2/silk/fixed/find_LTP_FIX.c new file mode 100644 index 00000000..bd210874 --- /dev/null +++ b/code/opus-1.0.2/silk/fixed/find_LTP_FIX.c @@ -0,0 +1,244 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" +#include "tuning_parameters.h" + +/* Head room for correlations */ +#define LTP_CORRS_HEAD_ROOM 2 + +void silk_fit_LTP( + opus_int32 LTP_coefs_Q16[ LTP_ORDER ], + opus_int16 LTP_coefs_Q14[ LTP_ORDER ] +); + +void silk_find_LTP_FIX( + opus_int16 b_Q14[ MAX_NB_SUBFR * LTP_ORDER ], /* O LTP coefs */ + opus_int32 WLTP[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Weight for LTP quantization */ + opus_int *LTPredCodGain_Q7, /* O LTP coding gain */ + const opus_int16 r_lpc[], /* I residual signal after LPC signal + state for first 10 ms */ + const opus_int lag[ MAX_NB_SUBFR ], /* I LTP lags */ + const opus_int32 Wght_Q15[ MAX_NB_SUBFR ], /* I weights */ + const opus_int subfr_length, /* I subframe length */ + const opus_int nb_subfr, /* I number of subframes */ + const opus_int mem_offset, /* I number of samples in LTP memory */ + opus_int corr_rshifts[ MAX_NB_SUBFR ] /* O right shifts applied to correlations */ +) +{ + opus_int i, k, lshift; + const opus_int16 *r_ptr, *lag_ptr; + opus_int16 *b_Q14_ptr; + + opus_int32 regu; + opus_int32 *WLTP_ptr; + opus_int32 b_Q16[ LTP_ORDER ], delta_b_Q14[ LTP_ORDER ], d_Q14[ MAX_NB_SUBFR ], nrg[ MAX_NB_SUBFR ], g_Q26; + opus_int32 w[ MAX_NB_SUBFR ], WLTP_max, max_abs_d_Q14, max_w_bits; + + opus_int32 temp32, denom32; + opus_int extra_shifts; + opus_int rr_shifts, maxRshifts, maxRshifts_wxtra, LZs; + opus_int32 LPC_res_nrg, LPC_LTP_res_nrg, div_Q16; + opus_int32 Rr[ LTP_ORDER ], rr[ MAX_NB_SUBFR ]; + opus_int32 wd, m_Q12; + + b_Q14_ptr = b_Q14; + WLTP_ptr = WLTP; + r_ptr = &r_lpc[ mem_offset ]; + for( k = 0; k < nb_subfr; k++ ) { + lag_ptr = r_ptr - ( lag[ k ] + LTP_ORDER / 2 ); + + silk_sum_sqr_shift( &rr[ k ], &rr_shifts, r_ptr, subfr_length ); /* rr[ k ] in Q( -rr_shifts ) */ + + /* Assure headroom */ + LZs = silk_CLZ32( rr[k] ); + if( LZs < LTP_CORRS_HEAD_ROOM ) { + rr[ k ] = silk_RSHIFT_ROUND( rr[ k ], LTP_CORRS_HEAD_ROOM - LZs ); + rr_shifts += ( LTP_CORRS_HEAD_ROOM - LZs ); + } + corr_rshifts[ k ] = rr_shifts; + 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 */ + 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 ] = silk_RSHIFT( rr[ k ], corr_rshifts[ k ] - rr_shifts ); /* rr[ k ] in Q( -corr_rshifts[ k ] ) */ + } + silk_assert( rr[ k ] >= 0 ); + + regu = 1; + regu = silk_SMLAWB( regu, rr[ k ], SILK_FIX_CONST( LTP_DAMPING/3, 16 ) ); + regu = silk_SMLAWB( regu, matrix_ptr( WLTP_ptr, 0, 0, LTP_ORDER ), SILK_FIX_CONST( LTP_DAMPING/3, 16 ) ); + regu = silk_SMLAWB( regu, matrix_ptr( WLTP_ptr, LTP_ORDER-1, LTP_ORDER-1, LTP_ORDER ), SILK_FIX_CONST( LTP_DAMPING/3, 16 ) ); + silk_regularize_correlations_FIX( WLTP_ptr, &rr[k], regu, LTP_ORDER ); + + 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 */ + silk_fit_LTP( b_Q16, b_Q14_ptr ); + + /* Calculate residual energy */ + nrg[ k ] = 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 = silk_min_int( corr_rshifts[ k ], LTP_CORRS_HEAD_ROOM ); + denom32 = silk_LSHIFT_SAT32( silk_SMULWB( nrg[ k ], Wght_Q15[ k ] ), 1 + extra_shifts ) + /* Q( -corr_rshifts[ k ] + extra_shifts ) */ + silk_RSHIFT( silk_SMULWB( (opus_int32)subfr_length, 655 ), corr_rshifts[ k ] - extra_shifts ); /* Q( -corr_rshifts[ k ] + extra_shifts ) */ + denom32 = silk_max( denom32, 1 ); + silk_assert( ((opus_int64)Wght_Q15[ k ] << 16 ) < silk_int32_MAX ); /* Wght always < 0.5 in Q0 */ + temp32 = silk_DIV32( silk_LSHIFT( (opus_int32)Wght_Q15[ k ], 16 ), denom32 ); /* Q( 15 + 16 + corr_rshifts[k] - extra_shifts ) */ + temp32 = silk_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 = silk_max( WLTP_ptr[ i ], WLTP_max ); + } + lshift = silk_CLZ32( WLTP_max ) - 1 - 3; /* keep 3 bits free for vq_nearest_neighbor_fix */ + silk_assert( 26 - 18 + lshift >= 0 ); + if( 26 - 18 + lshift < 31 ) { + temp32 = silk_min_32( temp32, silk_LSHIFT( (opus_int32)1, 26 - 18 + lshift ) ); + } + + 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/2, LTP_ORDER/2, LTP_ORDER ); /* w in Q( 18 - corr_rshifts[ k ] ) */ + silk_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 = silk_max_int( corr_rshifts[ k ], maxRshifts ); + } + + /* Compute LTP coding gain */ + if( LTPredCodGain_Q7 != NULL ) { + LPC_LTP_res_nrg = 0; + LPC_res_nrg = 0; + silk_assert( LTP_CORRS_HEAD_ROOM >= 2 ); /* Check that no overflow will happen when adding */ + for( k = 0; k < nb_subfr; k++ ) { + LPC_res_nrg = silk_ADD32( LPC_res_nrg, silk_RSHIFT( silk_ADD32( silk_SMULWB( rr[ k ], Wght_Q15[ k ] ), 1 ), 1 + ( maxRshifts - corr_rshifts[ k ] ) ) ); /* Q( -maxRshifts ) */ + LPC_LTP_res_nrg = silk_ADD32( LPC_LTP_res_nrg, silk_RSHIFT( silk_ADD32( silk_SMULWB( nrg[ k ], Wght_Q15[ k ] ), 1 ), 1 + ( maxRshifts - corr_rshifts[ k ] ) ) ); /* Q( -maxRshifts ) */ + } + LPC_LTP_res_nrg = silk_max( LPC_LTP_res_nrg, 1 ); /* avoid division by zero */ + + div_Q16 = silk_DIV32_varQ( LPC_res_nrg, LPC_LTP_res_nrg, 16 ); + *LTPredCodGain_Q7 = ( opus_int )silk_SMULBB( 3, silk_lin2log( div_Q16 ) - ( 16 << 7 ) ); + + silk_assert( *LTPredCodGain_Q7 == ( opus_int )silk_SAT16( silk_MUL( 3, 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 = silk_max_32( max_abs_d_Q14, silk_abs( d_Q14[ k ] ) ); + /* w[ k ] is in Q( 18 - corr_rshifts[ k ] ) */ + /* Find bits needed in Q( 18 - maxRshifts ) */ + max_w_bits = silk_max_32( max_w_bits, 32 - silk_CLZ32( w[ k ] ) + corr_rshifts[ k ] - maxRshifts ); + } + + /* max_abs_d_Q14 = (5 << 15); worst case, i.e. LTP_ORDER * -silk_int16_MIN */ + silk_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 - 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 = silk_max_int( extra_shifts, 0 ); + + maxRshifts_wxtra = maxRshifts + extra_shifts; + + temp32 = silk_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 = silk_ADD32( temp32, silk_RSHIFT( w[ k ], maxRshifts_wxtra - corr_rshifts[ k ] ) ); /* Q( 18 - maxRshifts_wxtra ) */ + wd = silk_ADD32( wd, silk_LSHIFT( silk_SMULWW( silk_RSHIFT( w[ k ], maxRshifts_wxtra - corr_rshifts[ k ] ), d_Q14[ k ] ), 2 ) ); /* Q( 18 - maxRshifts_wxtra ) */ + } + m_Q12 = silk_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 = silk_RSHIFT( w[ k ], 2 - corr_rshifts[ k ] ); + } else { + temp32 = silk_LSHIFT_SAT32( w[ k ], corr_rshifts[ k ] - 2 ); + } + + g_Q26 = silk_MUL( + silk_DIV32( + SILK_FIX_CONST( LTP_SMOOTHING, 26 ), + silk_RSHIFT( SILK_FIX_CONST( LTP_SMOOTHING, 26 ), 10 ) + temp32 ), /* Q10 */ + silk_LSHIFT_SAT32( silk_SUB_SAT32( (opus_int32)m_Q12, silk_RSHIFT( d_Q14[ k ], 2 ) ), 4 ) ); /* Q16 */ + + temp32 = 0; + for( i = 0; i < LTP_ORDER; i++ ) { + delta_b_Q14[ i ] = silk_max_16( b_Q14_ptr[ i ], 1638 ); /* 1638_Q14 = 0.1_Q0 */ + temp32 += delta_b_Q14[ i ]; /* Q14 */ + } + temp32 = silk_DIV32( g_Q26, temp32 ); /* Q14 -> Q12 */ + for( i = 0; i < LTP_ORDER; i++ ) { + b_Q14_ptr[ i ] = silk_LIMIT_32( (opus_int32)b_Q14_ptr[ i ] + silk_SMULWB( silk_LSHIFT_SAT32( temp32, 4 ), delta_b_Q14[ i ] ), -16000, 28000 ); + } + b_Q14_ptr += LTP_ORDER; + } +} + +void silk_fit_LTP( + opus_int32 LTP_coefs_Q16[ LTP_ORDER ], + opus_int16 LTP_coefs_Q14[ LTP_ORDER ] +) +{ + opus_int i; + + for( i = 0; i < LTP_ORDER; i++ ) { + LTP_coefs_Q14[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( LTP_coefs_Q16[ i ], 2 ) ); + } +} diff --git a/code/opus-1.0.2/silk/fixed/find_pitch_lags_FIX.c b/code/opus-1.0.2/silk/fixed/find_pitch_lags_FIX.c new file mode 100644 index 00000000..39c30487 --- /dev/null +++ b/code/opus-1.0.2/silk/fixed/find_pitch_lags_FIX.c @@ -0,0 +1,137 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" +#include "tuning_parameters.h" + +/* Find pitch lags */ +void silk_find_pitch_lags_FIX( + silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + opus_int16 res[], /* O residual */ + const opus_int16 x[] /* I Speech signal */ +) +{ + opus_int buf_len, i, scale; + opus_int32 thrhld_Q15, res_nrg; + const opus_int16 *x_buf, *x_buf_ptr; + opus_int16 Wsig[ FIND_PITCH_LPC_WIN_MAX ], *Wsig_ptr; + opus_int32 auto_corr[ MAX_FIND_PITCH_LPC_ORDER + 1 ]; + opus_int16 rc_Q15[ MAX_FIND_PITCH_LPC_ORDER ]; + opus_int32 A_Q24[ MAX_FIND_PITCH_LPC_ORDER ]; + opus_int16 A_Q12[ MAX_FIND_PITCH_LPC_ORDER ]; + + /******************************************/ + /* Set up buffer lengths etc based on Fs */ + /******************************************/ + buf_len = psEnc->sCmn.la_pitch + psEnc->sCmn.frame_length + psEnc->sCmn.ltp_mem_length; + + /* Safety check */ + silk_assert( buf_len >= psEnc->sCmn.pitch_LPC_win_length ); + + x_buf = x - psEnc->sCmn.ltp_mem_length; + + /*************************************/ + /* Estimate LPC AR coefficients */ + /*************************************/ + + /* Calculate windowed signal */ + + /* First LA_LTP samples */ + x_buf_ptr = x_buf + buf_len - psEnc->sCmn.pitch_LPC_win_length; + Wsig_ptr = Wsig; + 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; + silk_memcpy( Wsig_ptr, x_buf_ptr, ( psEnc->sCmn.pitch_LPC_win_length - silk_LSHIFT( psEnc->sCmn.la_pitch, 1 ) ) * sizeof( opus_int16 ) ); + + /* Last LA_LTP samples */ + Wsig_ptr += psEnc->sCmn.pitch_LPC_win_length - silk_LSHIFT( psEnc->sCmn.la_pitch, 1 ); + x_buf_ptr += psEnc->sCmn.pitch_LPC_win_length - silk_LSHIFT( psEnc->sCmn.la_pitch, 1 ); + silk_apply_sine_window( Wsig_ptr, x_buf_ptr, 2, psEnc->sCmn.la_pitch ); + + /* Calculate autocorrelation sequence */ + silk_autocorr( auto_corr, &scale, Wsig, psEnc->sCmn.pitch_LPC_win_length, psEnc->sCmn.pitchEstimationLPCOrder + 1 ); + + /* Add white noise, as fraction of energy */ + auto_corr[ 0 ] = silk_SMLAWB( auto_corr[ 0 ], auto_corr[ 0 ], SILK_FIX_CONST( FIND_PITCH_WHITE_NOISE_FRACTION, 16 ) ) + 1; + + /* Calculate the reflection coefficients using schur */ + res_nrg = silk_schur( rc_Q15, auto_corr, psEnc->sCmn.pitchEstimationLPCOrder ); + + /* Prediction gain */ + psEncCtrl->predGain_Q16 = silk_DIV32_varQ( auto_corr[ 0 ], silk_max_int( res_nrg, 1 ), 16 ); + + /* Convert reflection coefficients to prediction coefficients */ + 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 ] = (opus_int16)silk_SAT16( silk_RSHIFT( A_Q24[ i ], 12 ) ); + } + + /* Do BWE */ + silk_bwexpander( A_Q12, psEnc->sCmn.pitchEstimationLPCOrder, SILK_FIX_CONST( FIND_PITCH_BANDWIDTH_EXPANSION, 16 ) ); + + /*****************************************/ + /* LPC analysis filtering */ + /*****************************************/ + silk_LPC_analysis_filter( res, x_buf, A_Q12, buf_len, psEnc->sCmn.pitchEstimationLPCOrder ); + + if( psEnc->sCmn.indices.signalType != TYPE_NO_VOICE_ACTIVITY && psEnc->sCmn.first_frame_after_reset == 0 ) { + /* Threshold for pitch estimator */ + thrhld_Q15 = SILK_FIX_CONST( 0.6, 15 ); + thrhld_Q15 = silk_SMLABB( thrhld_Q15, SILK_FIX_CONST( -0.004, 15 ), psEnc->sCmn.pitchEstimationLPCOrder ); + thrhld_Q15 = silk_SMLABB( thrhld_Q15, SILK_FIX_CONST( -0.1, 7 ), psEnc->sCmn.speech_activity_Q8 ); + thrhld_Q15 = silk_SMLABB( thrhld_Q15, SILK_FIX_CONST( -0.15, 15 ), silk_RSHIFT( psEnc->sCmn.prevSignalType, 1 ) ); + thrhld_Q15 = silk_SMLAWB( thrhld_Q15, SILK_FIX_CONST( -0.1, 16 ), psEnc->sCmn.input_tilt_Q15 ); + thrhld_Q15 = silk_SAT16( thrhld_Q15 ); + + /*****************************************/ + /* Call pitch estimator */ + /*****************************************/ + if( silk_pitch_analysis_core( res, psEncCtrl->pitchL, &psEnc->sCmn.indices.lagIndex, &psEnc->sCmn.indices.contourIndex, + &psEnc->LTPCorr_Q15, psEnc->sCmn.prevLag, psEnc->sCmn.pitchEstimationThreshold_Q16, + (opus_int16)thrhld_Q15, psEnc->sCmn.fs_kHz, psEnc->sCmn.pitchEstimationComplexity, psEnc->sCmn.nb_subfr ) == 0 ) + { + psEnc->sCmn.indices.signalType = TYPE_VOICED; + } else { + psEnc->sCmn.indices.signalType = TYPE_UNVOICED; + } + } else { + silk_memset( psEncCtrl->pitchL, 0, sizeof( psEncCtrl->pitchL ) ); + psEnc->sCmn.indices.lagIndex = 0; + psEnc->sCmn.indices.contourIndex = 0; + psEnc->LTPCorr_Q15 = 0; + } +} diff --git a/code/opus-1.0.2/silk/fixed/find_pred_coefs_FIX.c b/code/opus-1.0.2/silk/fixed/find_pred_coefs_FIX.c new file mode 100644 index 00000000..997989b5 --- /dev/null +++ b/code/opus-1.0.2/silk/fixed/find_pred_coefs_FIX.c @@ -0,0 +1,136 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" + +void silk_find_pred_coefs_FIX( + silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + const opus_int16 res_pitch[], /* I Residual from pitch analysis */ + const opus_int16 x[], /* I Speech signal */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + opus_int i; + opus_int32 WLTP[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ]; + opus_int32 invGains_Q16[ MAX_NB_SUBFR ], local_gains[ MAX_NB_SUBFR ], Wght_Q15[ MAX_NB_SUBFR ]; + opus_int16 NLSF_Q15[ MAX_LPC_ORDER ]; + const opus_int16 *x_ptr; + opus_int16 *x_pre_ptr, LPC_in_pre[ MAX_NB_SUBFR * MAX_LPC_ORDER + MAX_FRAME_LENGTH ]; + opus_int32 tmp, min_gain_Q16, minInvGain_Q30; + opus_int LTP_corrs_rshift[ MAX_NB_SUBFR ]; + + /* weighting for weighted least squares */ + min_gain_Q16 = silk_int32_MAX >> 6; + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + min_gain_Q16 = silk_min( min_gain_Q16, psEncCtrl->Gains_Q16[ i ] ); + } + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + /* Divide to Q16 */ + silk_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 ] = silk_DIV32_varQ( min_gain_Q16, psEncCtrl->Gains_Q16[ i ], 16 - 2 ); + + /* Ensure Wght_Q15 a minimum value 1 */ + invGains_Q16[ i ] = silk_max( invGains_Q16[ i ], 363 ); + + /* Square the inverted gains */ + silk_assert( invGains_Q16[ i ] == silk_SAT16( invGains_Q16[ i ] ) ); + tmp = silk_SMULWB( invGains_Q16[ i ], invGains_Q16[ i ] ); + Wght_Q15[ i ] = silk_RSHIFT( tmp, 1 ); + + /* Invert the inverted and normalized gains */ + local_gains[ i ] = silk_DIV32( ( (opus_int32)1 << 16 ), invGains_Q16[ i ] ); + } + + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /**********/ + /* VOICED */ + /**********/ + silk_assert( psEnc->sCmn.ltp_mem_length - psEnc->sCmn.predictLPCOrder >= psEncCtrl->pitchL[ 0 ] + LTP_ORDER / 2 ); + + /* LTP analysis */ + silk_find_LTP_FIX( psEncCtrl->LTPCoef_Q14, WLTP, &psEncCtrl->LTPredCodGain_Q7, + res_pitch, psEncCtrl->pitchL, Wght_Q15, psEnc->sCmn.subfr_length, + psEnc->sCmn.nb_subfr, psEnc->sCmn.ltp_mem_length, LTP_corrs_rshift ); + + /* Quantize LTP gain parameters */ + silk_quant_LTP_gains( psEncCtrl->LTPCoef_Q14, psEnc->sCmn.indices.LTPIndex, &psEnc->sCmn.indices.PERIndex, + WLTP, psEnc->sCmn.mu_LTP_Q9, psEnc->sCmn.LTPQuantLowComplexity, psEnc->sCmn.nb_subfr); + + /* Control LTP scaling */ + silk_LTP_scale_ctrl_FIX( psEnc, psEncCtrl, condCoding ); + + /* Create LTP residual */ + silk_LTP_analysis_filter_FIX( LPC_in_pre, x - psEnc->sCmn.predictLPCOrder, psEncCtrl->LTPCoef_Q14, + psEncCtrl->pitchL, invGains_Q16, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.predictLPCOrder ); + + } else { + /************/ + /* UNVOICED */ + /************/ + /* Create signal with prepended subframes, scaled by inverse gains */ + x_ptr = x - psEnc->sCmn.predictLPCOrder; + x_pre_ptr = LPC_in_pre; + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + 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; + } + + silk_memset( psEncCtrl->LTPCoef_Q14, 0, psEnc->sCmn.nb_subfr * LTP_ORDER * sizeof( opus_int16 ) ); + psEncCtrl->LTPredCodGain_Q7 = 0; + } + + /* Limit on total predictive coding gain */ + if( psEnc->sCmn.first_frame_after_reset ) { + minInvGain_Q30 = SILK_FIX_CONST( 1.0f / MAX_PREDICTION_POWER_GAIN_AFTER_RESET, 30 ); + } else { + minInvGain_Q30 = silk_log2lin( silk_SMLAWB( 16 << 7, (opus_int32)psEncCtrl->LTPredCodGain_Q7, SILK_FIX_CONST( 1.0 / 3, 16 ) ) ); /* Q16 */ + minInvGain_Q30 = silk_DIV32_varQ( minInvGain_Q30, + silk_SMULWW( SILK_FIX_CONST( MAX_PREDICTION_POWER_GAIN, 0 ), + silk_SMLAWB( SILK_FIX_CONST( 0.25, 18 ), SILK_FIX_CONST( 0.75, 18 ), psEncCtrl->coding_quality_Q14 ) ), 14 ); + } + + /* LPC_in_pre contains the LTP-filtered input for voiced, and the unfiltered input for unvoiced */ + silk_find_LPC_FIX( &psEnc->sCmn, NLSF_Q15, LPC_in_pre, minInvGain_Q30 ); + + /* Quantize LSFs */ + silk_process_NLSFs( &psEnc->sCmn, psEncCtrl->PredCoef_Q12, NLSF_Q15, psEnc->sCmn.prev_NLSFq_Q15 ); + + /* Calculate residual energy using quantized LPC coefficients */ + silk_residual_energy_FIX( psEncCtrl->ResNrg, psEncCtrl->ResNrgQ, LPC_in_pre, psEncCtrl->PredCoef_Q12, local_gains, + psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.predictLPCOrder ); + + /* Copy to prediction struct for use in next frame for interpolation */ + silk_memcpy( psEnc->sCmn.prev_NLSFq_Q15, NLSF_Q15, sizeof( psEnc->sCmn.prev_NLSFq_Q15 ) ); +} diff --git a/code/opus-1.0.2/silk/fixed/k2a_FIX.c b/code/opus-1.0.2/silk/fixed/k2a_FIX.c new file mode 100644 index 00000000..cadc9274 --- /dev/null +++ b/code/opus-1.0.2/silk/fixed/k2a_FIX.c @@ -0,0 +1,53 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Step up function, converts reflection coefficients to prediction coefficients */ +void silk_k2a( + opus_int32 *A_Q24, /* O Prediction coefficients [order] Q24 */ + const opus_int16 *rc_Q15, /* I Reflection coefficients [order] Q15 */ + const opus_int32 order /* I Prediction order */ +) +{ + opus_int k, n; + opus_int32 Atmp[ 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 ] = silk_SMLAWB( A_Q24[ n ], silk_LSHIFT( Atmp[ k - n - 1 ], 1 ), rc_Q15[ k ] ); + } + A_Q24[ k ] = -silk_LSHIFT( (opus_int32)rc_Q15[ k ], 9 ); + } +} diff --git a/code/opus-1.0.2/silk/fixed/k2a_Q16_FIX.c b/code/opus-1.0.2/silk/fixed/k2a_Q16_FIX.c new file mode 100644 index 00000000..f96f3064 --- /dev/null +++ b/code/opus-1.0.2/silk/fixed/k2a_Q16_FIX.c @@ -0,0 +1,53 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Step up function, converts reflection coefficients to prediction coefficients */ +void silk_k2a_Q16( + opus_int32 *A_Q24, /* O Prediction coefficients [order] Q24 */ + const opus_int32 *rc_Q16, /* I Reflection coefficients [order] Q16 */ + const opus_int32 order /* I Prediction order */ +) +{ + opus_int k, n; + opus_int32 Atmp[ 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 ] = silk_SMLAWW( A_Q24[ n ], Atmp[ k - n - 1 ], rc_Q16[ k ] ); + } + A_Q24[ k ] = -silk_LSHIFT( rc_Q16[ k ], 8 ); + } +} diff --git a/code/opus-1.0.2/silk/fixed/main_FIX.h b/code/opus-1.0.2/silk/fixed/main_FIX.h new file mode 100644 index 00000000..369b31ee --- /dev/null +++ b/code/opus-1.0.2/silk/fixed/main_FIX.h @@ -0,0 +1,254 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (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 SILK_MAIN_FIX_H +#define SILK_MAIN_FIX_H + +#include "SigProc_FIX.h" +#include "structs_FIX.h" +#include "control.h" +#include "main.h" +#include "PLC.h" +#include "debug.h" +#include "entenc.h" + +#ifndef FORCE_CPP_BUILD +#ifdef __cplusplus +extern "C" +{ +#endif +#endif + +#define silk_encoder_state_Fxx silk_encoder_state_FIX +#define silk_encode_do_VAD_Fxx silk_encode_do_VAD_FIX +#define silk_encode_frame_Fxx silk_encode_frame_FIX + +/*********************/ +/* Encoder Functions */ +/*********************/ + +/* High-pass filter with cutoff frequency adaptation based on pitch lag statistics */ +void silk_HP_variable_cutoff( + silk_encoder_state_Fxx state_Fxx[] /* I/O Encoder states */ +); + +/* Encoder main function */ +void silk_encode_do_VAD_FIX( + silk_encoder_state_FIX *psEnc /* I/O Pointer to Silk FIX encoder state */ +); + +/* Encoder main function */ +opus_int silk_encode_frame_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */ + opus_int32 *pnBytesOut, /* O Pointer to number of payload bytes; */ + ec_enc *psRangeEnc, /* I/O compressor data structure */ + opus_int condCoding, /* I The type of conditional coding to use */ + opus_int maxBits, /* I If > 0: maximum number of output bits */ + opus_int useCBR /* I Flag to force constant-bitrate operation */ +); + +/* Initializes the Silk encoder state */ +opus_int silk_init_encoder( + silk_encoder_state_Fxx *psEnc /* I/O Pointer to Silk FIX encoder state */ +); + +/* Control the Silk encoder */ +opus_int silk_control_encoder( + silk_encoder_state_Fxx *psEnc, /* I/O Pointer to Silk encoder state */ + silk_EncControlStruct *encControl, /* I Control structure */ + const opus_int32 TargetRate_bps, /* I Target max bitrate (bps) */ + const opus_int allow_bw_switch, /* I Flag to allow switching audio bandwidth */ + const opus_int channelNb, /* I Channel number */ + const opus_int force_fs_kHz +); + +/****************/ +/* Prefiltering */ +/****************/ +void silk_prefilter_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Encoder state */ + const silk_encoder_control_FIX *psEncCtrl, /* I Encoder control */ + opus_int32 xw_Q10[], /* O Weighted signal */ + const opus_int16 x[] /* I Speech signal */ +); + +/**************************/ +/* Noise shaping analysis */ +/**************************/ +/* Compute noise shaping coefficients and initial gain values */ +void silk_noise_shape_analysis_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Encoder state FIX */ + silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control FIX */ + const opus_int16 *pitch_res, /* I LPC residual from pitch analysis */ + const opus_int16 *x /* I Input signal [ frame_length + la_shape ] */ +); + +/* Autocorrelations for a warped frequency axis */ +void silk_warped_autocorrelation_FIX( + opus_int32 *corr, /* O Result [order + 1] */ + opus_int *scale, /* O Scaling of the correlation vector */ + const opus_int16 *input, /* I Input data to correlate */ + const opus_int warping_Q16, /* I Warping coefficient */ + const opus_int length, /* I Length of input */ + const opus_int order /* I Correlation order (even) */ +); + +/* Calculation of LTP state scaling */ +void silk_LTP_scale_ctrl_FIX( + silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/**********************************************/ +/* Prediction Analysis */ +/**********************************************/ +/* Find pitch lags */ +void silk_find_pitch_lags_FIX( + silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + opus_int16 res[], /* O residual */ + const opus_int16 x[] /* I Speech signal */ +); + +/* Find LPC and LTP coefficients */ +void silk_find_pred_coefs_FIX( + silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + const opus_int16 res_pitch[], /* I Residual from pitch analysis */ + const opus_int16 x[], /* I Speech signal */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/* LPC analysis */ +void silk_find_LPC_FIX( + silk_encoder_state *psEncC, /* I/O Encoder state */ + opus_int16 NLSF_Q15[], /* O NLSFs */ + const opus_int16 x[], /* I Input signal */ + const opus_int32 minInvGain_Q30 /* I Inverse of max prediction gain */ +); + +/* LTP analysis */ +void silk_find_LTP_FIX( + opus_int16 b_Q14[ MAX_NB_SUBFR * LTP_ORDER ], /* O LTP coefs */ + opus_int32 WLTP[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Weight for LTP quantization */ + opus_int *LTPredCodGain_Q7, /* O LTP coding gain */ + const opus_int16 r_lpc[], /* I residual signal after LPC signal + state for first 10 ms */ + const opus_int lag[ MAX_NB_SUBFR ], /* I LTP lags */ + const opus_int32 Wght_Q15[ MAX_NB_SUBFR ], /* I weights */ + const opus_int subfr_length, /* I subframe length */ + const opus_int nb_subfr, /* I number of subframes */ + const opus_int mem_offset, /* I number of samples in LTP memory */ + opus_int corr_rshifts[ MAX_NB_SUBFR ] /* O right shifts applied to correlations */ +); + +void silk_LTP_analysis_filter_FIX( + opus_int16 *LTP_res, /* O LTP residual signal of length MAX_NB_SUBFR * ( pre_length + subfr_length ) */ + const opus_int16 *x, /* I Pointer to input signal with at least max( pitchL ) preceding samples */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ],/* I LTP_ORDER LTP coefficients for each MAX_NB_SUBFR subframe */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag, one for each subframe */ + const opus_int32 invGains_Q16[ MAX_NB_SUBFR ], /* I Inverse quantization gains, one for each subframe */ + const opus_int subfr_length, /* I Length of each subframe */ + const opus_int nb_subfr, /* I Number of subframes */ + const opus_int pre_length /* I Length of the preceding samples starting at &x[0] for each subframe */ +); + +/* Calculates residual energies of input subframes where all subframes have LPC_order */ +/* of preceding samples */ +void silk_residual_energy_FIX( + opus_int32 nrgs[ MAX_NB_SUBFR ], /* O Residual energy per subframe */ + opus_int nrgsQ[ MAX_NB_SUBFR ], /* O Q value per subframe */ + const opus_int16 x[], /* I Input signal */ + opus_int16 a_Q12[ 2 ][ MAX_LPC_ORDER ], /* I AR coefs for each frame half */ + const opus_int32 gains[ MAX_NB_SUBFR ], /* I Quantization gains */ + const opus_int subfr_length, /* I Subframe length */ + const opus_int nb_subfr, /* I Number of subframes */ + const opus_int LPC_order /* I LPC order */ +); + +/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */ +opus_int32 silk_residual_energy16_covar_FIX( + const opus_int16 *c, /* I Prediction vector */ + const opus_int32 *wXX, /* I Correlation matrix */ + const opus_int32 *wXx, /* I Correlation vector */ + opus_int32 wxx, /* I Signal energy */ + opus_int D, /* I Dimension */ + opus_int cQ /* I Q value for c vector 0 - 15 */ +); + +/* Processing of gains */ +void silk_process_gains_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/******************/ +/* Linear Algebra */ +/******************/ +/* Calculates correlation matrix X'*X */ +void silk_corrMatrix_FIX( + const opus_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */ + const opus_int L, /* I Length of vectors */ + const opus_int order, /* I Max lag for correlation */ + const opus_int head_room, /* I Desired headroom */ + opus_int32 *XX, /* O Pointer to X'*X correlation matrix [ order x order ] */ + opus_int *rshifts /* I/O Right shifts of correlations */ +); + +/* Calculates correlation vector X'*t */ +void silk_corrVector_FIX( + const opus_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */ + const opus_int16 *t, /* I Target vector [L] */ + const opus_int L, /* I Length of vectors */ + const opus_int order, /* I Max lag for correlation */ + opus_int32 *Xt, /* O Pointer to X'*t correlation vector [order] */ + const opus_int rshifts /* I Right shifts of correlations */ +); + +/* Add noise to matrix diagonal */ +void silk_regularize_correlations_FIX( + opus_int32 *XX, /* I/O Correlation matrices */ + opus_int32 *xx, /* I/O Correlation values */ + opus_int32 noise, /* I Noise to add */ + opus_int D /* I Dimension of XX */ +); + +/* Solves Ax = b, assuming A is symmetric */ +void silk_solve_LDL_FIX( + opus_int32 *A, /* I Pointer to symetric square matrix A */ + opus_int M, /* I Size of matrix */ + const opus_int32 *b, /* I Pointer to b vector */ + opus_int32 *x_Q16 /* O Pointer to x solution vector */ +); + +#ifndef FORCE_CPP_BUILD +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* FORCE_CPP_BUILD */ +#endif /* SILK_MAIN_FIX_H */ diff --git a/code/opus-1.0.2/silk/fixed/noise_shape_analysis_FIX.c b/code/opus-1.0.2/silk/fixed/noise_shape_analysis_FIX.c new file mode 100644 index 00000000..d230e48d --- /dev/null +++ b/code/opus-1.0.2/silk/fixed/noise_shape_analysis_FIX.c @@ -0,0 +1,440 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" +#include "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.) */ +/* Note: A monic filter is one with the first coefficient equal to 1.0. In Silk we omit the first */ +/* coefficient in an array of coefficients, for monic filters. */ +static inline opus_int32 warped_gain( /* gain in Q16*/ + const opus_int32 *coefs_Q24, + opus_int lambda_Q16, + opus_int order +) { + opus_int i; + opus_int32 gain_Q24; + + lambda_Q16 = -lambda_Q16; + gain_Q24 = coefs_Q24[ order - 1 ]; + for( i = order - 2; i >= 0; i-- ) { + gain_Q24 = silk_SMLAWB( coefs_Q24[ i ], gain_Q24, lambda_Q16 ); + } + gain_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), gain_Q24, -lambda_Q16 ); + return silk_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 */ +static inline void limit_warped_coefs( + opus_int32 *coefs_syn_Q24, + opus_int32 *coefs_ana_Q24, + opus_int lambda_Q16, + opus_int32 limit_Q24, + opus_int order +) { + opus_int i, iter, ind = 0; + opus_int32 tmp, maxabs_Q24, chirp_Q16, gain_syn_Q16, gain_ana_Q16; + opus_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 ] = silk_SMLAWB( coefs_syn_Q24[ i - 1 ], coefs_syn_Q24[ i ], lambda_Q16 ); + coefs_ana_Q24[ i - 1 ] = silk_SMLAWB( coefs_ana_Q24[ i - 1 ], coefs_ana_Q24[ i ], lambda_Q16 ); + } + lambda_Q16 = -lambda_Q16; + nom_Q16 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 16 ), -(opus_int32)lambda_Q16, lambda_Q16 ); + den_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), coefs_syn_Q24[ 0 ], lambda_Q16 ); + gain_syn_Q16 = silk_DIV32_varQ( nom_Q16, den_Q24, 24 ); + den_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), coefs_ana_Q24[ 0 ], lambda_Q16 ); + gain_ana_Q16 = silk_DIV32_varQ( nom_Q16, den_Q24, 24 ); + for( i = 0; i < order; i++ ) { + coefs_syn_Q24[ i ] = silk_SMULWW( gain_syn_Q16, coefs_syn_Q24[ i ] ); + coefs_ana_Q24[ i ] = silk_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 = silk_max( silk_abs_int32( coefs_syn_Q24[ i ] ), silk_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 ] = silk_SMLAWB( coefs_syn_Q24[ i - 1 ], coefs_syn_Q24[ i ], lambda_Q16 ); + coefs_ana_Q24[ i - 1 ] = silk_SMLAWB( coefs_ana_Q24[ i - 1 ], coefs_ana_Q24[ i ], lambda_Q16 ); + } + gain_syn_Q16 = silk_INVERSE32_varQ( gain_syn_Q16, 32 ); + gain_ana_Q16 = silk_INVERSE32_varQ( gain_ana_Q16, 32 ); + for( i = 0; i < order; i++ ) { + coefs_syn_Q24[ i ] = silk_SMULWW( gain_syn_Q16, coefs_syn_Q24[ i ] ); + coefs_ana_Q24[ i ] = silk_SMULWW( gain_ana_Q16, coefs_ana_Q24[ i ] ); + } + + /* Apply bandwidth expansion */ + chirp_Q16 = SILK_FIX_CONST( 0.99, 16 ) - silk_DIV32_varQ( + silk_SMULWB( maxabs_Q24 - limit_Q24, silk_SMLABB( SILK_FIX_CONST( 0.8, 10 ), SILK_FIX_CONST( 0.1, 10 ), iter ) ), + silk_MUL( maxabs_Q24, ind + 1 ), 22 ); + silk_bwexpander_32( coefs_syn_Q24, order, chirp_Q16 ); + 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 ] = silk_SMLAWB( coefs_syn_Q24[ i - 1 ], coefs_syn_Q24[ i ], lambda_Q16 ); + coefs_ana_Q24[ i - 1 ] = silk_SMLAWB( coefs_ana_Q24[ i - 1 ], coefs_ana_Q24[ i ], lambda_Q16 ); + } + lambda_Q16 = -lambda_Q16; + nom_Q16 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 16 ), -(opus_int32)lambda_Q16, lambda_Q16 ); + den_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), coefs_syn_Q24[ 0 ], lambda_Q16 ); + gain_syn_Q16 = silk_DIV32_varQ( nom_Q16, den_Q24, 24 ); + den_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), coefs_ana_Q24[ 0 ], lambda_Q16 ); + gain_ana_Q16 = silk_DIV32_varQ( nom_Q16, den_Q24, 24 ); + for( i = 0; i < order; i++ ) { + coefs_syn_Q24[ i ] = silk_SMULWW( gain_syn_Q16, coefs_syn_Q24[ i ] ); + coefs_ana_Q24[ i ] = silk_SMULWW( gain_ana_Q16, coefs_ana_Q24[ i ] ); + } + } + silk_assert( 0 ); +} + +/**************************************************************/ +/* Compute noise shaping coefficients and initial gain values */ +/**************************************************************/ +void silk_noise_shape_analysis_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Encoder state FIX */ + silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control FIX */ + const opus_int16 *pitch_res, /* I LPC residual from pitch analysis */ + const opus_int16 *x /* I Input signal [ frame_length + la_shape ] */ +) +{ + silk_shape_state_FIX *psShapeSt = &psEnc->sShape; + opus_int k, i, nSamples, Qnrg, b_Q14, warping_Q16, scale = 0; + opus_int32 SNR_adj_dB_Q7, HarmBoost_Q16, HarmShapeGain_Q16, Tilt_Q16, tmp32; + opus_int32 nrg, pre_nrg_Q30, log_energy_Q7, log_energy_prev_Q7, energy_variation_Q7; + opus_int32 delta_Q16, BWExp1_Q16, BWExp2_Q16, gain_mult_Q16, gain_add_Q16, strength_Q16, b_Q8; + opus_int32 auto_corr[ MAX_SHAPE_LPC_ORDER + 1 ]; + opus_int32 refl_coef_Q16[ MAX_SHAPE_LPC_ORDER ]; + opus_int32 AR1_Q24[ MAX_SHAPE_LPC_ORDER ]; + opus_int32 AR2_Q24[ MAX_SHAPE_LPC_ORDER ]; + opus_int16 x_windowed[ SHAPE_LPC_WIN_MAX ]; + const opus_int16 *x_ptr, *pitch_res_ptr; + + /* Point to start of first LPC analysis block */ + x_ptr = x - psEnc->sCmn.la_shape; + + /****************/ + /* GAIN CONTROL */ + /****************/ + SNR_adj_dB_Q7 = psEnc->sCmn.SNR_dB_Q7; + + /* Input quality is the average of the quality in the lowest two VAD bands */ + psEncCtrl->input_quality_Q14 = ( opus_int )silk_RSHIFT( (opus_int32)psEnc->sCmn.input_quality_bands_Q15[ 0 ] + + psEnc->sCmn.input_quality_bands_Q15[ 1 ], 2 ); + + /* Coding quality level, between 0.0_Q0 and 1.0_Q0, but in Q14 */ + psEncCtrl->coding_quality_Q14 = silk_RSHIFT( silk_sigm_Q15( silk_RSHIFT_ROUND( SNR_adj_dB_Q7 - + SILK_FIX_CONST( 20.0, 7 ), 4 ) ), 1 ); + + /* Reduce coding SNR during low speech activity */ + if( psEnc->sCmn.useCBR == 0 ) { + b_Q8 = SILK_FIX_CONST( 1.0, 8 ) - psEnc->sCmn.speech_activity_Q8; + b_Q8 = silk_SMULWB( silk_LSHIFT( b_Q8, 8 ), b_Q8 ); + SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, + silk_SMULBB( SILK_FIX_CONST( -BG_SNR_DECR_dB, 7 ) >> ( 4 + 1 ), b_Q8 ), /* Q11*/ + silk_SMULWB( SILK_FIX_CONST( 1.0, 14 ) + psEncCtrl->input_quality_Q14, psEncCtrl->coding_quality_Q14 ) ); /* Q12*/ + } + + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Reduce gains for periodic signals */ + SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, SILK_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 = silk_SMLAWB( SNR_adj_dB_Q7, + silk_SMLAWB( SILK_FIX_CONST( 6.0, 9 ), -SILK_FIX_CONST( 0.4, 18 ), psEnc->sCmn.SNR_dB_Q7 ), + SILK_FIX_CONST( 1.0, 14 ) - psEncCtrl->input_quality_Q14 ); + } + + /*************************/ + /* SPARSENESS PROCESSING */ + /*************************/ + /* Set quantizer offset */ + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Initially set to 0; may be overruled in process_gains(..) */ + psEnc->sCmn.indices.quantOffsetType = 0; + psEncCtrl->sparseness_Q8 = 0; + } else { + /* Sparseness measure, based on relative fluctuations of energy per 2 milliseconds */ + nSamples = silk_LSHIFT( psEnc->sCmn.fs_kHz, 1 ); + energy_variation_Q7 = 0; + log_energy_prev_Q7 = 0; + pitch_res_ptr = pitch_res; + for( k = 0; k < silk_SMULBB( SUB_FRAME_LENGTH_MS, psEnc->sCmn.nb_subfr ) / 2; k++ ) { + silk_sum_sqr_shift( &nrg, &scale, pitch_res_ptr, nSamples ); + nrg += silk_RSHIFT( nSamples, scale ); /* Q(-scale)*/ + + log_energy_Q7 = silk_lin2log( nrg ); + if( k > 0 ) { + energy_variation_Q7 += silk_abs( log_energy_Q7 - log_energy_prev_Q7 ); + } + log_energy_prev_Q7 = log_energy_Q7; + pitch_res_ptr += nSamples; + } + + psEncCtrl->sparseness_Q8 = silk_RSHIFT( silk_sigm_Q15( silk_SMULWB( energy_variation_Q7 - + SILK_FIX_CONST( 5.0, 7 ), SILK_FIX_CONST( 0.1, 16 ) ) ), 7 ); + + /* Set quantization offset depending on sparseness measure */ + if( psEncCtrl->sparseness_Q8 > SILK_FIX_CONST( SPARSENESS_THRESHOLD_QNT_OFFSET, 8 ) ) { + psEnc->sCmn.indices.quantOffsetType = 0; + } else { + psEnc->sCmn.indices.quantOffsetType = 1; + } + + /* Increase coding SNR for sparse signals */ + SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, SILK_FIX_CONST( SPARSE_SNR_INCR_dB, 15 ), psEncCtrl->sparseness_Q8 - SILK_FIX_CONST( 0.5, 8 ) ); + } + + /*******************************/ + /* Control bandwidth expansion */ + /*******************************/ + /* More BWE for signals with high prediction gain */ + strength_Q16 = silk_SMULWB( psEncCtrl->predGain_Q16, SILK_FIX_CONST( FIND_PITCH_WHITE_NOISE_FRACTION, 16 ) ); + BWExp1_Q16 = BWExp2_Q16 = silk_DIV32_varQ( SILK_FIX_CONST( BANDWIDTH_EXPANSION, 16 ), + silk_SMLAWW( SILK_FIX_CONST( 1.0, 16 ), strength_Q16, strength_Q16 ), 16 ); + delta_Q16 = silk_SMULWB( SILK_FIX_CONST( 1.0, 16 ) - silk_SMULBB( 3, psEncCtrl->coding_quality_Q14 ), + SILK_FIX_CONST( LOW_RATE_BANDWIDTH_EXPANSION_DELTA, 16 ) ); + BWExp1_Q16 = silk_SUB32( BWExp1_Q16, delta_Q16 ); + BWExp2_Q16 = silk_ADD32( BWExp2_Q16, delta_Q16 ); + /* BWExp1 will be applied after BWExp2, so make it relative */ + BWExp1_Q16 = silk_DIV32_16( silk_LSHIFT( BWExp1_Q16, 14 ), silk_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 = silk_SMLAWB( psEnc->sCmn.warping_Q16, (opus_int32)psEncCtrl->coding_quality_Q14, SILK_FIX_CONST( 0.01, 18 ) ); + } else { + warping_Q16 = 0; + } + + /********************************************/ + /* Compute noise shaping AR coefs and gains */ + /********************************************/ + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + /* Apply window: sine slope followed by flat part followed by cosine slope */ + opus_int shift, slope_part, flat_part; + flat_part = psEnc->sCmn.fs_kHz * 3; + slope_part = silk_RSHIFT( psEnc->sCmn.shapeWinLength - flat_part, 1 ); + + silk_apply_sine_window( x_windowed, x_ptr, 1, slope_part ); + shift = slope_part; + silk_memcpy( x_windowed + shift, x_ptr + shift, flat_part * sizeof(opus_int16) ); + shift += flat_part; + 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 */ + silk_warped_autocorrelation_FIX( auto_corr, &scale, x_windowed, warping_Q16, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder ); + } else { + /* Calculate regular auto correlation */ + 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] = silk_ADD32( auto_corr[0], silk_max_32( silk_SMULWB( silk_RSHIFT( auto_corr[ 0 ], 4 ), + SILK_FIX_CONST( SHAPE_WHITE_NOISE_FRACTION, 20 ) ), 1 ) ); + + /* Calculate the reflection coefficients using schur */ + nrg = silk_schur64( refl_coef_Q16, auto_corr, psEnc->sCmn.shapingLPCOrder ); + silk_assert( nrg >= 0 ); + + /* Convert reflection coefficients to prediction coefficients */ + silk_k2a_Q16( AR2_Q24, refl_coef_Q16, psEnc->sCmn.shapingLPCOrder ); + + Qnrg = -scale; /* range: -12...30*/ + silk_assert( Qnrg >= -12 ); + silk_assert( Qnrg <= 30 ); + + /* Make sure that Qnrg is an even number */ + if( Qnrg & 1 ) { + Qnrg -= 1; + nrg >>= 1; + } + + tmp32 = silk_SQRT_APPROX( nrg ); + Qnrg >>= 1; /* range: -6...15*/ + + psEncCtrl->Gains_Q16[ k ] = silk_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 ); + silk_assert( psEncCtrl->Gains_Q16[ k ] >= 0 ); + if ( silk_SMULWW( silk_RSHIFT_ROUND( psEncCtrl->Gains_Q16[ k ], 1 ), gain_mult_Q16 ) >= ( silk_int32_MAX >> 1 ) ) { + psEncCtrl->Gains_Q16[ k ] = silk_int32_MAX; + } else { + psEncCtrl->Gains_Q16[ k ] = silk_SMULWW( psEncCtrl->Gains_Q16[ k ], gain_mult_Q16 ); + } + } + + /* Bandwidth expansion for synthesis filter shaping */ + silk_bwexpander_32( AR2_Q24, psEnc->sCmn.shapingLPCOrder, BWExp2_Q16 ); + + /* Compute noise shaping filter coefficients */ + silk_memcpy( AR1_Q24, AR2_Q24, psEnc->sCmn.shapingLPCOrder * sizeof( opus_int32 ) ); + + /* Bandwidth expansion for analysis filter shaping */ + silk_assert( BWExp1_Q16 <= SILK_FIX_CONST( 1.0, 16 ) ); + silk_bwexpander_32( AR1_Q24, psEnc->sCmn.shapingLPCOrder, BWExp1_Q16 ); + + /* Ratio of prediction gains, in energy domain */ + pre_nrg_Q30 = silk_LPC_inverse_pred_gain_Q24( AR2_Q24, psEnc->sCmn.shapingLPCOrder ); + nrg = silk_LPC_inverse_pred_gain_Q24( 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 = silk_LSHIFT32( silk_SMULWB( pre_nrg_Q30, SILK_FIX_CONST( 0.7, 15 ) ), 1 ); + psEncCtrl->GainsPre_Q14[ k ] = ( opus_int ) SILK_FIX_CONST( 0.3, 14 ) + silk_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, SILK_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 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( AR1_Q24[ i ], 11 ) ); + psEncCtrl->AR2_Q13[ k * MAX_SHAPE_LPC_ORDER + i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( AR2_Q24[ i ], 11 ) ); + } + } + + /*****************/ + /* Gain tweaking */ + /*****************/ + /* Increase gains during low speech activity and put lower limit on gains */ + gain_mult_Q16 = silk_log2lin( -silk_SMLAWB( -SILK_FIX_CONST( 16.0, 7 ), SNR_adj_dB_Q7, SILK_FIX_CONST( 0.16, 16 ) ) ); + gain_add_Q16 = silk_log2lin( silk_SMLAWB( SILK_FIX_CONST( 16.0, 7 ), SILK_FIX_CONST( MIN_QGAIN_DB, 7 ), SILK_FIX_CONST( 0.16, 16 ) ) ); + silk_assert( gain_mult_Q16 > 0 ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->Gains_Q16[ k ] = silk_SMULWW( psEncCtrl->Gains_Q16[ k ], gain_mult_Q16 ); + silk_assert( psEncCtrl->Gains_Q16[ k ] >= 0 ); + psEncCtrl->Gains_Q16[ k ] = silk_ADD_POS_SAT32( psEncCtrl->Gains_Q16[ k ], gain_add_Q16 ); + } + + gain_mult_Q16 = SILK_FIX_CONST( 1.0, 16 ) + silk_RSHIFT_ROUND( silk_MLA( SILK_FIX_CONST( INPUT_TILT, 26 ), + psEncCtrl->coding_quality_Q14, SILK_FIX_CONST( HIGH_RATE_INPUT_TILT, 12 ) ), 10 ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->GainsPre_Q14[ k ] = silk_SMULWB( gain_mult_Q16, psEncCtrl->GainsPre_Q14[ k ] ); + } + + /************************************************/ + /* Control low-frequency shaping and noise tilt */ + /************************************************/ + /* Less low frequency shaping for noisy inputs */ + strength_Q16 = silk_MUL( SILK_FIX_CONST( LOW_FREQ_SHAPING, 4 ), silk_SMLAWB( SILK_FIX_CONST( 1.0, 12 ), + SILK_FIX_CONST( LOW_QUALITY_LOW_FREQ_SHAPING_DECR, 13 ), psEnc->sCmn.input_quality_bands_Q15[ 0 ] - SILK_FIX_CONST( 1.0, 15 ) ) ); + strength_Q16 = silk_RSHIFT( silk_MUL( strength_Q16, psEnc->sCmn.speech_activity_Q8 ), 8 ); + if( psEnc->sCmn.indices.signalType == 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])*/ + opus_int fs_kHz_inv = silk_DIV32_16( SILK_FIX_CONST( 0.2, 14 ), psEnc->sCmn.fs_kHz ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + b_Q14 = fs_kHz_inv + silk_DIV32_16( SILK_FIX_CONST( 3.0, 14 ), psEncCtrl->pitchL[ k ] ); + /* Pack two coefficients in one int32 */ + psEncCtrl->LF_shp_Q14[ k ] = silk_LSHIFT( SILK_FIX_CONST( 1.0, 14 ) - b_Q14 - silk_SMULWB( strength_Q16, b_Q14 ), 16 ); + psEncCtrl->LF_shp_Q14[ k ] |= (opus_uint16)( b_Q14 - SILK_FIX_CONST( 1.0, 14 ) ); + } + silk_assert( SILK_FIX_CONST( HARM_HP_NOISE_COEF, 24 ) < SILK_FIX_CONST( 0.5, 24 ) ); /* Guarantees that second argument to SMULWB() is within range of an opus_int16*/ + Tilt_Q16 = - SILK_FIX_CONST( HP_NOISE_COEF, 16 ) - + silk_SMULWB( SILK_FIX_CONST( 1.0, 16 ) - SILK_FIX_CONST( HP_NOISE_COEF, 16 ), + silk_SMULWB( SILK_FIX_CONST( HARM_HP_NOISE_COEF, 24 ), psEnc->sCmn.speech_activity_Q8 ) ); + } else { + b_Q14 = silk_DIV32_16( 21299, psEnc->sCmn.fs_kHz ); /* 1.3_Q0 = 21299_Q14*/ + /* Pack two coefficients in one int32 */ + psEncCtrl->LF_shp_Q14[ 0 ] = silk_LSHIFT( SILK_FIX_CONST( 1.0, 14 ) - b_Q14 - + silk_SMULWB( strength_Q16, silk_SMULWB( SILK_FIX_CONST( 0.6, 16 ), b_Q14 ) ), 16 ); + psEncCtrl->LF_shp_Q14[ 0 ] |= (opus_uint16)( b_Q14 - SILK_FIX_CONST( 1.0, 14 ) ); + for( k = 1; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->LF_shp_Q14[ k ] = psEncCtrl->LF_shp_Q14[ 0 ]; + } + Tilt_Q16 = -SILK_FIX_CONST( HP_NOISE_COEF, 16 ); + } + + /****************************/ + /* HARMONIC SHAPING CONTROL */ + /****************************/ + /* Control boosting of harmonic frequencies */ + HarmBoost_Q16 = silk_SMULWB( silk_SMULWB( SILK_FIX_CONST( 1.0, 17 ) - silk_LSHIFT( psEncCtrl->coding_quality_Q14, 3 ), + psEnc->LTPCorr_Q15 ), SILK_FIX_CONST( LOW_RATE_HARMONIC_BOOST, 16 ) ); + + /* More harmonic boost for noisy input signals */ + HarmBoost_Q16 = silk_SMLAWB( HarmBoost_Q16, + SILK_FIX_CONST( 1.0, 16 ) - silk_LSHIFT( psEncCtrl->input_quality_Q14, 2 ), SILK_FIX_CONST( LOW_INPUT_QUALITY_HARMONIC_BOOST, 16 ) ); + + if( USE_HARM_SHAPING && psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* More harmonic noise shaping for high bitrates or noisy input */ + HarmShapeGain_Q16 = silk_SMLAWB( SILK_FIX_CONST( HARMONIC_SHAPING, 16 ), + SILK_FIX_CONST( 1.0, 16 ) - silk_SMULWB( SILK_FIX_CONST( 1.0, 18 ) - silk_LSHIFT( psEncCtrl->coding_quality_Q14, 4 ), + psEncCtrl->input_quality_Q14 ), SILK_FIX_CONST( HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING, 16 ) ); + + /* Less harmonic noise shaping for less periodic signals */ + HarmShapeGain_Q16 = silk_SMULWB( silk_LSHIFT( HarmShapeGain_Q16, 1 ), + silk_SQRT_APPROX( silk_LSHIFT( psEnc->LTPCorr_Q15, 15 ) ) ); + } else { + HarmShapeGain_Q16 = 0; + } + + /*************************/ + /* Smooth over subframes */ + /*************************/ + for( k = 0; k < MAX_NB_SUBFR; k++ ) { + psShapeSt->HarmBoost_smth_Q16 = + silk_SMLAWB( psShapeSt->HarmBoost_smth_Q16, HarmBoost_Q16 - psShapeSt->HarmBoost_smth_Q16, SILK_FIX_CONST( SUBFR_SMTH_COEF, 16 ) ); + psShapeSt->HarmShapeGain_smth_Q16 = + silk_SMLAWB( psShapeSt->HarmShapeGain_smth_Q16, HarmShapeGain_Q16 - psShapeSt->HarmShapeGain_smth_Q16, SILK_FIX_CONST( SUBFR_SMTH_COEF, 16 ) ); + psShapeSt->Tilt_smth_Q16 = + silk_SMLAWB( psShapeSt->Tilt_smth_Q16, Tilt_Q16 - psShapeSt->Tilt_smth_Q16, SILK_FIX_CONST( SUBFR_SMTH_COEF, 16 ) ); + + psEncCtrl->HarmBoost_Q14[ k ] = ( opus_int )silk_RSHIFT_ROUND( psShapeSt->HarmBoost_smth_Q16, 2 ); + psEncCtrl->HarmShapeGain_Q14[ k ] = ( opus_int )silk_RSHIFT_ROUND( psShapeSt->HarmShapeGain_smth_Q16, 2 ); + psEncCtrl->Tilt_Q14[ k ] = ( opus_int )silk_RSHIFT_ROUND( psShapeSt->Tilt_smth_Q16, 2 ); + } +} diff --git a/code/opus-1.0.2/silk/fixed/pitch_analysis_core_FIX.c b/code/opus-1.0.2/silk/fixed/pitch_analysis_core_FIX.c new file mode 100644 index 00000000..d43f444d --- /dev/null +++ b/code/opus-1.0.2/silk/fixed/pitch_analysis_core_FIX.c @@ -0,0 +1,745 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/*********************************************************** +* Pitch analyser function +********************************************************** */ +#include "SigProc_FIX.h" +#include "pitch_est_defines.h" +#include "debug.h" + +#define SCRATCH_SIZE 22 + +/************************************************************/ +/* Internally used functions */ +/************************************************************/ +void silk_P_Ana_calc_corr_st3( + opus_int32 cross_corr_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ],/* (O) 3 DIM correlation array */ + const opus_int16 frame[], /* I vector to correlate */ + opus_int start_lag, /* I lag offset to search around */ + opus_int sf_length, /* I length of a 5 ms subframe */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity /* I Complexity setting */ +); + +void silk_P_Ana_calc_energy_st3( + opus_int32 energies_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ],/* (O) 3 DIM energy array */ + const opus_int16 frame[], /* I vector to calc energy in */ + opus_int start_lag, /* I lag offset to search around */ + opus_int sf_length, /* I length of one 5 ms subframe */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity /* I Complexity setting */ +); + +opus_int32 silk_P_Ana_find_scaling( + const opus_int16 *frame, + const opus_int frame_length, + const opus_int sum_sqr_len +); + +/*************************************************************/ +/* FIXED POINT CORE PITCH ANALYSIS FUNCTION */ +/*************************************************************/ +opus_int silk_pitch_analysis_core( /* O Voicing estimate: 0 voiced, 1 unvoiced */ + const opus_int16 *frame, /* I Signal of length PE_FRAME_LENGTH_MS*Fs_kHz */ + opus_int *pitch_out, /* O 4 pitch lag values */ + opus_int16 *lagIndex, /* O Lag Index */ + opus_int8 *contourIndex, /* O Pitch contour Index */ + opus_int *LTPCorr_Q15, /* I/O Normalized correlation; input: value from previous frame */ + opus_int prevLag, /* I Last lag of previous frame; set to zero is unvoiced */ + const opus_int32 search_thres1_Q16, /* I First stage threshold for lag candidates 0 - 1 */ + const opus_int search_thres2_Q15, /* I Final threshold for lag candidates 0 - 1 */ + const opus_int Fs_kHz, /* I Sample frequency (kHz) */ + const opus_int complexity, /* I Complexity setting, 0-2, where 2 is highest */ + const opus_int nb_subfr /* I number of 5 ms subframes */ +) +{ + opus_int16 frame_8kHz[ PE_MAX_FRAME_LENGTH_ST_2 ]; + opus_int16 frame_4kHz[ PE_MAX_FRAME_LENGTH_ST_1 ]; + opus_int32 filt_state[ 6 ]; + opus_int32 scratch_mem[ 3 * PE_MAX_FRAME_LENGTH ]; + opus_int16 *input_frame_ptr; + opus_int i, k, d, j; + opus_int16 C[ PE_MAX_NB_SUBFR ][ ( PE_MAX_LAG >> 1 ) + 5 ]; + const opus_int16 *target_ptr, *basis_ptr; + opus_int32 cross_corr, normalizer, energy, shift, energy_basis, energy_target; + opus_int d_srch[ PE_D_SRCH_LENGTH ], Cmax, length_d_srch, length_d_comp; + opus_int16 d_comp[ ( PE_MAX_LAG >> 1 ) + 5 ]; + opus_int32 sum, threshold, temp32, lag_counter; + opus_int CBimax, CBimax_new, CBimax_old, lag, start_lag, end_lag, lag_new; + opus_int32 CC[ PE_NB_CBKS_STAGE2_EXT ], CCmax, CCmax_b, CCmax_new_b, CCmax_new; + opus_int32 energies_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ]; + opus_int32 crosscorr_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ]; + opus_int frame_length, frame_length_8kHz, frame_length_4kHz, max_sum_sq_length; + opus_int sf_length, sf_length_8kHz, sf_length_4kHz; + opus_int min_lag, min_lag_8kHz, min_lag_4kHz; + opus_int max_lag, max_lag_8kHz, max_lag_4kHz; + opus_int32 contour_bias_Q20, diff, lz, lshift; + opus_int nb_cbk_search, cbk_size; + opus_int32 delta_lag_log2_sqr_Q7, lag_log2_Q7, prevLag_log2_Q7, prev_lag_bias_Q15, corr_thres_Q15; + const opus_int8 *Lag_CB_ptr; + /* Check for valid sampling frequency */ + silk_assert( Fs_kHz == 8 || Fs_kHz == 12 || Fs_kHz == 16 ); + + /* Check for valid complexity setting */ + silk_assert( complexity >= SILK_PE_MIN_COMPLEX ); + silk_assert( complexity <= SILK_PE_MAX_COMPLEX ); + + silk_assert( search_thres1_Q16 >= 0 && search_thres1_Q16 <= (1<<16) ); + silk_assert( search_thres2_Q15 >= 0 && search_thres2_Q15 <= (1<<15) ); + + /* Set up frame lengths max / min lag for the sampling frequency */ + frame_length = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * Fs_kHz; + frame_length_4kHz = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * 4; + frame_length_8kHz = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * 8; + sf_length = PE_SUBFR_LENGTH_MS * Fs_kHz; + sf_length_4kHz = PE_SUBFR_LENGTH_MS * 4; + sf_length_8kHz = PE_SUBFR_LENGTH_MS * 8; + min_lag = PE_MIN_LAG_MS * Fs_kHz; + min_lag_4kHz = PE_MIN_LAG_MS * 4; + min_lag_8kHz = PE_MIN_LAG_MS * 8; + max_lag = PE_MAX_LAG_MS * Fs_kHz - 1; + max_lag_4kHz = PE_MAX_LAG_MS * 4; + max_lag_8kHz = PE_MAX_LAG_MS * 8 - 1; + + silk_memset( C, 0, sizeof( opus_int16 ) * nb_subfr * ( ( PE_MAX_LAG >> 1 ) + 5) ); + + /* Resample from input sampled at Fs_kHz to 8 kHz */ + if( Fs_kHz == 16 ) { + silk_memset( filt_state, 0, 2 * sizeof( opus_int32 ) ); + silk_resampler_down2( filt_state, frame_8kHz, frame, frame_length ); + } else if( Fs_kHz == 12 ) { + silk_memset( filt_state, 0, 6 * sizeof( opus_int32 ) ); + silk_resampler_down2_3( filt_state, frame_8kHz, frame, frame_length ); + } else { + silk_assert( Fs_kHz == 8 ); + silk_memcpy( frame_8kHz, frame, frame_length_8kHz * sizeof(opus_int16) ); + } + + /* Decimate again to 4 kHz */ + silk_memset( filt_state, 0, 2 * sizeof( opus_int32 ) );/* Set state to zero */ + silk_resampler_down2( filt_state, frame_4kHz, frame_8kHz, frame_length_8kHz ); + + /* Low-pass filter */ + for( i = frame_length_4kHz - 1; i > 0; i-- ) { + frame_4kHz[ i ] = silk_ADD_SAT16( frame_4kHz[ i ], frame_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 = silk_max_32( sf_length_8kHz, silk_LSHIFT( sf_length_4kHz, 2 ) ); + shift = silk_P_Ana_find_scaling( frame_4kHz, frame_length_4kHz, max_sum_sq_length ); + if( shift > 0 ) { + for( i = 0; i < frame_length_4kHz; i++ ) { + frame_4kHz[ i ] = silk_RSHIFT( frame_4kHz[ i ], shift ); + } + } + + /****************************************************************************** + * FIRST STAGE, operating in 4 khz + ******************************************************************************/ + target_ptr = &frame_4kHz[ silk_LSHIFT( sf_length_4kHz, 2 ) ]; + for( k = 0; k < nb_subfr >> 1; k++ ) { + /* Check that we are within range of the array */ + silk_assert( target_ptr >= frame_4kHz ); + silk_assert( target_ptr + sf_length_8kHz <= frame_4kHz + frame_length_4kHz ); + + basis_ptr = target_ptr - min_lag_4kHz; + + /* Check that we are within range of the array */ + silk_assert( basis_ptr >= frame_4kHz ); + silk_assert( basis_ptr + sf_length_8kHz <= frame_4kHz + frame_length_4kHz ); + + /* Calculate first vector products before loop */ + cross_corr = silk_inner_prod_aligned( target_ptr, basis_ptr, sf_length_8kHz ); + normalizer = silk_inner_prod_aligned( basis_ptr, basis_ptr, sf_length_8kHz ); + normalizer = silk_ADD_SAT32( normalizer, silk_SMULBB( sf_length_8kHz, 4000 ) ); + + temp32 = silk_DIV32( cross_corr, silk_SQRT_APPROX( normalizer ) + 1 ); + C[ k ][ min_lag_4kHz ] = (opus_int16)silk_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 */ + silk_assert( basis_ptr >= frame_4kHz ); + silk_assert( basis_ptr + sf_length_8kHz <= frame_4kHz + frame_length_4kHz ); + + cross_corr = silk_inner_prod_aligned( target_ptr, basis_ptr, sf_length_8kHz ); + + /* Add contribution of new sample and remove contribution from oldest sample */ + normalizer += + silk_SMULBB( basis_ptr[ 0 ], basis_ptr[ 0 ] ) - + silk_SMULBB( basis_ptr[ sf_length_8kHz ], basis_ptr[ sf_length_8kHz ] ); + + temp32 = silk_DIV32( cross_corr, silk_SQRT_APPROX( normalizer ) + 1 ); + C[ k ][ d ] = (opus_int16)silk_SAT16( temp32 ); /* Q0 */ + } + /* Update target pointer */ + target_ptr += sf_length_8kHz; + } + + /* Combine two subframes into single correlation measure and apply short-lag bias */ + if( nb_subfr == PE_MAX_NB_SUBFR ) { + for( i = max_lag_4kHz; i >= min_lag_4kHz; i-- ) { + sum = (opus_int32)C[ 0 ][ i ] + (opus_int32)C[ 1 ][ i ]; /* Q0 */ + silk_assert( silk_RSHIFT( sum, 1 ) == silk_SAT16( silk_RSHIFT( sum, 1 ) ) ); + sum = silk_RSHIFT( sum, 1 ); /* Q-1 */ + silk_assert( silk_LSHIFT( (opus_int32)-i, 4 ) == silk_SAT16( silk_LSHIFT( (opus_int32)-i, 4 ) ) ); + sum = silk_SMLAWB( sum, sum, silk_LSHIFT( -i, 4 ) ); /* Q-1 */ + silk_assert( sum == silk_SAT16( sum ) ); + C[ 0 ][ i ] = (opus_int16)sum; /* Q-1 */ + } + } else { + /* Only short-lag bias */ + for( i = max_lag_4kHz; i >= min_lag_4kHz; i-- ) { + sum = (opus_int32)C[ 0 ][ i ]; + sum = silk_SMLAWB( sum, sum, silk_LSHIFT( -i, 4 ) ); /* Q-1 */ + C[ 0 ][ i ] = (opus_int16)sum; /* Q-1 */ + } + } + + /* Sort */ + length_d_srch = silk_ADD_LSHIFT32( 4, complexity, 1 ); + silk_assert( 3 * length_d_srch <= PE_D_SRCH_LENGTH ); + 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 = &frame_4kHz[ silk_SMULBB( sf_length_4kHz, nb_subfr ) ]; + energy = silk_inner_prod_aligned( target_ptr, target_ptr, silk_LSHIFT( sf_length_4kHz, 2 ) ); + energy = silk_ADD_SAT32( energy, 1000 ); /* Q0 */ + Cmax = (opus_int)C[ 0 ][ min_lag_4kHz ]; /* Q-1 */ + threshold = silk_SMULBB( Cmax, Cmax ); /* Q-2 */ + + /* Compare in Q-2 domain */ + if( silk_RSHIFT( energy, 4 + 2 ) > threshold ) { + silk_memset( pitch_out, 0, nb_subfr * sizeof( opus_int ) ); + *LTPCorr_Q15 = 0; + *lagIndex = 0; + *contourIndex = 0; + return 1; + } + + threshold = silk_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 ] = silk_LSHIFT( d_srch[ i ] + min_lag_4kHz, 1 ); + } else { + length_d_srch = i; + break; + } + } + silk_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 = silk_P_Ana_find_scaling( frame_8kHz, frame_length_8kHz, sf_length_8kHz ); + if( shift > 0 ) { + for( i = 0; i < frame_length_8kHz; i++ ) { + frame_8kHz[ i ] = silk_RSHIFT( frame_8kHz[ i ], shift ); + } + } + + /********************************************************************************* + * Find energy of each subframe projected onto its history, for a range of delays + *********************************************************************************/ + silk_memset( C, 0, PE_MAX_NB_SUBFR * ( ( PE_MAX_LAG >> 1 ) + 5 ) * sizeof( opus_int16 ) ); + + target_ptr = &frame_8kHz[ PE_LTP_MEM_LENGTH_MS * 8 ]; + for( k = 0; k < nb_subfr; k++ ) { + + /* Check that we are within range of the array */ + silk_assert( target_ptr >= frame_8kHz ); + silk_assert( target_ptr + sf_length_8kHz <= frame_8kHz + frame_length_8kHz ); + + energy_target = silk_inner_prod_aligned( target_ptr, target_ptr, sf_length_8kHz ); + for( j = 0; j < length_d_comp; j++ ) { + d = d_comp[ j ]; + basis_ptr = target_ptr - d; + + /* Check that we are within range of the array */ + silk_assert( basis_ptr >= frame_8kHz ); + silk_assert( basis_ptr + sf_length_8kHz <= frame_8kHz + frame_length_8kHz ); + + cross_corr = silk_inner_prod_aligned( target_ptr, basis_ptr, sf_length_8kHz ); + energy_basis = silk_inner_prod_aligned( basis_ptr, basis_ptr, sf_length_8kHz ); + if( cross_corr > 0 ) { + energy = silk_max( energy_target, energy_basis ); /* Find max to make sure first division < 1.0 */ + lz = silk_CLZ32( cross_corr ); + lshift = silk_LIMIT_32( lz - 1, 0, 15 ); + temp32 = silk_DIV32( silk_LSHIFT( cross_corr, lshift ), silk_RSHIFT( energy, 15 - lshift ) + 1 ); /* Q15 */ + silk_assert( temp32 == silk_SAT16( temp32 ) ); + temp32 = silk_SMULWB( cross_corr, temp32 ); /* Q(-1), cc * ( cc / max(b, t) ) */ + temp32 = silk_ADD_SAT32( temp32, temp32 ); /* Q(0) */ + lz = silk_CLZ32( temp32 ); + lshift = silk_LIMIT_32( lz - 1, 0, 15 ); + energy = silk_min( energy_target, energy_basis ); + C[ k ][ d ] = silk_DIV32( silk_LSHIFT( temp32, lshift ), silk_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 = silk_int32_MIN; + CCmax_b = silk_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 = silk_DIV32_16( silk_LSHIFT( prevLag, 1 ), 3 ); + } else if( Fs_kHz == 16 ) { + prevLag = silk_RSHIFT( prevLag, 1 ); + } + prevLag_log2_Q7 = silk_lin2log( (opus_int32)prevLag ); + } else { + prevLag_log2_Q7 = 0; + } + silk_assert( search_thres2_Q15 == silk_SAT16( search_thres2_Q15 ) ); + /* Set up stage 2 codebook based on number of subframes */ + if( nb_subfr == PE_MAX_NB_SUBFR ) { + cbk_size = PE_NB_CBKS_STAGE2_EXT; + Lag_CB_ptr = &silk_CB_lags_stage2[ 0 ][ 0 ]; + if( Fs_kHz == 8 && complexity > SILK_PE_MIN_COMPLEX ) { + /* If input is 8 khz use a larger codebook here because it is last stage */ + nb_cbk_search = PE_NB_CBKS_STAGE2_EXT; + } else { + nb_cbk_search = PE_NB_CBKS_STAGE2; + } + corr_thres_Q15 = silk_RSHIFT( silk_SMULBB( search_thres2_Q15, search_thres2_Q15 ), 13 ); + } else { + cbk_size = PE_NB_CBKS_STAGE2_10MS; + Lag_CB_ptr = &silk_CB_lags_stage2_10_ms[ 0 ][ 0 ]; + nb_cbk_search = PE_NB_CBKS_STAGE2_10MS; + corr_thres_Q15 = silk_RSHIFT( silk_SMULBB( search_thres2_Q15, search_thres2_Q15 ), 14 ); + } + + for( k = 0; k < length_d_srch; k++ ) { + d = d_srch[ k ]; + for( j = 0; j < nb_cbk_search; j++ ) { + CC[ j ] = 0; + for( i = 0; i < nb_subfr; i++ ) { + /* Try all codebooks */ + CC[ j ] = CC[ j ] + (opus_int32)C[ i ][ d + matrix_ptr( Lag_CB_ptr, i, j, cbk_size )]; + } + } + /* Find best codebook */ + CCmax_new = silk_int32_MIN; + CBimax_new = 0; + for( i = 0; i < nb_cbk_search; i++ ) { + if( CC[ i ] > CCmax_new ) { + CCmax_new = CC[ i ]; + CBimax_new = i; + } + } + + /* Bias towards shorter lags */ + lag_log2_Q7 = silk_lin2log( (opus_int32)d ); /* Q7 */ + silk_assert( lag_log2_Q7 == silk_SAT16( lag_log2_Q7 ) ); + silk_assert( nb_subfr * SILK_FIX_CONST( PE_SHORTLAG_BIAS, 15 ) == silk_SAT16( nb_subfr * SILK_FIX_CONST( PE_SHORTLAG_BIAS, 15 ) ) ); + CCmax_new_b = CCmax_new - silk_RSHIFT( silk_SMULBB( nb_subfr * SILK_FIX_CONST( PE_SHORTLAG_BIAS, 15 ), lag_log2_Q7 ), 7 ); /* Q15 */ + + /* Bias towards previous lag */ + silk_assert( nb_subfr * SILK_FIX_CONST( PE_PREVLAG_BIAS, 15 ) == silk_SAT16( nb_subfr * SILK_FIX_CONST( PE_PREVLAG_BIAS, 15 ) ) ); + if( prevLag > 0 ) { + delta_lag_log2_sqr_Q7 = lag_log2_Q7 - prevLag_log2_Q7; + silk_assert( delta_lag_log2_sqr_Q7 == silk_SAT16( delta_lag_log2_sqr_Q7 ) ); + delta_lag_log2_sqr_Q7 = silk_RSHIFT( silk_SMULBB( delta_lag_log2_sqr_Q7, delta_lag_log2_sqr_Q7 ), 7 ); + prev_lag_bias_Q15 = silk_RSHIFT( silk_SMULBB( nb_subfr * SILK_FIX_CONST( PE_PREVLAG_BIAS, 15 ), *LTPCorr_Q15 ), 15 ); /* Q15 */ + prev_lag_bias_Q15 = silk_DIV32( silk_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 */ + 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 */ + silk_memset( pitch_out, 0, nb_subfr * sizeof( opus_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 = silk_P_Ana_find_scaling( frame, 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_frame_ptr = (opus_int16*)scratch_mem; + for( i = 0; i < frame_length; i++ ) { + input_frame_ptr[ i ] = silk_RSHIFT( frame[ i ], shift ); + } + } else { + input_frame_ptr = (opus_int16*)frame; + } + + /* Search in original signal */ + + CBimax_old = CBimax; + /* Compensate for decimation */ + silk_assert( lag == silk_SAT16( lag ) ); + if( Fs_kHz == 12 ) { + lag = silk_RSHIFT( silk_SMULBB( lag, 3 ), 1 ); + } else if( Fs_kHz == 16 ) { + lag = silk_LSHIFT( lag, 1 ); + } else { + lag = silk_SMULBB( lag, 3 ); + } + + lag = silk_LIMIT_int( lag, min_lag, max_lag ); + start_lag = silk_max_int( lag - 2, min_lag ); + end_lag = silk_min_int( lag + 2, max_lag ); + lag_new = lag; /* to avoid undefined lag */ + CBimax = 0; /* to avoid undefined lag */ + silk_assert( silk_LSHIFT( CCmax, 13 ) >= 0 ); + *LTPCorr_Q15 = (opus_int)silk_SQRT_APPROX( silk_LSHIFT( CCmax, 13 ) ); /* Output normalized correlation */ + + CCmax = silk_int32_MIN; + /* pitch lags according to second stage */ + for( k = 0; k < nb_subfr; k++ ) { + pitch_out[ k ] = lag + 2 * silk_CB_lags_stage2[ k ][ CBimax_old ]; + } + /* Calculate the correlations and energies needed in stage 3 */ + silk_P_Ana_calc_corr_st3( crosscorr_st3, input_frame_ptr, start_lag, sf_length, nb_subfr, complexity ); + silk_P_Ana_calc_energy_st3( energies_st3, input_frame_ptr, start_lag, sf_length, nb_subfr, complexity ); + + lag_counter = 0; + silk_assert( lag == silk_SAT16( lag ) ); + contour_bias_Q20 = silk_DIV32_16( SILK_FIX_CONST( PE_FLATCONTOUR_BIAS, 20 ), lag ); + + /* Set up codebook parameters according to complexity setting and frame length */ + if( nb_subfr == PE_MAX_NB_SUBFR ) { + nb_cbk_search = (opus_int)silk_nb_cbk_searchs_stage3[ complexity ]; + cbk_size = PE_NB_CBKS_STAGE3_MAX; + Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ]; + } else { + nb_cbk_search = PE_NB_CBKS_STAGE3_10MS; + cbk_size = PE_NB_CBKS_STAGE3_10MS; + Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ]; + } + for( d = start_lag; d <= end_lag; d++ ) { + for( j = 0; j < nb_cbk_search; j++ ) { + cross_corr = 0; + energy = 0; + for( k = 0; k < nb_subfr; k++ ) { + silk_assert( PE_MAX_NB_SUBFR == 4 ); + energy += silk_RSHIFT( energies_st3[ k ][ j ][ lag_counter ], 2 ); /* use mean, to avoid overflow */ + silk_assert( energy >= 0 ); + cross_corr += silk_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 = silk_CLZ32( cross_corr ); + /* Divide with result in Q13, cross_corr could be larger than energy */ + lshift = silk_LIMIT_32( lz - 1, 0, 13 ); + CCmax_new = silk_DIV32( silk_LSHIFT( cross_corr, lshift ), silk_RSHIFT( energy, 13 - lshift ) + 1 ); + CCmax_new = silk_SAT16( CCmax_new ); + CCmax_new = silk_SMULWB( cross_corr, CCmax_new ); + /* Saturate */ + if( CCmax_new > silk_RSHIFT( silk_int32_MAX, 3 ) ) { + CCmax_new = silk_int32_MAX; + } else { + CCmax_new = silk_LSHIFT( CCmax_new, 3 ); + } + /* Reduce depending on flatness of contour */ + diff = silk_int16_MAX - silk_RSHIFT( silk_MUL( contour_bias_Q20, j ), 5 ); /* Q20 -> Q15 */ + silk_assert( diff == silk_SAT16( diff ) ); + CCmax_new = silk_LSHIFT( silk_SMULWB( CCmax_new, diff ), 1 ); + } else { + CCmax_new = 0; + } + + if( CCmax_new > CCmax && + ( d + silk_CB_lags_stage3[ 0 ][ j ] ) <= max_lag + ) { + CCmax = CCmax_new; + lag_new = d; + CBimax = j; + } + } + lag_counter++; + } + + for( k = 0; k < nb_subfr; k++ ) { + pitch_out[ k ] = lag_new + matrix_ptr( Lag_CB_ptr, k, CBimax, cbk_size ); + pitch_out[ k ] = silk_LIMIT( pitch_out[ k ], min_lag, PE_MAX_LAG_MS * Fs_kHz ); + } + *lagIndex = (opus_int16)( lag_new - min_lag); + *contourIndex = (opus_int8)CBimax; + } else { /* Fs_kHz == 8 */ + /* Save Lags and correlation */ + CCmax = silk_max( CCmax, 0 ); + *LTPCorr_Q15 = (opus_int)silk_SQRT_APPROX( silk_LSHIFT( CCmax, 13 ) ); /* Output normalized correlation */ + for( k = 0; k < nb_subfr; k++ ) { + pitch_out[ k ] = lag + matrix_ptr( Lag_CB_ptr, k, CBimax, cbk_size ); + pitch_out[ k ] = silk_LIMIT( pitch_out[ k ], min_lag_8kHz, PE_MAX_LAG_MS * Fs_kHz ); + } + *lagIndex = (opus_int16)( lag - min_lag_8kHz ); + *contourIndex = (opus_int8)CBimax; + } + silk_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 silk_P_Ana_calc_corr_st3( + opus_int32 cross_corr_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ],/* (O) 3 DIM correlation array */ + const opus_int16 frame[], /* I vector to correlate */ + opus_int start_lag, /* I lag offset to search around */ + opus_int sf_length, /* I length of a 5 ms subframe */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity /* I Complexity setting */ +) +{ + const opus_int16 *target_ptr, *basis_ptr; + opus_int32 cross_corr; + opus_int i, j, k, lag_counter, lag_low, lag_high; + opus_int nb_cbk_search, delta, idx, cbk_size; + opus_int32 scratch_mem[ SCRATCH_SIZE ]; + const opus_int8 *Lag_range_ptr, *Lag_CB_ptr; + + silk_assert( complexity >= SILK_PE_MIN_COMPLEX ); + silk_assert( complexity <= SILK_PE_MAX_COMPLEX ); + + if( nb_subfr == PE_MAX_NB_SUBFR ) { + Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ]; + nb_cbk_search = silk_nb_cbk_searchs_stage3[ complexity ]; + cbk_size = PE_NB_CBKS_STAGE3_MAX; + } else { + silk_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1); + Lag_range_ptr = &silk_Lag_range_stage3_10_ms[ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ]; + nb_cbk_search = PE_NB_CBKS_STAGE3_10MS; + cbk_size = PE_NB_CBKS_STAGE3_10MS; + } + + target_ptr = &frame[ silk_LSHIFT( sf_length, 2 ) ]; /* Pointer to middle of frame */ + for( k = 0; k < nb_subfr; k++ ) { + lag_counter = 0; + + /* Calculate the correlations for each subframe */ + lag_low = matrix_ptr( Lag_range_ptr, k, 0, 2 ); + lag_high = matrix_ptr( Lag_range_ptr, k, 1, 2 ); + for( j = lag_low; j <= lag_high; j++ ) { + basis_ptr = target_ptr - ( start_lag + j ); + cross_corr = silk_inner_prod_aligned( (opus_int16*)target_ptr, (opus_int16*)basis_ptr, sf_length ); + silk_assert( lag_counter < SCRATCH_SIZE ); + scratch_mem[ lag_counter ] = cross_corr; + lag_counter++; + } + + delta = matrix_ptr( Lag_range_ptr, k, 0, 2 ); + for( i = 0; i < nb_cbk_search; i++ ) { + /* Fill out the 3 dim array that stores the correlations for */ + /* each code_book vector for each start lag */ + idx = matrix_ptr( Lag_CB_ptr, k, i, cbk_size ) - delta; + for( j = 0; j < PE_NB_STAGE3_LAGS; j++ ) { + silk_assert( idx + j < SCRATCH_SIZE ); + silk_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 silk_P_Ana_calc_energy_st3( + opus_int32 energies_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ],/* (O) 3 DIM energy array */ + const opus_int16 frame[], /* I vector to calc energy in */ + opus_int start_lag, /* I lag offset to search around */ + opus_int sf_length, /* I length of one 5 ms subframe */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity /* I Complexity setting */ +) +{ + const opus_int16 *target_ptr, *basis_ptr; + opus_int32 energy; + opus_int k, i, j, lag_counter; + opus_int nb_cbk_search, delta, idx, cbk_size, lag_diff; + opus_int32 scratch_mem[ SCRATCH_SIZE ]; + const opus_int8 *Lag_range_ptr, *Lag_CB_ptr; + + silk_assert( complexity >= SILK_PE_MIN_COMPLEX ); + silk_assert( complexity <= SILK_PE_MAX_COMPLEX ); + + if( nb_subfr == PE_MAX_NB_SUBFR ) { + Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ]; + nb_cbk_search = silk_nb_cbk_searchs_stage3[ complexity ]; + cbk_size = PE_NB_CBKS_STAGE3_MAX; + } else { + silk_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1); + Lag_range_ptr = &silk_Lag_range_stage3_10_ms[ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ]; + nb_cbk_search = PE_NB_CBKS_STAGE3_10MS; + cbk_size = PE_NB_CBKS_STAGE3_10MS; + } + target_ptr = &frame[ silk_LSHIFT( sf_length, 2 ) ]; + for( k = 0; k < nb_subfr; k++ ) { + lag_counter = 0; + + /* Calculate the energy for first lag */ + basis_ptr = target_ptr - ( start_lag + matrix_ptr( Lag_range_ptr, k, 0, 2 ) ); + energy = silk_inner_prod_aligned( basis_ptr, basis_ptr, sf_length ); + silk_assert( energy >= 0 ); + scratch_mem[ lag_counter ] = energy; + lag_counter++; + + lag_diff = ( matrix_ptr( Lag_range_ptr, k, 1, 2 ) - matrix_ptr( Lag_range_ptr, k, 0, 2 ) + 1 ); + for( i = 1; i < lag_diff; i++ ) { + /* remove part outside new window */ + energy -= silk_SMULBB( basis_ptr[ sf_length - i ], basis_ptr[ sf_length - i ] ); + silk_assert( energy >= 0 ); + + /* add part that comes into window */ + energy = silk_ADD_SAT32( energy, silk_SMULBB( basis_ptr[ -i ], basis_ptr[ -i ] ) ); + silk_assert( energy >= 0 ); + silk_assert( lag_counter < SCRATCH_SIZE ); + scratch_mem[ lag_counter ] = energy; + lag_counter++; + } + + delta = matrix_ptr( Lag_range_ptr, k, 0, 2 ); + for( i = 0; i < nb_cbk_search; i++ ) { + /* Fill out the 3 dim array that stores the correlations for */ + /* each code_book vector for each start lag */ + idx = matrix_ptr( Lag_CB_ptr, k, i, cbk_size ) - delta; + for( j = 0; j < PE_NB_STAGE3_LAGS; j++ ) { + silk_assert( idx + j < SCRATCH_SIZE ); + silk_assert( idx + j < lag_counter ); + energies_st3[ k ][ i ][ j ] = scratch_mem[ idx + j ]; + silk_assert( energies_st3[ k ][ i ][ j ] >= 0 ); + } + } + target_ptr += sf_length; + } +} + +opus_int32 silk_P_Ana_find_scaling( + const opus_int16 *frame, + const opus_int frame_length, + const opus_int sum_sqr_len +) +{ + opus_int32 nbits, x_max; + + x_max = silk_int16_array_maxabs( frame, frame_length ); + + if( x_max < silk_int16_MAX ) { + /* Number of bits needed for the sum of the squares */ + nbits = 32 - silk_CLZ32( silk_SMULBB( x_max, x_max ) ); + } else { + /* Here we don't know if x_max should have been silk_int16_MAX + 1, so we expect the worst case */ + nbits = 30; + } + nbits += 17 - 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/code/opus-1.0.2/silk/fixed/prefilter_FIX.c b/code/opus-1.0.2/silk/fixed/prefilter_FIX.c new file mode 100644 index 00000000..a96f5118 --- /dev/null +++ b/code/opus-1.0.2/silk/fixed/prefilter_FIX.c @@ -0,0 +1,204 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" +#include "tuning_parameters.h" + +/* Prefilter for finding Quantizer input signal */ +static inline void silk_prefilt_FIX( + silk_prefilter_state_FIX *P, /* I/O state */ + opus_int32 st_res_Q12[], /* I short term residual signal */ + opus_int32 xw_Q3[], /* O prefiltered signal */ + opus_int32 HarmShapeFIRPacked_Q12, /* I Harmonic shaping coeficients */ + opus_int Tilt_Q14, /* I Tilt shaping coeficient */ + opus_int32 LF_shp_Q14, /* I Low-frequancy shaping coeficients */ + opus_int lag, /* I Lag for harmonic shaping */ + opus_int length /* I Length of signals */ +); + +void silk_warped_LPC_analysis_filter_FIX( + opus_int32 state[], /* I/O State [order + 1] */ + opus_int32 res_Q2[], /* O Residual signal [length] */ + const opus_int16 coef_Q13[], /* I Coefficients [order] */ + const opus_int16 input[], /* I Input signal [length] */ + const opus_int16 lambda_Q16, /* I Warping factor */ + const opus_int length, /* I Length of input signal */ + const opus_int order /* I Filter order (even) */ +) +{ + opus_int n, i; + opus_int32 acc_Q11, tmp1, tmp2; + + /* Order must be even */ + silk_assert( ( order & 1 ) == 0 ); + + for( n = 0; n < length; n++ ) { + /* Output of lowpass section */ + tmp2 = silk_SMLAWB( state[ 0 ], state[ 1 ], lambda_Q16 ); + state[ 0 ] = silk_LSHIFT( input[ n ], 14 ); + /* Output of allpass section */ + tmp1 = silk_SMLAWB( state[ 1 ], state[ 2 ] - tmp2, lambda_Q16 ); + state[ 1 ] = tmp2; + acc_Q11 = silk_RSHIFT( order, 1 ); + acc_Q11 = silk_SMLAWB( acc_Q11, tmp2, coef_Q13[ 0 ] ); + /* Loop over allpass sections */ + for( i = 2; i < order; i += 2 ) { + /* Output of allpass section */ + tmp2 = silk_SMLAWB( state[ i ], state[ i + 1 ] - tmp1, lambda_Q16 ); + state[ i ] = tmp1; + acc_Q11 = silk_SMLAWB( acc_Q11, tmp1, coef_Q13[ i - 1 ] ); + /* Output of allpass section */ + tmp1 = silk_SMLAWB( state[ i + 1 ], state[ i + 2 ] - tmp2, lambda_Q16 ); + state[ i + 1 ] = tmp2; + acc_Q11 = silk_SMLAWB( acc_Q11, tmp2, coef_Q13[ i ] ); + } + state[ order ] = tmp1; + acc_Q11 = silk_SMLAWB( acc_Q11, tmp1, coef_Q13[ order - 1 ] ); + res_Q2[ n ] = silk_LSHIFT( (opus_int32)input[ n ], 2 ) - silk_RSHIFT_ROUND( acc_Q11, 9 ); + } +} + +void silk_prefilter_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Encoder state */ + const silk_encoder_control_FIX *psEncCtrl, /* I Encoder control */ + opus_int32 xw_Q3[], /* O Weighted signal */ + const opus_int16 x[] /* I Speech signal */ +) +{ + silk_prefilter_state_FIX *P = &psEnc->sPrefilt; + opus_int j, k, lag; + opus_int32 tmp_32; + const opus_int16 *AR1_shp_Q13; + const opus_int16 *px; + opus_int32 *pxw_Q3; + opus_int HarmShapeGain_Q12, Tilt_Q14; + opus_int32 HarmShapeFIRPacked_Q12, LF_shp_Q14; + opus_int32 x_filt_Q12[ MAX_SUB_FRAME_LENGTH ]; + opus_int32 st_res_Q2[ MAX_SUB_FRAME_LENGTH + MAX_LPC_ORDER ]; + opus_int16 B_Q10[ 2 ]; + + /* Set up pointers */ + px = x; + pxw_Q3 = xw_Q3; + lag = P->lagPrev; + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + /* Update Variables that change per sub frame */ + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + lag = psEncCtrl->pitchL[ k ]; + } + + /* Noise shape parameters */ + HarmShapeGain_Q12 = silk_SMULWB( (opus_int32)psEncCtrl->HarmShapeGain_Q14[ k ], 16384 - psEncCtrl->HarmBoost_Q14[ k ] ); + silk_assert( HarmShapeGain_Q12 >= 0 ); + HarmShapeFIRPacked_Q12 = silk_RSHIFT( HarmShapeGain_Q12, 2 ); + HarmShapeFIRPacked_Q12 |= silk_LSHIFT( (opus_int32)silk_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*/ + silk_warped_LPC_analysis_filter_FIX( P->sAR_shp, st_res_Q2, AR1_shp_Q13, px, + psEnc->sCmn.warping_Q16, psEnc->sCmn.subfr_length, psEnc->sCmn.shapingLPCOrder ); + + /* Reduce (mainly) low frequencies during harmonic emphasis */ + B_Q10[ 0 ] = silk_RSHIFT_ROUND( psEncCtrl->GainsPre_Q14[ k ], 4 ); + tmp_32 = silk_SMLABB( SILK_FIX_CONST( INPUT_TILT, 26 ), psEncCtrl->HarmBoost_Q14[ k ], HarmShapeGain_Q12 ); /* Q26 */ + tmp_32 = silk_SMLABB( tmp_32, psEncCtrl->coding_quality_Q14, SILK_FIX_CONST( HIGH_RATE_INPUT_TILT, 12 ) ); /* Q26 */ + tmp_32 = silk_SMULWB( tmp_32, -psEncCtrl->GainsPre_Q14[ k ] ); /* Q24 */ + tmp_32 = silk_RSHIFT_ROUND( tmp_32, 14 ); /* Q10 */ + B_Q10[ 1 ]= silk_SAT16( tmp_32 ); + x_filt_Q12[ 0 ] = silk_MLA( silk_MUL( st_res_Q2[ 0 ], B_Q10[ 0 ] ), P->sHarmHP_Q2, B_Q10[ 1 ] ); + for( j = 1; j < psEnc->sCmn.subfr_length; j++ ) { + x_filt_Q12[ j ] = silk_MLA( silk_MUL( st_res_Q2[ j ], B_Q10[ 0 ] ), st_res_Q2[ j - 1 ], B_Q10[ 1 ] ); + } + P->sHarmHP_Q2 = st_res_Q2[ psEnc->sCmn.subfr_length - 1 ]; + + silk_prefilt_FIX( P, x_filt_Q12, pxw_Q3, HarmShapeFIRPacked_Q12, Tilt_Q14, LF_shp_Q14, lag, psEnc->sCmn.subfr_length ); + + px += psEnc->sCmn.subfr_length; + pxw_Q3 += psEnc->sCmn.subfr_length; + } + + P->lagPrev = psEncCtrl->pitchL[ psEnc->sCmn.nb_subfr - 1 ]; +} + +/* Prefilter for finding Quantizer input signal */ +static inline void silk_prefilt_FIX( + silk_prefilter_state_FIX *P, /* I/O state */ + opus_int32 st_res_Q12[], /* I short term residual signal */ + opus_int32 xw_Q3[], /* O prefiltered signal */ + opus_int32 HarmShapeFIRPacked_Q12, /* I Harmonic shaping coeficients */ + opus_int Tilt_Q14, /* I Tilt shaping coeficient */ + opus_int32 LF_shp_Q14, /* I Low-frequancy shaping coeficients */ + opus_int lag, /* I Lag for harmonic shaping */ + opus_int length /* I Length of signals */ +) +{ + opus_int i, idx, LTP_shp_buf_idx; + opus_int32 n_LTP_Q12, n_Tilt_Q10, n_LF_Q10; + opus_int32 sLF_MA_shp_Q12, sLF_AR_shp_Q12; + opus_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 */ + silk_assert( HARM_SHAPE_FIR_TAPS == 3 ); + idx = lag + LTP_shp_buf_idx; + n_LTP_Q12 = silk_SMULBB( LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 - 1) & LTP_MASK ], HarmShapeFIRPacked_Q12 ); + n_LTP_Q12 = silk_SMLABT( n_LTP_Q12, LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 ) & LTP_MASK ], HarmShapeFIRPacked_Q12 ); + n_LTP_Q12 = silk_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 = silk_SMULWB( sLF_AR_shp_Q12, Tilt_Q14 ); + n_LF_Q10 = silk_SMLAWB( silk_SMULWT( sLF_AR_shp_Q12, LF_shp_Q14 ), sLF_MA_shp_Q12, LF_shp_Q14 ); + + sLF_AR_shp_Q12 = silk_SUB32( st_res_Q12[ i ], silk_LSHIFT( n_Tilt_Q10, 2 ) ); + sLF_MA_shp_Q12 = silk_SUB32( sLF_AR_shp_Q12, silk_LSHIFT( n_LF_Q10, 2 ) ); + + LTP_shp_buf_idx = ( LTP_shp_buf_idx - 1 ) & LTP_MASK; + LTP_shp_buf[ LTP_shp_buf_idx ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sLF_MA_shp_Q12, 12 ) ); + + xw_Q3[i] = silk_RSHIFT_ROUND( silk_SUB32( sLF_MA_shp_Q12, n_LTP_Q12 ), 9 ); + } + + /* 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/code/opus-1.0.2/silk/fixed/process_gains_FIX.c b/code/opus-1.0.2/silk/fixed/process_gains_FIX.c new file mode 100644 index 00000000..22d3a71a --- /dev/null +++ b/code/opus-1.0.2/silk/fixed/process_gains_FIX.c @@ -0,0 +1,117 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" +#include "tuning_parameters.h" + +/* Processing of gains */ +void silk_process_gains_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + silk_shape_state_FIX *psShapeSt = &psEnc->sShape; + opus_int k; + opus_int32 s_Q16, InvMaxSqrVal_Q16, gain, gain_squared, ResNrg, ResNrgPart, quant_offset_Q10; + + /* Gain reduction when LTP coding gain is high */ + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /*s = -0.5f * silk_sigmoid( 0.25f * ( psEncCtrl->LTPredCodGain - 12.0f ) ); */ + s_Q16 = -silk_sigm_Q15( silk_RSHIFT_ROUND( psEncCtrl->LTPredCodGain_Q7 - SILK_FIX_CONST( 12.0, 7 ), 4 ) ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->Gains_Q16[ k ] = silk_SMLAWB( psEncCtrl->Gains_Q16[ k ], psEncCtrl->Gains_Q16[ k ], s_Q16 ); + } + } + + /* Limit the quantized signal */ + /* InvMaxSqrVal = pow( 2.0f, 0.33f * ( 21.0f - SNR_dB ) ) / subfr_length; */ + InvMaxSqrVal_Q16 = silk_DIV32_16( silk_log2lin( + silk_SMULWB( SILK_FIX_CONST( 21 + 16 / 0.33, 7 ) - psEnc->sCmn.SNR_dB_Q7, SILK_FIX_CONST( 0.33, 16 ) ) ), psEnc->sCmn.subfr_length ); + + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + /* Soft limit on ratio residual energy and squared gains */ + ResNrg = psEncCtrl->ResNrg[ k ]; + ResNrgPart = silk_SMULWW( ResNrg, InvMaxSqrVal_Q16 ); + if( psEncCtrl->ResNrgQ[ k ] > 0 ) { + ResNrgPart = silk_RSHIFT_ROUND( ResNrgPart, psEncCtrl->ResNrgQ[ k ] ); + } else { + if( ResNrgPart >= silk_RSHIFT( silk_int32_MAX, -psEncCtrl->ResNrgQ[ k ] ) ) { + ResNrgPart = silk_int32_MAX; + } else { + ResNrgPart = silk_LSHIFT( ResNrgPart, -psEncCtrl->ResNrgQ[ k ] ); + } + } + gain = psEncCtrl->Gains_Q16[ k ]; + gain_squared = silk_ADD_SAT32( ResNrgPart, silk_SMMUL( gain, gain ) ); + if( gain_squared < silk_int16_MAX ) { + /* recalculate with higher precision */ + gain_squared = silk_SMLAWW( silk_LSHIFT( ResNrgPart, 16 ), gain, gain ); + silk_assert( gain_squared > 0 ); + gain = silk_SQRT_APPROX( gain_squared ); /* Q8 */ + gain = silk_min( gain, silk_int32_MAX >> 8 ); + psEncCtrl->Gains_Q16[ k ] = silk_LSHIFT_SAT32( gain, 8 ); /* Q16 */ + } else { + gain = silk_SQRT_APPROX( gain_squared ); /* Q0 */ + gain = silk_min( gain, silk_int32_MAX >> 16 ); + psEncCtrl->Gains_Q16[ k ] = silk_LSHIFT_SAT32( gain, 16 ); /* Q16 */ + } + } + + /* Save unquantized gains and gain Index */ + silk_memcpy( psEncCtrl->GainsUnq_Q16, psEncCtrl->Gains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) ); + psEncCtrl->lastGainIndexPrev = psShapeSt->LastGainIndex; + + /* Quantize gains */ + silk_gains_quant( psEnc->sCmn.indices.GainsIndices, psEncCtrl->Gains_Q16, + &psShapeSt->LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr ); + + /* Set quantizer offset for voiced signals. Larger offset when LTP coding gain is low or tilt is high (ie low-pass) */ + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + if( psEncCtrl->LTPredCodGain_Q7 + silk_RSHIFT( psEnc->sCmn.input_tilt_Q15, 8 ) > SILK_FIX_CONST( 1.0, 7 ) ) { + psEnc->sCmn.indices.quantOffsetType = 0; + } else { + psEnc->sCmn.indices.quantOffsetType = 1; + } + } + + /* Quantizer boundary adjustment */ + quant_offset_Q10 = silk_Quantization_Offsets_Q10[ psEnc->sCmn.indices.signalType >> 1 ][ psEnc->sCmn.indices.quantOffsetType ]; + psEncCtrl->Lambda_Q10 = SILK_FIX_CONST( LAMBDA_OFFSET, 10 ) + + silk_SMULBB( SILK_FIX_CONST( LAMBDA_DELAYED_DECISIONS, 10 ), psEnc->sCmn.nStatesDelayedDecision ) + + silk_SMULWB( SILK_FIX_CONST( LAMBDA_SPEECH_ACT, 18 ), psEnc->sCmn.speech_activity_Q8 ) + + silk_SMULWB( SILK_FIX_CONST( LAMBDA_INPUT_QUALITY, 12 ), psEncCtrl->input_quality_Q14 ) + + silk_SMULWB( SILK_FIX_CONST( LAMBDA_CODING_QUALITY, 12 ), psEncCtrl->coding_quality_Q14 ) + + silk_SMULWB( SILK_FIX_CONST( LAMBDA_QUANT_OFFSET, 16 ), quant_offset_Q10 ); + + silk_assert( psEncCtrl->Lambda_Q10 > 0 ); + silk_assert( psEncCtrl->Lambda_Q10 < SILK_FIX_CONST( 2, 10 ) ); +} diff --git a/code/opus-1.0.2/silk/fixed/regularize_correlations_FIX.c b/code/opus-1.0.2/silk/fixed/regularize_correlations_FIX.c new file mode 100644 index 00000000..098c1509 --- /dev/null +++ b/code/opus-1.0.2/silk/fixed/regularize_correlations_FIX.c @@ -0,0 +1,47 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" + +/* Add noise to matrix diagonal */ +void silk_regularize_correlations_FIX( + opus_int32 *XX, /* I/O Correlation matrices */ + opus_int32 *xx, /* I/O Correlation values */ + opus_int32 noise, /* I Noise to add */ + opus_int D /* I Dimension of XX */ +) +{ + opus_int i; + for( i = 0; i < D; i++ ) { + matrix_ptr( &XX[ 0 ], i, i, D ) = silk_ADD32( matrix_ptr( &XX[ 0 ], i, i, D ), noise ); + } + xx[ 0 ] += noise; +} diff --git a/code/opus-1.0.2/silk/fixed/residual_energy16_FIX.c b/code/opus-1.0.2/silk/fixed/residual_energy16_FIX.c new file mode 100644 index 00000000..d61e8493 --- /dev/null +++ b/code/opus-1.0.2/silk/fixed/residual_energy16_FIX.c @@ -0,0 +1,103 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" + +/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */ +opus_int32 silk_residual_energy16_covar_FIX( + const opus_int16 *c, /* I Prediction vector */ + const opus_int32 *wXX, /* I Correlation matrix */ + const opus_int32 *wXx, /* I Correlation vector */ + opus_int32 wxx, /* I Signal energy */ + opus_int D, /* I Dimension */ + opus_int cQ /* I Q value for c vector 0 - 15 */ +) +{ + opus_int i, j, lshifts, Qxtra; + opus_int32 c_max, w_max, tmp, tmp2, nrg; + opus_int cn[ MAX_MATRIX_SIZE ]; + const opus_int32 *pRow; + + /* Safety checks */ + silk_assert( D >= 0 ); + silk_assert( D <= 16 ); + silk_assert( cQ > 0 ); + silk_assert( cQ < 16 ); + + lshifts = 16 - cQ; + Qxtra = lshifts; + + c_max = 0; + for( i = 0; i < D; i++ ) { + c_max = silk_max_32( c_max, silk_abs( (opus_int32)c[ i ] ) ); + } + Qxtra = silk_min_int( Qxtra, silk_CLZ32( c_max ) - 17 ); + + w_max = silk_max_32( wXX[ 0 ], wXX[ D * D - 1 ] ); + Qxtra = silk_min_int( Qxtra, silk_CLZ32( silk_MUL( D, silk_RSHIFT( silk_SMULWB( w_max, c_max ), 4 ) ) ) - 5 ); + Qxtra = silk_max_int( Qxtra, 0 ); + for( i = 0; i < D; i++ ) { + cn[ i ] = silk_LSHIFT( ( opus_int )c[ i ], Qxtra ); + silk_assert( silk_abs(cn[i]) <= ( silk_int16_MAX + 1 ) ); /* Check that silk_SMLAWB can be used */ + } + lshifts -= Qxtra; + + /* Compute wxx - 2 * wXx * c */ + tmp = 0; + for( i = 0; i < D; i++ ) { + tmp = silk_SMLAWB( tmp, wXx[ i ], cn[ i ] ); + } + nrg = silk_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 = silk_SMLAWB( tmp, pRow[ j ], cn[ j ] ); + } + tmp = silk_SMLAWB( tmp, silk_RSHIFT( pRow[ i ], 1 ), cn[ i ] ); + tmp2 = silk_SMLAWB( tmp2, tmp, cn[ i ] ); + } + nrg = silk_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 > silk_RSHIFT( silk_int32_MAX, lshifts + 2 ) ) { + nrg = silk_int32_MAX >> 1; + } else { + nrg = silk_LSHIFT( nrg, lshifts + 1 ); /* Q0 */ + } + return nrg; + +} diff --git a/code/opus-1.0.2/silk/fixed/residual_energy_FIX.c b/code/opus-1.0.2/silk/fixed/residual_energy_FIX.c new file mode 100644 index 00000000..f284e51f --- /dev/null +++ b/code/opus-1.0.2/silk/fixed/residual_energy_FIX.c @@ -0,0 +1,91 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" + +/* Calculates residual energies of input subframes where all subframes have LPC_order */ +/* of preceding samples */ +void silk_residual_energy_FIX( + opus_int32 nrgs[ MAX_NB_SUBFR ], /* O Residual energy per subframe */ + opus_int nrgsQ[ MAX_NB_SUBFR ], /* O Q value per subframe */ + const opus_int16 x[], /* I Input signal */ + opus_int16 a_Q12[ 2 ][ MAX_LPC_ORDER ], /* I AR coefs for each frame half */ + const opus_int32 gains[ MAX_NB_SUBFR ], /* I Quantization gains */ + const opus_int subfr_length, /* I Subframe length */ + const opus_int nb_subfr, /* I Number of subframes */ + const opus_int LPC_order /* I LPC order */ +) +{ + opus_int offset, i, j, rshift, lz1, lz2; + opus_int16 *LPC_res_ptr, LPC_res[ ( MAX_FRAME_LENGTH + MAX_NB_SUBFR * MAX_LPC_ORDER ) / 2 ]; + const opus_int16 *x_ptr; + opus_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 < nb_subfr >> 1; i++ ) { + /* Calculate half frame LPC residual signal including preceding samples */ + silk_LPC_analysis_filter( LPC_res, x_ptr, a_Q12[ i ], ( MAX_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 < ( MAX_NB_SUBFR >> 1 ); j++ ) { + /* Measure subframe energy */ + silk_sum_sqr_shift( &nrgs[ i * ( MAX_NB_SUBFR >> 1 ) + j ], &rshift, LPC_res_ptr, subfr_length ); + + /* Set Q values for the measured energy */ + nrgsQ[ i * ( MAX_NB_SUBFR >> 1 ) + j ] = -rshift; + + /* Move to next subframe */ + LPC_res_ptr += offset; + } + /* Move to next frame half */ + x_ptr += ( MAX_NB_SUBFR >> 1 ) * offset; + } + + /* Apply the squared subframe gains */ + for( i = 0; i < nb_subfr; i++ ) { + /* Fully upscale gains and energies */ + lz1 = silk_CLZ32( nrgs[ i ] ) - 1; + lz2 = silk_CLZ32( gains[ i ] ) - 1; + + tmp32 = silk_LSHIFT32( gains[ i ], lz2 ); + + /* Find squared gains */ + tmp32 = silk_SMMUL( tmp32, tmp32 ); /* Q( 2 * lz2 - 32 )*/ + + /* Scale energies */ + nrgs[ i ] = silk_SMMUL( tmp32, silk_LSHIFT32( nrgs[ i ], lz1 ) ); /* Q( nrgsQ[ i ] + lz1 + 2 * lz2 - 32 - 32 )*/ + nrgsQ[ i ] += lz1 + 2 * lz2 - 32 - 32; + } +} diff --git a/code/opus-1.0.2/silk/fixed/schur64_FIX.c b/code/opus-1.0.2/silk/fixed/schur64_FIX.c new file mode 100644 index 00000000..5ff27567 --- /dev/null +++ b/code/opus-1.0.2/silk/fixed/schur64_FIX.c @@ -0,0 +1,77 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Slower than schur(), but more accurate. */ +/* Uses SMULL(), available on armv4 */ +opus_int32 silk_schur64( /* O returns residual energy */ + opus_int32 rc_Q16[], /* O Reflection coefficients [order] Q16 */ + const opus_int32 c[], /* I Correlations [order+1] */ + opus_int32 order /* I Prediction order */ +) +{ + opus_int k, n; + opus_int32 C[ SILK_MAX_ORDER_LPC + 1 ][ 2 ]; + opus_int32 Ctmp1_Q30, Ctmp2_Q30, rc_tmp_Q31; + + silk_assert( order==6||order==8||order==10||order==12||order==14||order==16 ); + + /* Check for invalid input */ + if( c[ 0 ] <= 0 ) { + silk_memset( rc_Q16, 0, order * sizeof( opus_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 = silk_DIV32_varQ( -C[ k + 1 ][ 0 ], C[ 0 ][ 1 ], 31 ); + + /* Save the output */ + rc_Q16[ k ] = silk_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 + silk_SMMUL( silk_LSHIFT( Ctmp2_Q30, 1 ), rc_tmp_Q31 ); + C[ n ][ 1 ] = Ctmp2_Q30 + silk_SMMUL( silk_LSHIFT( Ctmp1_Q30, 1 ), rc_tmp_Q31 ); + } + } + + return( C[ 0 ][ 1 ] ); +} diff --git a/code/opus-1.0.2/silk/fixed/schur_FIX.c b/code/opus-1.0.2/silk/fixed/schur_FIX.c new file mode 100644 index 00000000..43db5018 --- /dev/null +++ b/code/opus-1.0.2/silk/fixed/schur_FIX.c @@ -0,0 +1,92 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Faster than schur64(), but much less accurate. */ +/* uses SMLAWB(), requiring armv5E and higher. */ +opus_int32 silk_schur( /* O Returns residual energy */ + opus_int16 *rc_Q15, /* O reflection coefficients [order] Q15 */ + const opus_int32 *c, /* I correlations [order+1] */ + const opus_int32 order /* I prediction order */ +) +{ + opus_int k, n, lz; + opus_int32 C[ SILK_MAX_ORDER_LPC + 1 ][ 2 ]; + opus_int32 Ctmp1, Ctmp2, rc_tmp_Q15; + + silk_assert( order==6||order==8||order==10||order==12||order==14||order==16 ); + + /* Get number of leading zeros */ + lz = 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 ] = silk_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 ] = silk_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 = -silk_DIV32_16( C[ k + 1 ][ 0 ], silk_max_32( silk_RSHIFT( C[ 0 ][ 1 ], 15 ), 1 ) ); + + /* Clip (shouldn't happen for properly conditioned inputs) */ + rc_tmp_Q15 = silk_SAT16( rc_tmp_Q15 ); + + /* Store */ + rc_Q15[ k ] = (opus_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 ] = silk_SMLAWB( Ctmp1, silk_LSHIFT( Ctmp2, 1 ), rc_tmp_Q15 ); + C[ n ][ 1 ] = silk_SMLAWB( Ctmp2, silk_LSHIFT( Ctmp1, 1 ), rc_tmp_Q15 ); + } + } + + /* return residual energy */ + return C[ 0 ][ 1 ]; +} diff --git a/code/opus-1.0.2/silk/fixed/solve_LS_FIX.c b/code/opus-1.0.2/silk/fixed/solve_LS_FIX.c new file mode 100644 index 00000000..fb913abe --- /dev/null +++ b/code/opus-1.0.2/silk/fixed/solve_LS_FIX.c @@ -0,0 +1,245 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" +#include "tuning_parameters.h" + +/*****************************/ +/* Internal function headers */ +/*****************************/ + +typedef struct { + opus_int32 Q36_part; + opus_int32 Q48_part; +} inv_D_t; + +/* Factorize square matrix A into LDL form */ +static inline void silk_LDL_factorize_FIX( + opus_int32 *A, /* I/O Pointer to Symetric Square Matrix */ + opus_int M, /* I Size of Matrix */ + opus_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 */ +static inline void silk_LS_SolveFirst_FIX( + const opus_int32 *L_Q16, /* I Pointer to Lower Triangular Matrix */ + opus_int M, /* I Dim of Matrix equation */ + const opus_int32 *b, /* I b Vector */ + opus_int32 *x_Q16 /* O x Vector */ +); + +/* Solve L^t*x = b, where L is lower triangular with ones on the diagonal */ +static inline void silk_LS_SolveLast_FIX( + const opus_int32 *L_Q16, /* I Pointer to Lower Triangular Matrix */ + const opus_int M, /* I Dim of Matrix equation */ + const opus_int32 *b, /* I b Vector */ + opus_int32 *x_Q16 /* O x Vector */ +); + +static inline void silk_LS_divide_Q16_FIX( + opus_int32 T[], /* I/O Numenator vector */ + inv_D_t *inv_D, /* I 1 / D vector */ + opus_int M /* I dimension */ +); + +/* Solves Ax = b, assuming A is symmetric */ +void silk_solve_LDL_FIX( + opus_int32 *A, /* I Pointer to symetric square matrix A */ + opus_int M, /* I Size of matrix */ + const opus_int32 *b, /* I Pointer to b vector */ + opus_int32 *x_Q16 /* O Pointer to x solution vector */ +) +{ + opus_int32 L_Q16[ MAX_MATRIX_SIZE * MAX_MATRIX_SIZE ]; + opus_int32 Y[ MAX_MATRIX_SIZE ]; + inv_D_t inv_D[ MAX_MATRIX_SIZE ]; + + silk_assert( M <= MAX_MATRIX_SIZE ); + + /*************************************************** + Factorize A by LDL such that A = L*D*L', + where L is lower triangular with ones on diagonal + ****************************************************/ + 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 + ******************************************************/ + 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 + ****************************************************/ + silk_LS_divide_Q16_FIX( Y, inv_D, M ); + + /**************************************************** + x = inv(L') * inv(D) * Y + *****************************************************/ + silk_LS_SolveLast_FIX( L_Q16, M, Y, x_Q16 ); +} + +static inline void silk_LDL_factorize_FIX( + opus_int32 *A, /* I/O Pointer to Symetric Square Matrix */ + opus_int M, /* I Size of Matrix */ + opus_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 */ +) +{ + opus_int i, j, k, status, loop_count; + const opus_int32 *ptr1, *ptr2; + opus_int32 diag_min_value, tmp_32, err; + opus_int32 v_Q0[ MAX_MATRIX_SIZE ], D_Q0[ MAX_MATRIX_SIZE ]; + opus_int32 one_div_diag_Q36, one_div_diag_Q40, one_div_diag_Q48; + + silk_assert( M <= MAX_MATRIX_SIZE ); + + status = 1; + diag_min_value = silk_max_32( silk_SMMUL( silk_ADD_SAT32( A[ 0 ], A[ silk_SMULBB( M, M ) - 1 ] ), SILK_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 ] = silk_SMULWW( D_Q0[ i ], ptr1[ i ] ); /* Q0 */ + tmp_32 = silk_SMLAWW( tmp_32, v_Q0[ i ], ptr1[ i ] ); /* Q0 */ + } + tmp_32 = silk_SUB32( matrix_ptr( A, j, j, M ), tmp_32 ); + + if( tmp_32 < diag_min_value ) { + tmp_32 = silk_SUB32( silk_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 ) = silk_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 = silk_INVERSE32_varQ( tmp_32, 36 ); /* Q36 */ + one_div_diag_Q40 = silk_LSHIFT( one_div_diag_Q36, 4 ); /* Q40 */ + err = silk_SUB32( (opus_int32)1 << 24, silk_SMULWW( tmp_32, one_div_diag_Q40 ) ); /* Q24 */ + one_div_diag_Q48 = silk_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 = silk_SMLAWW( tmp_32, v_Q0[ k ], ptr2[ k ] ); /* Q0 */ + } + tmp_32 = silk_SUB32( ptr1[ i ], tmp_32 ); /* always < max(Correlation) */ + + /* tmp_32 / D_Q0[j] : Divide to Q16 */ + matrix_ptr( L_Q16, i, j, M ) = silk_ADD32( silk_SMMUL( tmp_32, one_div_diag_Q48 ), + silk_RSHIFT( silk_SMULWW( tmp_32, one_div_diag_Q36 ), 4 ) ); + + /* go to next column */ + ptr2 += M; + } + } + } + + silk_assert( status == 0 ); +} + +static inline void silk_LS_divide_Q16_FIX( + opus_int32 T[], /* I/O Numenator vector */ + inv_D_t *inv_D, /* I 1 / D vector */ + opus_int M /* I dimension */ +) +{ + opus_int i; + opus_int32 tmp_32; + opus_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 ] = silk_ADD32( silk_SMMUL( tmp_32, one_div_diag_Q48 ), silk_RSHIFT( silk_SMULWW( tmp_32, one_div_diag_Q36 ), 4 ) ); + } +} + +/* Solve Lx = b, when L is lower triangular and has ones on the diagonal */ +static inline void silk_LS_SolveFirst_FIX( + const opus_int32 *L_Q16, /* I Pointer to Lower Triangular Matrix */ + opus_int M, /* I Dim of Matrix equation */ + const opus_int32 *b, /* I b Vector */ + opus_int32 *x_Q16 /* O x Vector */ +) +{ + opus_int i, j; + const opus_int32 *ptr32; + opus_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 = silk_SMLAWW( tmp_32, ptr32[ j ], x_Q16[ j ] ); + } + x_Q16[ i ] = silk_SUB32( b[ i ], tmp_32 ); + } +} + +/* Solve L^t*x = b, where L is lower triangular with ones on the diagonal */ +static inline void silk_LS_SolveLast_FIX( + const opus_int32 *L_Q16, /* I Pointer to Lower Triangular Matrix */ + const opus_int M, /* I Dim of Matrix equation */ + const opus_int32 *b, /* I b Vector */ + opus_int32 *x_Q16 /* O x Vector */ +) +{ + opus_int i, j; + const opus_int32 *ptr32; + opus_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 = silk_SMLAWW( tmp_32, ptr32[ silk_SMULBB( j, M ) ], x_Q16[ j ] ); + } + x_Q16[ i ] = silk_SUB32( b[ i ], tmp_32 ); + } +} diff --git a/code/opus-1.0.2/silk/fixed/structs_FIX.h b/code/opus-1.0.2/silk/fixed/structs_FIX.h new file mode 100644 index 00000000..4162608b --- /dev/null +++ b/code/opus-1.0.2/silk/fixed/structs_FIX.h @@ -0,0 +1,133 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (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 SILK_STRUCTS_FIX_H +#define SILK_STRUCTS_FIX_H + +#include "typedef.h" +#include "main.h" +#include "structs.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************/ +/* Noise shaping analysis state */ +/********************************/ +typedef struct { + opus_int8 LastGainIndex; + opus_int32 HarmBoost_smth_Q16; + opus_int32 HarmShapeGain_smth_Q16; + opus_int32 Tilt_smth_Q16; +} silk_shape_state_FIX; + +/********************************/ +/* Prefilter state */ +/********************************/ +typedef struct { + opus_int16 sLTP_shp[ LTP_BUF_LENGTH ]; + opus_int32 sAR_shp[ MAX_SHAPE_LPC_ORDER + 1 ]; + opus_int sLTP_shp_buf_idx; + opus_int32 sLF_AR_shp_Q12; + opus_int32 sLF_MA_shp_Q12; + opus_int32 sHarmHP_Q2; + opus_int32 rand_seed; + opus_int lagPrev; +} silk_prefilter_state_FIX; + +/********************************/ +/* Encoder state FIX */ +/********************************/ +typedef struct { + silk_encoder_state sCmn; /* Common struct, shared with floating-point code */ + silk_shape_state_FIX sShape; /* Shape state */ + silk_prefilter_state_FIX sPrefilt; /* Prefilter State */ + + /* Buffer for find pitch and noise shape analysis */ + silk_DWORD_ALIGN opus_int16 x_buf[ 2 * MAX_FRAME_LENGTH + LA_SHAPE_MAX ];/* Buffer for find pitch and noise shape analysis */ + opus_int LTPCorr_Q15; /* Normalized correlation from pitch lag estimator */ +} silk_encoder_state_FIX; + +/************************/ +/* Encoder control FIX */ +/************************/ +typedef struct { + /* Prediction and coding parameters */ + opus_int32 Gains_Q16[ MAX_NB_SUBFR ]; + silk_DWORD_ALIGN opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ]; + opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ]; + opus_int LTP_scale_Q14; + opus_int pitchL[ MAX_NB_SUBFR ]; + + /* Noise shaping parameters */ + /* Testing */ + silk_DWORD_ALIGN opus_int16 AR1_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ]; + silk_DWORD_ALIGN opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ]; + opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ]; /* Packs two int16 coefficients per int32 value */ + opus_int GainsPre_Q14[ MAX_NB_SUBFR ]; + opus_int HarmBoost_Q14[ MAX_NB_SUBFR ]; + opus_int Tilt_Q14[ MAX_NB_SUBFR ]; + opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ]; + opus_int Lambda_Q10; + opus_int input_quality_Q14; + opus_int coding_quality_Q14; + + /* measures */ + opus_int sparseness_Q8; + opus_int32 predGain_Q16; + opus_int LTPredCodGain_Q7; + opus_int32 ResNrg[ MAX_NB_SUBFR ]; /* Residual energy per subframe */ + opus_int ResNrgQ[ MAX_NB_SUBFR ]; /* Q domain for the residual energy > 0 */ + + /* Parameters for CBR mode */ + opus_int32 GainsUnq_Q16[ MAX_NB_SUBFR ]; + opus_int8 lastGainIndexPrev; +} silk_encoder_control_FIX; + +/************************/ +/* Encoder Super Struct */ +/************************/ +typedef struct { + silk_encoder_state_FIX state_Fxx[ ENCODER_NUM_CHANNELS ]; + stereo_enc_state sStereo; + opus_int32 nBitsExceeded; + opus_int nChannelsAPI; + opus_int nChannelsInternal; + opus_int nPrevChannelsInternal; + opus_int timeSinceSwitchAllowed_ms; + opus_int allowBandwidthSwitch; + opus_int prev_decode_only_middle; +} silk_encoder; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/code/opus-1.0.2/silk/fixed/vector_ops_FIX.c b/code/opus-1.0.2/silk/fixed/vector_ops_FIX.c new file mode 100644 index 00000000..d6206024 --- /dev/null +++ b/code/opus-1.0.2/silk/fixed/vector_ops_FIX.c @@ -0,0 +1,127 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Copy and multiply a vector by a constant */ +void silk_scale_copy_vector16( + opus_int16 *data_out, + const opus_int16 *data_in, + opus_int32 gain_Q16, /* I Gain in Q16 */ + const opus_int dataSize /* I Length */ +) +{ + opus_int i; + opus_int32 tmp32; + + for( i = 0; i < dataSize; i++ ) { + tmp32 = silk_SMULWB( gain_Q16, data_in[ i ] ); + data_out[ i ] = (opus_int16)silk_CHECK_FIT16( tmp32 ); + } +} + +/* Multiply a vector by a constant */ +void silk_scale_vector32_Q26_lshift_18( + opus_int32 *data1, /* I/O Q0/Q18 */ + opus_int32 gain_Q26, /* I Q26 */ + opus_int dataSize /* I length */ +) +{ + opus_int i; + + for( i = 0; i < dataSize; i++ ) { + data1[ i ] = (opus_int32)silk_CHECK_FIT32( silk_RSHIFT64( silk_SMULL( data1[ i ], gain_Q26 ), 8 ) ); /* OUTPUT: Q18 */ + } +} + +/* sum = for(i=0;i6, memory access can be reduced by half. */ +opus_int32 silk_inner_prod_aligned( + const opus_int16 *const inVec1, /* I input vector 1 */ + const opus_int16 *const inVec2, /* I input vector 2 */ + const opus_int len /* I vector lengths */ +) +{ + opus_int i; + opus_int32 sum = 0; + for( i = 0; i < len; i++ ) { + sum = silk_SMLABB( sum, inVec1[ i ], inVec2[ i ] ); + } + return sum; +} + +opus_int64 silk_inner_prod16_aligned_64( + const opus_int16 *inVec1, /* I input vector 1 */ + const opus_int16 *inVec2, /* I input vector 2 */ + const opus_int len /* I vector lengths */ +) +{ + opus_int i; + opus_int64 sum = 0; + for( i = 0; i < len; i++ ) { + sum = silk_SMLALBB( sum, inVec1[ i ], inVec2[ i ] ); + } + return sum; +} + +/* Function that returns the maximum absolut value of the input vector */ +opus_int16 silk_int16_array_maxabs( /* O Maximum absolute value, max: 2^15-1 */ + const opus_int16 *vec, /* I Input vector [len] */ + const opus_int32 len /* I Length of input vector */ +) +{ + opus_int32 max = 0, i, lvl = 0, ind; + if( len == 0 ) return 0; + + ind = len - 1; + max = silk_SMULBB( vec[ ind ], vec[ ind ] ); + for( i = len - 2; i >= 0; i-- ) { + lvl = silk_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( silk_int16_MAX ); + } else { + if( vec[ ind ] < 0 ) { + return( -vec[ ind ] ); + } else { + return( vec[ ind ] ); + } + } +} diff --git a/code/opus-1.0.2/silk/fixed/warped_autocorrelation_FIX.c b/code/opus-1.0.2/silk/fixed/warped_autocorrelation_FIX.c new file mode 100644 index 00000000..d7a3944b --- /dev/null +++ b/code/opus-1.0.2/silk/fixed/warped_autocorrelation_FIX.c @@ -0,0 +1,88 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FIX.h" + +#define QC 10 +#define QS 14 + +/* Autocorrelations for a warped frequency axis */ +void silk_warped_autocorrelation_FIX( + opus_int32 *corr, /* O Result [order + 1] */ + opus_int *scale, /* O Scaling of the correlation vector */ + const opus_int16 *input, /* I Input data to correlate */ + const opus_int warping_Q16, /* I Warping coefficient */ + const opus_int length, /* I Length of input */ + const opus_int order /* I Correlation order (even) */ +) +{ + opus_int n, i, lsh; + opus_int32 tmp1_QS, tmp2_QS; + opus_int32 state_QS[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; + opus_int64 corr_QC[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; + + /* Order must be even */ + silk_assert( ( order & 1 ) == 0 ); + silk_assert( 2 * QS - QC >= 0 ); + + /* Loop over samples */ + for( n = 0; n < length; n++ ) { + tmp1_QS = silk_LSHIFT32( (opus_int32)input[ n ], QS ); + /* Loop over allpass sections */ + for( i = 0; i < order; i += 2 ) { + /* Output of allpass section */ + tmp2_QS = silk_SMLAWB( state_QS[ i ], state_QS[ i + 1 ] - tmp1_QS, warping_Q16 ); + state_QS[ i ] = tmp1_QS; + corr_QC[ i ] += silk_RSHIFT64( silk_SMULL( tmp1_QS, state_QS[ 0 ] ), 2 * QS - QC ); + /* Output of allpass section */ + tmp1_QS = silk_SMLAWB( state_QS[ i + 1 ], state_QS[ i + 2 ] - tmp2_QS, warping_Q16 ); + state_QS[ i + 1 ] = tmp2_QS; + corr_QC[ i + 1 ] += silk_RSHIFT64( silk_SMULL( tmp2_QS, state_QS[ 0 ] ), 2 * QS - QC ); + } + state_QS[ order ] = tmp1_QS; + corr_QC[ order ] += silk_RSHIFT64( silk_SMULL( tmp1_QS, state_QS[ 0 ] ), 2 * QS - QC ); + } + + lsh = silk_CLZ64( corr_QC[ 0 ] ) - 35; + lsh = silk_LIMIT( lsh, -12 - QC, 30 - QC ); + *scale = -( QC + lsh ); + silk_assert( *scale >= -30 && *scale <= 12 ); + if( lsh >= 0 ) { + for( i = 0; i < order + 1; i++ ) { + corr[ i ] = (opus_int32)silk_CHECK_FIT32( silk_LSHIFT64( corr_QC[ i ], lsh ) ); + } + } else { + for( i = 0; i < order + 1; i++ ) { + corr[ i ] = (opus_int32)silk_CHECK_FIT32( silk_RSHIFT64( corr_QC[ i ], -lsh ) ); + } + } + silk_assert( corr_QC[ 0 ] >= 0 ); /* If breaking, decrease QC*/ +} diff --git a/code/opus-1.0.2/silk/float/LPC_analysis_filter_FLP.c b/code/opus-1.0.2/silk/float/LPC_analysis_filter_FLP.c new file mode 100644 index 00000000..9845655b --- /dev/null +++ b/code/opus-1.0.2/silk/float/LPC_analysis_filter_FLP.c @@ -0,0 +1,249 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "main_FLP.h" + +/************************************************/ +/* LPC analysis filter */ +/* NB! State is kept internally and the */ +/* filter always starts with zero state */ +/* first Order output samples are set to zero */ +/************************************************/ + +/* 16th order LPC analysis filter, does not write first 16 samples */ +static inline void silk_LPC_analysis_filter16_FLP( + silk_float r_LPC[], /* O LPC residual signal */ + const silk_float PredCoef[], /* I LPC coefficients */ + const silk_float s[], /* I Input signal */ + const opus_int length /* I Length of input signal */ +) +{ + opus_int ix; + silk_float LPC_pred; + const silk_float *s_ptr; + + for( ix = 16; ix < length; ix++ ) { + s_ptr = &s[ix - 1]; + + /* short-term prediction */ + LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] + + s_ptr[ -1 ] * PredCoef[ 1 ] + + s_ptr[ -2 ] * PredCoef[ 2 ] + + s_ptr[ -3 ] * PredCoef[ 3 ] + + s_ptr[ -4 ] * PredCoef[ 4 ] + + s_ptr[ -5 ] * PredCoef[ 5 ] + + s_ptr[ -6 ] * PredCoef[ 6 ] + + s_ptr[ -7 ] * PredCoef[ 7 ] + + s_ptr[ -8 ] * PredCoef[ 8 ] + + s_ptr[ -9 ] * PredCoef[ 9 ] + + s_ptr[ -10 ] * PredCoef[ 10 ] + + s_ptr[ -11 ] * PredCoef[ 11 ] + + s_ptr[ -12 ] * PredCoef[ 12 ] + + s_ptr[ -13 ] * PredCoef[ 13 ] + + s_ptr[ -14 ] * PredCoef[ 14 ] + + s_ptr[ -15 ] * PredCoef[ 15 ]; + + /* prediction error */ + r_LPC[ix] = s_ptr[ 1 ] - LPC_pred; + } +} + +/* 12th order LPC analysis filter, does not write first 12 samples */ +static inline void silk_LPC_analysis_filter12_FLP( + silk_float r_LPC[], /* O LPC residual signal */ + const silk_float PredCoef[], /* I LPC coefficients */ + const silk_float s[], /* I Input signal */ + const opus_int length /* I Length of input signal */ +) +{ + opus_int ix; + silk_float LPC_pred; + const silk_float *s_ptr; + + for( ix = 12; ix < length; ix++ ) { + s_ptr = &s[ix - 1]; + + /* short-term prediction */ + LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] + + s_ptr[ -1 ] * PredCoef[ 1 ] + + s_ptr[ -2 ] * PredCoef[ 2 ] + + s_ptr[ -3 ] * PredCoef[ 3 ] + + s_ptr[ -4 ] * PredCoef[ 4 ] + + s_ptr[ -5 ] * PredCoef[ 5 ] + + s_ptr[ -6 ] * PredCoef[ 6 ] + + s_ptr[ -7 ] * PredCoef[ 7 ] + + s_ptr[ -8 ] * PredCoef[ 8 ] + + s_ptr[ -9 ] * PredCoef[ 9 ] + + s_ptr[ -10 ] * PredCoef[ 10 ] + + s_ptr[ -11 ] * PredCoef[ 11 ]; + + /* prediction error */ + r_LPC[ix] = s_ptr[ 1 ] - LPC_pred; + } +} + +/* 10th order LPC analysis filter, does not write first 10 samples */ +static inline void silk_LPC_analysis_filter10_FLP( + silk_float r_LPC[], /* O LPC residual signal */ + const silk_float PredCoef[], /* I LPC coefficients */ + const silk_float s[], /* I Input signal */ + const opus_int length /* I Length of input signal */ +) +{ + opus_int ix; + silk_float LPC_pred; + const silk_float *s_ptr; + + for( ix = 10; ix < length; ix++ ) { + s_ptr = &s[ix - 1]; + + /* short-term prediction */ + LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] + + s_ptr[ -1 ] * PredCoef[ 1 ] + + s_ptr[ -2 ] * PredCoef[ 2 ] + + s_ptr[ -3 ] * PredCoef[ 3 ] + + s_ptr[ -4 ] * PredCoef[ 4 ] + + s_ptr[ -5 ] * PredCoef[ 5 ] + + s_ptr[ -6 ] * PredCoef[ 6 ] + + s_ptr[ -7 ] * PredCoef[ 7 ] + + s_ptr[ -8 ] * PredCoef[ 8 ] + + s_ptr[ -9 ] * PredCoef[ 9 ]; + + /* prediction error */ + r_LPC[ix] = s_ptr[ 1 ] - LPC_pred; + } +} + +/* 8th order LPC analysis filter, does not write first 8 samples */ +static inline void silk_LPC_analysis_filter8_FLP( + silk_float r_LPC[], /* O LPC residual signal */ + const silk_float PredCoef[], /* I LPC coefficients */ + const silk_float s[], /* I Input signal */ + const opus_int length /* I Length of input signal */ +) +{ + opus_int ix; + silk_float LPC_pred; + const silk_float *s_ptr; + + for( ix = 8; ix < length; ix++ ) { + s_ptr = &s[ix - 1]; + + /* short-term prediction */ + LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] + + s_ptr[ -1 ] * PredCoef[ 1 ] + + s_ptr[ -2 ] * PredCoef[ 2 ] + + s_ptr[ -3 ] * PredCoef[ 3 ] + + s_ptr[ -4 ] * PredCoef[ 4 ] + + s_ptr[ -5 ] * PredCoef[ 5 ] + + s_ptr[ -6 ] * PredCoef[ 6 ] + + s_ptr[ -7 ] * PredCoef[ 7 ]; + + /* prediction error */ + r_LPC[ix] = s_ptr[ 1 ] - LPC_pred; + } +} + +/* 6th order LPC analysis filter, does not write first 6 samples */ +static inline void silk_LPC_analysis_filter6_FLP( + silk_float r_LPC[], /* O LPC residual signal */ + const silk_float PredCoef[], /* I LPC coefficients */ + const silk_float s[], /* I Input signal */ + const opus_int length /* I Length of input signal */ +) +{ + opus_int ix; + silk_float LPC_pred; + const silk_float *s_ptr; + + for( ix = 6; ix < length; ix++ ) { + s_ptr = &s[ix - 1]; + + /* short-term prediction */ + LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] + + s_ptr[ -1 ] * PredCoef[ 1 ] + + s_ptr[ -2 ] * PredCoef[ 2 ] + + s_ptr[ -3 ] * PredCoef[ 3 ] + + s_ptr[ -4 ] * PredCoef[ 4 ] + + s_ptr[ -5 ] * PredCoef[ 5 ]; + + /* prediction error */ + r_LPC[ix] = s_ptr[ 1 ] - LPC_pred; + } +} + +/************************************************/ +/* LPC analysis filter */ +/* NB! State is kept internally and the */ +/* filter always starts with zero state */ +/* first Order output samples are set to zero */ +/************************************************/ +void silk_LPC_analysis_filter_FLP( + silk_float r_LPC[], /* O LPC residual signal */ + const silk_float PredCoef[], /* I LPC coefficients */ + const silk_float s[], /* I Input signal */ + const opus_int length, /* I Length of input signal */ + const opus_int Order /* I LPC order */ +) +{ + silk_assert( Order <= length ); + + switch( Order ) { + case 6: + silk_LPC_analysis_filter6_FLP( r_LPC, PredCoef, s, length ); + break; + + case 8: + silk_LPC_analysis_filter8_FLP( r_LPC, PredCoef, s, length ); + break; + + case 10: + silk_LPC_analysis_filter10_FLP( r_LPC, PredCoef, s, length ); + break; + + case 12: + silk_LPC_analysis_filter12_FLP( r_LPC, PredCoef, s, length ); + break; + + case 16: + silk_LPC_analysis_filter16_FLP( r_LPC, PredCoef, s, length ); + break; + + default: + silk_assert( 0 ); + break; + } + + /* Set first Order output samples to zero */ + silk_memset( r_LPC, 0, Order * sizeof( silk_float ) ); +} + diff --git a/code/opus-1.0.2/silk/float/LPC_inv_pred_gain_FLP.c b/code/opus-1.0.2/silk/float/LPC_inv_pred_gain_FLP.c new file mode 100644 index 00000000..8645f77f --- /dev/null +++ b/code/opus-1.0.2/silk/float/LPC_inv_pred_gain_FLP.c @@ -0,0 +1,76 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "SigProc_FLP.h" + +#define RC_THRESHOLD 0.9999f + +/* compute inverse of LPC prediction gain, and */ +/* test if LPC coefficients are stable (all poles within unit circle) */ +/* this code is based on silk_a2k_FLP() */ +silk_float silk_LPC_inverse_pred_gain_FLP( /* O return inverse prediction gain, energy domain */ + const silk_float *A, /* I prediction coefficients [order] */ + opus_int32 order /* I prediction order */ +) +{ + opus_int k, n; + double invGain, rc, rc_mult1, rc_mult2; + silk_float Atmp[ 2 ][ SILK_MAX_ORDER_LPC ]; + silk_float *Aold, *Anew; + + Anew = Atmp[ order & 1 ]; + silk_memcpy( Anew, A, order * sizeof(silk_float) ); + + invGain = 1.0; + for( k = order - 1; k > 0; k-- ) { + rc = -Anew[ k ]; + if( rc > RC_THRESHOLD || rc < -RC_THRESHOLD ) { + return 0.0f; + } + rc_mult1 = 1.0f - rc * rc; + rc_mult2 = 1.0f / rc_mult1; + invGain *= rc_mult1; + /* swap pointers */ + Aold = Anew; + Anew = Atmp[ k & 1 ]; + for( n = 0; n < k; n++ ) { + Anew[ n ] = (silk_float)( ( Aold[ n ] - Aold[ k - n - 1 ] * rc ) * rc_mult2 ); + } + } + rc = -Anew[ 0 ]; + if( rc > RC_THRESHOLD || rc < -RC_THRESHOLD ) { + return 0.0f; + } + rc_mult1 = 1.0f - rc * rc; + invGain *= rc_mult1; + return (silk_float)invGain; +} diff --git a/code/opus-1.0.2/silk/float/LTP_analysis_filter_FLP.c b/code/opus-1.0.2/silk/float/LTP_analysis_filter_FLP.c new file mode 100644 index 00000000..d3a6a5ae --- /dev/null +++ b/code/opus-1.0.2/silk/float/LTP_analysis_filter_FLP.c @@ -0,0 +1,75 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" + +void silk_LTP_analysis_filter_FLP( + silk_float *LTP_res, /* O LTP res MAX_NB_SUBFR*(pre_lgth+subfr_lngth) */ + const silk_float *x, /* I Input signal, with preceding samples */ + const silk_float B[ LTP_ORDER * MAX_NB_SUBFR ], /* I LTP coefficients for each subframe */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const silk_float invGains[ MAX_NB_SUBFR ], /* I Inverse quantization gains */ + const opus_int subfr_length, /* I Length of each subframe */ + const opus_int nb_subfr, /* I number of subframes */ + const opus_int pre_length /* I Preceding samples for each subframe */ +) +{ + const silk_float *x_ptr, *x_lag_ptr; + silk_float Btmp[ LTP_ORDER ]; + silk_float *LTP_res_ptr; + silk_float inv_gain; + opus_int k, i, j; + + x_ptr = x; + LTP_res_ptr = LTP_res; + for( k = 0; k < nb_subfr; k++ ) { + x_lag_ptr = x_ptr - pitchL[ k ]; + inv_gain = invGains[ k ]; + for( i = 0; i < LTP_ORDER; i++ ) { + Btmp[ i ] = B[ k * LTP_ORDER + i ]; + } + + /* LTP analysis FIR filter */ + for( i = 0; i < subfr_length + pre_length; i++ ) { + LTP_res_ptr[ i ] = x_ptr[ i ]; + /* Subtract long-term prediction */ + for( j = 0; j < LTP_ORDER; j++ ) { + LTP_res_ptr[ i ] -= Btmp[ j ] * x_lag_ptr[ LTP_ORDER / 2 - j ]; + } + LTP_res_ptr[ i ] *= inv_gain; + x_lag_ptr++; + } + + /* Update pointers */ + LTP_res_ptr += subfr_length + pre_length; + x_ptr += subfr_length; + } +} diff --git a/code/opus-1.0.2/silk/float/LTP_scale_ctrl_FLP.c b/code/opus-1.0.2/silk/float/LTP_scale_ctrl_FLP.c new file mode 100644 index 00000000..f3f0c572 --- /dev/null +++ b/code/opus-1.0.2/silk/float/LTP_scale_ctrl_FLP.c @@ -0,0 +1,52 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" + +void silk_LTP_scale_ctrl_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + opus_int round_loss; + + if( condCoding == CODE_INDEPENDENTLY ) { + /* Only scale if first frame in packet */ + round_loss = psEnc->sCmn.PacketLoss_perc + psEnc->sCmn.nFramesPerPacket; + psEnc->sCmn.indices.LTP_scaleIndex = (opus_int8)silk_LIMIT( round_loss * psEncCtrl->LTPredCodGain * 0.1f, 0.0f, 2.0f ); + } else { + /* Default is minimum scaling */ + psEnc->sCmn.indices.LTP_scaleIndex = 0; + } + + psEncCtrl->LTP_scale = (silk_float)silk_LTPScales_table_Q14[ psEnc->sCmn.indices.LTP_scaleIndex ] / 16384.0f; +} diff --git a/code/opus-1.0.2/silk/float/SigProc_FLP.h b/code/opus-1.0.2/silk/float/SigProc_FLP.h new file mode 100644 index 00000000..036b46da --- /dev/null +++ b/code/opus-1.0.2/silk/float/SigProc_FLP.h @@ -0,0 +1,203 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (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 SILK_SIGPROC_FLP_H +#define SILK_SIGPROC_FLP_H + +#include "SigProc_FIX.h" +#include "float_cast.h" +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************************************************/ +/* SIGNAL PROCESSING FUNCTIONS */ +/********************************************************************/ + +/* Chirp (bw expand) LP AR filter */ +void silk_bwexpander_FLP( + silk_float *ar, /* I/O AR filter to be expanded (without leading 1) */ + const opus_int d, /* I length of ar */ + const silk_float chirp /* I chirp factor (typically in range (0..1) ) */ +); + +/* compute inverse of LPC prediction gain, and */ +/* test if LPC coefficients are stable (all poles within unit circle) */ +/* this code is based on silk_FLP_a2k() */ +silk_float silk_LPC_inverse_pred_gain_FLP( /* O return inverse prediction gain, energy domain */ + const silk_float *A, /* I prediction coefficients [order] */ + opus_int32 order /* I prediction order */ +); + +silk_float silk_schur_FLP( /* O returns residual energy */ + silk_float refl_coef[], /* O reflection coefficients (length order) */ + const silk_float auto_corr[], /* I autocorrelation sequence (length order+1) */ + opus_int order /* I order */ +); + +void silk_k2a_FLP( + silk_float *A, /* O prediction coefficients [order] */ + const silk_float *rc, /* I reflection coefficients [order] */ + opus_int32 order /* I prediction order */ +); + +/* Solve the normal equations using the Levinson-Durbin recursion */ +silk_float silk_levinsondurbin_FLP( /* O prediction error energy */ + silk_float A[], /* O prediction coefficients [order] */ + const silk_float corr[], /* I input auto-correlations [order + 1] */ + const opus_int order /* I prediction order */ +); + +/* compute autocorrelation */ +void silk_autocorrelation_FLP( + silk_float *results, /* O result (length correlationCount) */ + const silk_float *inputData, /* I input data to correlate */ + opus_int inputDataSize, /* I length of input */ + opus_int correlationCount /* I number of correlation taps to compute */ +); + +opus_int silk_pitch_analysis_core_FLP( /* O Voicing estimate: 0 voiced, 1 unvoiced */ + const silk_float *frame, /* I Signal of length PE_FRAME_LENGTH_MS*Fs_kHz */ + opus_int *pitch_out, /* O Pitch lag values [nb_subfr] */ + opus_int16 *lagIndex, /* O Lag Index */ + opus_int8 *contourIndex, /* O Pitch contour Index */ + silk_float *LTPCorr, /* I/O Normalized correlation; input: value from previous frame */ + opus_int prevLag, /* I Last lag of previous frame; set to zero is unvoiced */ + const silk_float search_thres1, /* I First stage threshold for lag candidates 0 - 1 */ + const silk_float search_thres2, /* I Final threshold for lag candidates 0 - 1 */ + const opus_int Fs_kHz, /* I sample frequency (kHz) */ + const opus_int complexity, /* I Complexity setting, 0-2, where 2 is highest */ + const opus_int nb_subfr /* I Number of 5 ms subframes */ +); + +void silk_insertion_sort_decreasing_FLP( + silk_float *a, /* I/O Unsorted / Sorted vector */ + opus_int *idx, /* O Index vector for the sorted elements */ + const opus_int L, /* I Vector length */ + const opus_int K /* I Number of correctly sorted positions */ +); + +/* Compute reflection coefficients from input signal */ +silk_float silk_burg_modified_FLP( /* O returns residual energy */ + silk_float A[], /* O prediction coefficients (length order) */ + const silk_float x[], /* I input signal, length: nb_subfr*(D+L_sub) */ + const silk_float minInvGain, /* I minimum inverse prediction gain */ + const opus_int subfr_length, /* I input signal subframe length (incl. D preceding samples) */ + const opus_int nb_subfr, /* I number of subframes stacked in x */ + const opus_int D /* I order */ +); + +/* multiply a vector by a constant */ +void silk_scale_vector_FLP( + silk_float *data1, + silk_float gain, + opus_int dataSize +); + +/* copy and multiply a vector by a constant */ +void silk_scale_copy_vector_FLP( + silk_float *data_out, + const silk_float *data_in, + silk_float gain, + opus_int dataSize +); + +/* inner product of two silk_float arrays, with result as double */ +double silk_inner_product_FLP( + const silk_float *data1, + const silk_float *data2, + opus_int dataSize +); + +/* sum of squares of a silk_float array, with result as double */ +double silk_energy_FLP( + const silk_float *data, + opus_int dataSize +); + +/********************************************************************/ +/* MACROS */ +/********************************************************************/ + +#define PI (3.1415926536f) + +#define silk_min_float( a, b ) (((a) < (b)) ? (a) : (b)) +#define silk_max_float( a, b ) (((a) > (b)) ? (a) : (b)) +#define silk_abs_float( a ) ((silk_float)fabs(a)) + +/* sigmoid function */ +static inline silk_float silk_sigmoid( silk_float x ) +{ + return (silk_float)(1.0 / (1.0 + exp(-x))); +} + +/* floating-point to integer conversion (rounding) */ +static inline opus_int32 silk_float2int( silk_float x ) +{ + return (opus_int32)float2int( x ); +} + +/* floating-point to integer conversion (rounding) */ +static inline void silk_float2short_array( + opus_int16 *out, + const silk_float *in, + opus_int32 length +) +{ + opus_int32 k; + for( k = length - 1; k >= 0; k-- ) { + out[k] = silk_SAT16( (opus_int32)float2int( in[k] ) ); + } +} + +/* integer to floating-point conversion */ +static inline void silk_short2float_array( + silk_float *out, + const opus_int16 *in, + opus_int32 length +) +{ + opus_int32 k; + for( k = length - 1; k >= 0; k-- ) { + out[k] = (silk_float)in[k]; + } +} + +/* using log2() helps the fixed-point conversion */ +static inline silk_float silk_log2( double x ) +{ + return ( silk_float )( 3.32192809488736 * log10( x ) ); +} + +#ifdef __cplusplus +} +#endif + +#endif /* SILK_SIGPROC_FLP_H */ diff --git a/code/opus-1.0.2/silk/float/apply_sine_window_FLP.c b/code/opus-1.0.2/silk/float/apply_sine_window_FLP.c new file mode 100644 index 00000000..e06333f7 --- /dev/null +++ b/code/opus-1.0.2/silk/float/apply_sine_window_FLP.c @@ -0,0 +1,81 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" + +/* Apply sine window to signal vector */ +/* Window types: */ +/* 1 -> sine window from 0 to pi/2 */ +/* 2 -> sine window from pi/2 to pi */ +void silk_apply_sine_window_FLP( + silk_float px_win[], /* O Pointer to windowed signal */ + const silk_float px[], /* I Pointer to input signal */ + const opus_int win_type, /* I Selects a window type */ + const opus_int length /* I Window length, multiple of 4 */ +) +{ + opus_int k; + silk_float freq, c, S0, S1; + + silk_assert( win_type == 1 || win_type == 2 ); + + /* Length must be multiple of 4 */ + silk_assert( ( length & 3 ) == 0 ); + + freq = PI / ( length + 1 ); + + /* Approximation of 2 * cos(f) */ + c = 2.0f - freq * freq; + + /* Initialize state */ + if( win_type < 2 ) { + /* Start from 0 */ + S0 = 0.0f; + /* Approximation of sin(f) */ + S1 = freq; + } else { + /* Start from 1 */ + S0 = 1.0f; + /* Approximation of cos(f) */ + S1 = 0.5f * c; + } + + /* Uses the recursive equation: sin(n*f) = 2 * cos(f) * sin((n-1)*f) - sin((n-2)*f) */ + /* 4 samples at a time */ + for( k = 0; k < length; k += 4 ) { + px_win[ k + 0 ] = px[ k + 0 ] * 0.5f * ( S0 + S1 ); + px_win[ k + 1 ] = px[ k + 1 ] * S1; + S0 = c * S1 - S0; + px_win[ k + 2 ] = px[ k + 2 ] * 0.5f * ( S1 + S0 ); + px_win[ k + 3 ] = px[ k + 3 ] * S0; + S1 = c * S0 - S1; + } +} diff --git a/code/opus-1.0.2/silk/float/autocorrelation_FLP.c b/code/opus-1.0.2/silk/float/autocorrelation_FLP.c new file mode 100644 index 00000000..9ce709e2 --- /dev/null +++ b/code/opus-1.0.2/silk/float/autocorrelation_FLP.c @@ -0,0 +1,52 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "typedef.h" +#include "SigProc_FLP.h" + +/* compute autocorrelation */ +void silk_autocorrelation_FLP( + silk_float *results, /* O result (length correlationCount) */ + const silk_float *inputData, /* I input data to correlate */ + opus_int inputDataSize, /* I length of input */ + opus_int correlationCount /* I number of correlation taps to compute */ +) +{ + opus_int i; + + if( correlationCount > inputDataSize ) { + correlationCount = inputDataSize; + } + + for( i = 0; i < correlationCount; i++ ) { + results[ i ] = (silk_float)silk_inner_product_FLP( inputData, inputData + i, inputDataSize - i ); + } +} diff --git a/code/opus-1.0.2/silk/float/burg_modified_FLP.c b/code/opus-1.0.2/silk/float/burg_modified_FLP.c new file mode 100644 index 00000000..31c9b228 --- /dev/null +++ b/code/opus-1.0.2/silk/float/burg_modified_FLP.c @@ -0,0 +1,186 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FLP.h" +#include "tuning_parameters.h" +#include "define.h" + +#define MAX_FRAME_SIZE 384 /* subfr_length * nb_subfr = ( 0.005 * 16000 + 16 ) * 4 = 384*/ + +/* Compute reflection coefficients from input signal */ +silk_float silk_burg_modified_FLP( /* O returns residual energy */ + silk_float A[], /* O prediction coefficients (length order) */ + const silk_float x[], /* I input signal, length: nb_subfr*(D+L_sub) */ + const silk_float minInvGain, /* I minimum inverse prediction gain */ + const opus_int subfr_length, /* I input signal subframe length (incl. D preceding samples) */ + const opus_int nb_subfr, /* I number of subframes stacked in x */ + const opus_int D /* I order */ +) +{ + opus_int k, n, s, reached_max_gain; + double C0, invGain, num, nrg_f, nrg_b, rc, Atmp, tmp1, tmp2; + const silk_float *x_ptr; + double C_first_row[ SILK_MAX_ORDER_LPC ], C_last_row[ SILK_MAX_ORDER_LPC ]; + double CAf[ SILK_MAX_ORDER_LPC + 1 ], CAb[ SILK_MAX_ORDER_LPC + 1 ]; + double Af[ SILK_MAX_ORDER_LPC ]; + + silk_assert( subfr_length * nb_subfr <= MAX_FRAME_SIZE ); + + /* Compute autocorrelations, added over subframes */ + C0 = silk_energy_FLP( x, nb_subfr * subfr_length ); + silk_memset( C_first_row, 0, SILK_MAX_ORDER_LPC * sizeof( double ) ); + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + for( n = 1; n < D + 1; n++ ) { + C_first_row[ n - 1 ] += silk_inner_product_FLP( x_ptr, x_ptr + n, subfr_length - n ); + } + } + silk_memcpy( C_last_row, C_first_row, SILK_MAX_ORDER_LPC * sizeof( double ) ); + + /* Initialize */ + CAb[ 0 ] = CAf[ 0 ] = C0 + FIND_LPC_COND_FAC * C0 + 1e-9f; + invGain = 1.0f; + reached_max_gain = 0; + for( n = 0; n < D; n++ ) { + /* Update first row of correlation matrix (without first element) */ + /* Update last row of correlation matrix (without last element, stored in reversed order) */ + /* Update C * Af */ + /* Update C * flipud(Af) (stored in reversed order) */ + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + tmp1 = x_ptr[ n ]; + tmp2 = x_ptr[ subfr_length - n - 1 ]; + for( k = 0; k < n; k++ ) { + C_first_row[ k ] -= x_ptr[ n ] * x_ptr[ n - k - 1 ]; + C_last_row[ k ] -= x_ptr[ subfr_length - n - 1 ] * x_ptr[ subfr_length - n + k ]; + Atmp = Af[ k ]; + tmp1 += x_ptr[ n - k - 1 ] * Atmp; + tmp2 += x_ptr[ subfr_length - n + k ] * Atmp; + } + for( k = 0; k <= n; k++ ) { + CAf[ k ] -= tmp1 * x_ptr[ n - k ]; + CAb[ k ] -= tmp2 * x_ptr[ subfr_length - n + k - 1 ]; + } + } + tmp1 = C_first_row[ n ]; + tmp2 = C_last_row[ n ]; + for( k = 0; k < n; k++ ) { + Atmp = Af[ k ]; + tmp1 += C_last_row[ n - k - 1 ] * Atmp; + tmp2 += C_first_row[ n - k - 1 ] * Atmp; + } + CAf[ n + 1 ] = tmp1; + CAb[ n + 1 ] = tmp2; + + /* Calculate nominator and denominator for the next order reflection (parcor) coefficient */ + num = CAb[ n + 1 ]; + nrg_b = CAb[ 0 ]; + nrg_f = CAf[ 0 ]; + for( k = 0; k < n; k++ ) { + Atmp = Af[ k ]; + num += CAb[ n - k ] * Atmp; + nrg_b += CAb[ k + 1 ] * Atmp; + nrg_f += CAf[ k + 1 ] * Atmp; + } + silk_assert( nrg_f > 0.0 ); + silk_assert( nrg_b > 0.0 ); + + /* Calculate the next order reflection (parcor) coefficient */ + rc = -2.0 * num / ( nrg_f + nrg_b ); + silk_assert( rc > -1.0 && rc < 1.0 ); + + /* Update inverse prediction gain */ + tmp1 = invGain * ( 1.0 - rc * rc ); + if( tmp1 <= minInvGain ) { + /* Max prediction gain exceeded; set reflection coefficient such that max prediction gain is exactly hit */ + rc = sqrt( 1.0 - minInvGain / invGain ); + if( num > 0 ) { + /* Ensure adjusted reflection coefficients has the original sign */ + rc = -rc; + } + invGain = minInvGain; + reached_max_gain = 1; + } else { + invGain = tmp1; + } + + /* Update the AR coefficients */ + for( k = 0; k < (n + 1) >> 1; k++ ) { + tmp1 = Af[ k ]; + tmp2 = Af[ n - k - 1 ]; + Af[ k ] = tmp1 + rc * tmp2; + Af[ n - k - 1 ] = tmp2 + rc * tmp1; + } + Af[ n ] = rc; + + if( reached_max_gain ) { + /* Reached max prediction gain; set remaining coefficients to zero and exit loop */ + for( k = n + 1; k < D; k++ ) { + Af[ k ] = 0.0; + } + break; + } + + /* Update C * Af and C * Ab */ + for( k = 0; k <= n + 1; k++ ) { + tmp1 = CAf[ k ]; + CAf[ k ] += rc * CAb[ n - k + 1 ]; + CAb[ n - k + 1 ] += rc * tmp1; + } + } + + if( reached_max_gain ) { + /* Convert to silk_float */ + for( k = 0; k < D; k++ ) { + A[ k ] = (silk_float)( -Af[ k ] ); + } + /* Subtract energy of preceding samples from C0 */ + for( s = 0; s < nb_subfr; s++ ) { + C0 -= silk_energy_FLP( x + s * subfr_length, D ); + } + /* Approximate residual energy */ + nrg_f = C0 * invGain; + } else { + /* Compute residual energy and store coefficients as silk_float */ + nrg_f = CAf[ 0 ]; + tmp1 = 1.0; + for( k = 0; k < D; k++ ) { + Atmp = Af[ k ]; + nrg_f += CAf[ k + 1 ] * Atmp; + tmp1 += Atmp * Atmp; + A[ k ] = (silk_float)(-Atmp); + } + nrg_f -= FIND_LPC_COND_FAC * C0 * tmp1; + } + + /* Return residual energy */ + return (silk_float)nrg_f; +} diff --git a/code/opus-1.0.2/silk/float/bwexpander_FLP.c b/code/opus-1.0.2/silk/float/bwexpander_FLP.c new file mode 100644 index 00000000..59ca4eaf --- /dev/null +++ b/code/opus-1.0.2/silk/float/bwexpander_FLP.c @@ -0,0 +1,49 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FLP.h" + +/* Chirp (bw expand) LP AR filter */ +void silk_bwexpander_FLP( + silk_float *ar, /* I/O AR filter to be expanded (without leading 1) */ + const opus_int d, /* I length of ar */ + const silk_float chirp /* I chirp factor (typically in range (0..1) ) */ +) +{ + opus_int i; + silk_float cfac = chirp; + + for( i = 0; i < d - 1; i++ ) { + ar[ i ] *= cfac; + cfac *= chirp; + } + ar[ d - 1 ] *= cfac; +} diff --git a/code/opus-1.0.2/silk/float/corrMatrix_FLP.c b/code/opus-1.0.2/silk/float/corrMatrix_FLP.c new file mode 100644 index 00000000..c59f73c3 --- /dev/null +++ b/code/opus-1.0.2/silk/float/corrMatrix_FLP.c @@ -0,0 +1,93 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/********************************************************************** + * Correlation matrix computations for LS estimate. + **********************************************************************/ + +#include "main_FLP.h" + +/* Calculates correlation vector X'*t */ +void silk_corrVector_FLP( + const silk_float *x, /* I x vector [L+order-1] used to create X */ + const silk_float *t, /* I Target vector [L] */ + const opus_int L, /* I Length of vecors */ + const opus_int Order, /* I Max lag for correlation */ + silk_float *Xt /* O X'*t correlation vector [order] */ +) +{ + opus_int lag; + const silk_float *ptr1; + + ptr1 = &x[ Order - 1 ]; /* Points to first sample of column 0 of X: X[:,0] */ + for( lag = 0; lag < Order; lag++ ) { + /* Calculate X[:,lag]'*t */ + Xt[ lag ] = (silk_float)silk_inner_product_FLP( ptr1, t, L ); + ptr1--; /* Next column of X */ + } +} + +/* Calculates correlation matrix X'*X */ +void silk_corrMatrix_FLP( + const silk_float *x, /* I x vector [ L+order-1 ] used to create X */ + const opus_int L, /* I Length of vectors */ + const opus_int Order, /* I Max lag for correlation */ + silk_float *XX /* O X'*X correlation matrix [order x order] */ +) +{ + opus_int j, lag; + double energy; + const silk_float *ptr1, *ptr2; + + ptr1 = &x[ Order - 1 ]; /* First sample of column 0 of X */ + energy = silk_energy_FLP( ptr1, L ); /* X[:,0]'*X[:,0] */ + matrix_ptr( XX, 0, 0, Order ) = ( silk_float )energy; + for( j = 1; j < Order; j++ ) { + /* Calculate X[:,j]'*X[:,j] */ + energy += ptr1[ -j ] * ptr1[ -j ] - ptr1[ L - j ] * ptr1[ L - j ]; + matrix_ptr( XX, j, j, Order ) = ( silk_float )energy; + } + + ptr2 = &x[ Order - 2 ]; /* First sample of column 1 of X */ + for( lag = 1; lag < Order; lag++ ) { + /* Calculate X[:,0]'*X[:,lag] */ + energy = silk_inner_product_FLP( ptr1, ptr2, L ); + matrix_ptr( XX, lag, 0, Order ) = ( silk_float )energy; + matrix_ptr( XX, 0, lag, Order ) = ( silk_float )energy; + /* Calculate X[:,j]'*X[:,j + lag] */ + for( j = 1; j < ( Order - lag ); j++ ) { + energy += ptr1[ -j ] * ptr2[ -j ] - ptr1[ L - j ] * ptr2[ L - j ]; + matrix_ptr( XX, lag + j, j, Order ) = ( silk_float )energy; + matrix_ptr( XX, j, lag + j, Order ) = ( silk_float )energy; + } + ptr2--; /* Next column of X */ + } +} diff --git a/code/opus-1.0.2/silk/float/encode_frame_FLP.c b/code/opus-1.0.2/silk/float/encode_frame_FLP.c new file mode 100644 index 00000000..23260bc7 --- /dev/null +++ b/code/opus-1.0.2/silk/float/encode_frame_FLP.c @@ -0,0 +1,372 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" +#include "tuning_parameters.h" + +/* Low Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode with lower bitrate */ +static inline void silk_LBRR_encode_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + const silk_float xfw[], /* I Input signal */ + opus_int condCoding /* I The type of conditional coding used so far for this frame */ +); + +void silk_encode_do_VAD_FLP( + silk_encoder_state_FLP *psEnc /* I/O Encoder state FLP */ +) +{ + /****************************/ + /* Voice Activity Detection */ + /****************************/ + silk_VAD_GetSA_Q8( &psEnc->sCmn, psEnc->sCmn.inputBuf + 1 ); + + /**************************************************/ + /* Convert speech activity into VAD and DTX flags */ + /**************************************************/ + if( psEnc->sCmn.speech_activity_Q8 < SILK_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 ) ) { + psEnc->sCmn.indices.signalType = TYPE_NO_VOICE_ACTIVITY; + psEnc->sCmn.noSpeechCounter++; + if( psEnc->sCmn.noSpeechCounter < NB_SPEECH_FRAMES_BEFORE_DTX ) { + psEnc->sCmn.inDTX = 0; + } else if( psEnc->sCmn.noSpeechCounter > MAX_CONSECUTIVE_DTX + NB_SPEECH_FRAMES_BEFORE_DTX ) { + psEnc->sCmn.noSpeechCounter = NB_SPEECH_FRAMES_BEFORE_DTX; + psEnc->sCmn.inDTX = 0; + } + psEnc->sCmn.VAD_flags[ psEnc->sCmn.nFramesEncoded ] = 0; + } else { + psEnc->sCmn.noSpeechCounter = 0; + psEnc->sCmn.inDTX = 0; + psEnc->sCmn.indices.signalType = TYPE_UNVOICED; + psEnc->sCmn.VAD_flags[ psEnc->sCmn.nFramesEncoded ] = 1; + } +} + +/****************/ +/* Encode frame */ +/****************/ +opus_int silk_encode_frame_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + opus_int32 *pnBytesOut, /* O Number of payload bytes; */ + ec_enc *psRangeEnc, /* I/O compressor data structure */ + opus_int condCoding, /* I The type of conditional coding to use */ + opus_int maxBits, /* I If > 0: maximum number of output bits */ + opus_int useCBR /* I Flag to force constant-bitrate operation */ +) +{ + silk_encoder_control_FLP sEncCtrl; + opus_int i, iter, maxIter, found_upper, found_lower, ret = 0; + silk_float *x_frame, *res_pitch_frame; + silk_float xfw[ MAX_FRAME_LENGTH ]; + silk_float res_pitch[ 2 * MAX_FRAME_LENGTH + LA_PITCH_MAX ]; + ec_enc sRangeEnc_copy, sRangeEnc_copy2; + silk_nsq_state sNSQ_copy, sNSQ_copy2; + opus_int32 seed_copy, nBits, nBits_lower, nBits_upper, gainMult_lower, gainMult_upper; + opus_int32 gainsID, gainsID_lower, gainsID_upper; + opus_int16 gainMult_Q8; + opus_int16 ec_prevLagIndex_copy; + opus_int ec_prevSignalType_copy; + opus_int8 LastGainIndex_copy2; + opus_int32 pGains_Q16[ MAX_NB_SUBFR ]; + opus_uint8 ec_buf_copy[ 1275 ]; + + /* This is totally unnecessary but many compilers (including gcc) are too dumb to realise it */ + LastGainIndex_copy2 = nBits_lower = nBits_upper = gainMult_lower = gainMult_upper = 0; + + psEnc->sCmn.indices.Seed = psEnc->sCmn.frameCounter++ & 3; + + /**************************************************************/ + /* Set up Input Pointers, and insert frame in input buffer */ + /**************************************************************/ + /* pointers aligned with start of frame to encode */ + x_frame = psEnc->x_buf + psEnc->sCmn.ltp_mem_length; /* start of frame to encode */ + res_pitch_frame = res_pitch + psEnc->sCmn.ltp_mem_length; /* start of pitch LPC residual frame */ + + /***************************************/ + /* Ensure smooth bandwidth transitions */ + /***************************************/ + silk_LP_variable_cutoff( &psEnc->sCmn.sLP, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length ); + + /*******************************************/ + /* Copy new frame to front of input buffer */ + /*******************************************/ + silk_short2float_array( x_frame + LA_SHAPE_MS * psEnc->sCmn.fs_kHz, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length ); + + /* Add tiny signal to avoid high CPU load from denormalized floating point numbers */ + for( i = 0; i < 8; i++ ) { + x_frame[ LA_SHAPE_MS * psEnc->sCmn.fs_kHz + i * ( psEnc->sCmn.frame_length >> 3 ) ] += ( 1 - ( i & 2 ) ) * 1e-6f; + } + + if( !psEnc->sCmn.prefillFlag ) { + /*****************************************/ + /* Find pitch lags, initial LPC analysis */ + /*****************************************/ + silk_find_pitch_lags_FLP( psEnc, &sEncCtrl, res_pitch, x_frame ); + + /************************/ + /* Noise shape analysis */ + /************************/ + silk_noise_shape_analysis_FLP( psEnc, &sEncCtrl, res_pitch_frame, x_frame ); + + /***************************************************/ + /* Find linear prediction coefficients (LPC + LTP) */ + /***************************************************/ + silk_find_pred_coefs_FLP( psEnc, &sEncCtrl, res_pitch, x_frame, condCoding ); + + /****************************************/ + /* Process gains */ + /****************************************/ + silk_process_gains_FLP( psEnc, &sEncCtrl, condCoding ); + + /*****************************************/ + /* Prefiltering for noise shaper */ + /*****************************************/ + silk_prefilter_FLP( psEnc, &sEncCtrl, xfw, x_frame ); + + /****************************************/ + /* Low Bitrate Redundant Encoding */ + /****************************************/ + silk_LBRR_encode_FLP( psEnc, &sEncCtrl, xfw, condCoding ); + + /* Loop over quantizer and entroy coding to control bitrate */ + maxIter = 6; + gainMult_Q8 = SILK_FIX_CONST( 1, 8 ); + found_lower = 0; + found_upper = 0; + gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr ); + gainsID_lower = -1; + gainsID_upper = -1; + /* Copy part of the input state */ + silk_memcpy( &sRangeEnc_copy, psRangeEnc, sizeof( ec_enc ) ); + silk_memcpy( &sNSQ_copy, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) ); + seed_copy = psEnc->sCmn.indices.Seed; + ec_prevLagIndex_copy = psEnc->sCmn.ec_prevLagIndex; + ec_prevSignalType_copy = psEnc->sCmn.ec_prevSignalType; + for( iter = 0; ; iter++ ) { + if( gainsID == gainsID_lower ) { + nBits = nBits_lower; + } else if( gainsID == gainsID_upper ) { + nBits = nBits_upper; + } else { + /* Restore part of the input state */ + if( iter > 0 ) { + silk_memcpy( psRangeEnc, &sRangeEnc_copy, sizeof( ec_enc ) ); + silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy, sizeof( silk_nsq_state ) ); + psEnc->sCmn.indices.Seed = seed_copy; + psEnc->sCmn.ec_prevLagIndex = ec_prevLagIndex_copy; + psEnc->sCmn.ec_prevSignalType = ec_prevSignalType_copy; + } + + /*****************************************/ + /* Noise shaping quantization */ + /*****************************************/ + silk_NSQ_wrapper_FLP( psEnc, &sEncCtrl, &psEnc->sCmn.indices, &psEnc->sCmn.sNSQ, psEnc->sCmn.pulses, xfw ); + + /****************************************/ + /* Encode Parameters */ + /****************************************/ + silk_encode_indices( &psEnc->sCmn, psRangeEnc, psEnc->sCmn.nFramesEncoded, 0, condCoding ); + + /****************************************/ + /* Encode Excitation Signal */ + /****************************************/ + silk_encode_pulses( psRangeEnc, psEnc->sCmn.indices.signalType, psEnc->sCmn.indices.quantOffsetType, + psEnc->sCmn.pulses, psEnc->sCmn.frame_length ); + + nBits = ec_tell( psRangeEnc ); + + if( useCBR == 0 && iter == 0 && nBits <= maxBits ) { + break; + } + } + + if( iter == maxIter ) { + if( found_lower && ( gainsID == gainsID_lower || nBits > maxBits ) ) { + /* Restore output state from earlier iteration that did meet the bitrate budget */ + silk_memcpy( psRangeEnc, &sRangeEnc_copy2, sizeof( ec_enc ) ); + silk_assert( sRangeEnc_copy2.offs <= 1275 ); + silk_memcpy( psRangeEnc->buf, ec_buf_copy, sRangeEnc_copy2.offs ); + silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy2, sizeof( silk_nsq_state ) ); + psEnc->sShape.LastGainIndex = LastGainIndex_copy2; + } + break; + } + + if( nBits > maxBits ) { + if( found_lower == 0 && iter >= 2 ) { + /* Adjust the quantizer's rate/distortion tradeoff and discard previous "upper" results */ + sEncCtrl.Lambda *= 1.5f; + found_upper = 0; + gainsID_upper = -1; + } else { + found_upper = 1; + nBits_upper = nBits; + gainMult_upper = gainMult_Q8; + gainsID_upper = gainsID; + } + } else if( nBits < maxBits - 5 ) { + found_lower = 1; + nBits_lower = nBits; + gainMult_lower = gainMult_Q8; + if( gainsID != gainsID_lower ) { + gainsID_lower = gainsID; + /* Copy part of the output state */ + silk_memcpy( &sRangeEnc_copy2, psRangeEnc, sizeof( ec_enc ) ); + silk_assert( psRangeEnc->offs <= 1275 ); + silk_memcpy( ec_buf_copy, psRangeEnc->buf, psRangeEnc->offs ); + silk_memcpy( &sNSQ_copy2, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) ); + LastGainIndex_copy2 = psEnc->sShape.LastGainIndex; + } + } else { + /* Within 5 bits of budget: close enough */ + break; + } + + if( ( found_lower & found_upper ) == 0 ) { + /* Adjust gain according to high-rate rate/distortion curve */ + opus_int32 gain_factor_Q16; + gain_factor_Q16 = silk_log2lin( silk_LSHIFT( nBits - maxBits, 7 ) / psEnc->sCmn.frame_length + SILK_FIX_CONST( 16, 7 ) ); + gain_factor_Q16 = silk_min_32( gain_factor_Q16, SILK_FIX_CONST( 2, 16 ) ); + if( nBits > maxBits ) { + gain_factor_Q16 = silk_max_32( gain_factor_Q16, SILK_FIX_CONST( 1.3, 16 ) ); + } + gainMult_Q8 = silk_SMULWB( gain_factor_Q16, gainMult_Q8 ); + } else { + /* Adjust gain by interpolating */ + gainMult_Q8 = gainMult_lower + ( ( gainMult_upper - gainMult_lower ) * ( maxBits - nBits_lower ) ) / ( nBits_upper - nBits_lower ); + /* New gain multplier must be between 25% and 75% of old range (note that gainMult_upper < gainMult_lower) */ + if( gainMult_Q8 > silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 ) ) { + gainMult_Q8 = silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 ); + } else + if( gainMult_Q8 < silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 ) ) { + gainMult_Q8 = silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 ); + } + } + + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + pGains_Q16[ i ] = silk_LSHIFT_SAT32( silk_SMULWB( sEncCtrl.GainsUnq_Q16[ i ], gainMult_Q8 ), 8 ); + } + + /* Quantize gains */ + psEnc->sShape.LastGainIndex = sEncCtrl.lastGainIndexPrev; + silk_gains_quant( psEnc->sCmn.indices.GainsIndices, pGains_Q16, + &psEnc->sShape.LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr ); + + /* Unique identifier of gains vector */ + gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr ); + + /* Overwrite unquantized gains with quantized gains and convert back to Q0 from Q16 */ + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + sEncCtrl.Gains[ i ] = pGains_Q16[ i ] / 65536.0f; + } + } + } + + /* Update input buffer */ + silk_memmove( psEnc->x_buf, &psEnc->x_buf[ psEnc->sCmn.frame_length ], + ( psEnc->sCmn.ltp_mem_length + LA_SHAPE_MS * psEnc->sCmn.fs_kHz ) * sizeof( silk_float ) ); + + /* Parameters needed for next frame */ + psEnc->sCmn.prevLag = sEncCtrl.pitchL[ psEnc->sCmn.nb_subfr - 1 ]; + psEnc->sCmn.prevSignalType = psEnc->sCmn.indices.signalType; + + /* Exit without entropy coding */ + if( psEnc->sCmn.prefillFlag ) { + /* No payload */ + *pnBytesOut = 0; + return ret; + } + + /****************************************/ + /* Finalize payload */ + /****************************************/ + psEnc->sCmn.first_frame_after_reset = 0; + /* Payload size */ + *pnBytesOut = silk_RSHIFT( ec_tell( psRangeEnc ) + 7, 3 ); + + return ret; +} + +/* Low-Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode excitation at lower bitrate */ +static inline void silk_LBRR_encode_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + const silk_float xfw[], /* I Input signal */ + opus_int condCoding /* I The type of conditional coding used so far for this frame */ +) +{ + opus_int k; + opus_int32 Gains_Q16[ MAX_NB_SUBFR ]; + silk_float TempGains[ MAX_NB_SUBFR ]; + SideInfoIndices *psIndices_LBRR = &psEnc->sCmn.indices_LBRR[ psEnc->sCmn.nFramesEncoded ]; + silk_nsq_state sNSQ_LBRR; + + /*******************************************/ + /* Control use of inband LBRR */ + /*******************************************/ + if( psEnc->sCmn.LBRR_enabled && psEnc->sCmn.speech_activity_Q8 > SILK_FIX_CONST( LBRR_SPEECH_ACTIVITY_THRES, 8 ) ) { + psEnc->sCmn.LBRR_flags[ psEnc->sCmn.nFramesEncoded ] = 1; + + /* Copy noise shaping quantizer state and quantization indices from regular encoding */ + silk_memcpy( &sNSQ_LBRR, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) ); + silk_memcpy( psIndices_LBRR, &psEnc->sCmn.indices, sizeof( SideInfoIndices ) ); + + /* Save original gains */ + silk_memcpy( TempGains, psEncCtrl->Gains, psEnc->sCmn.nb_subfr * sizeof( silk_float ) ); + + if( psEnc->sCmn.nFramesEncoded == 0 || psEnc->sCmn.LBRR_flags[ psEnc->sCmn.nFramesEncoded - 1 ] == 0 ) { + /* First frame in packet or previous frame not LBRR coded */ + psEnc->sCmn.LBRRprevLastGainIndex = psEnc->sShape.LastGainIndex; + + /* Increase Gains to get target LBRR rate */ + psIndices_LBRR->GainsIndices[ 0 ] += psEnc->sCmn.LBRR_GainIncreases; + psIndices_LBRR->GainsIndices[ 0 ] = silk_min_int( psIndices_LBRR->GainsIndices[ 0 ], N_LEVELS_QGAIN - 1 ); + } + + /* Decode to get gains in sync with decoder */ + silk_gains_dequant( Gains_Q16, psIndices_LBRR->GainsIndices, + &psEnc->sCmn.LBRRprevLastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr ); + + /* Overwrite unquantized gains with quantized gains and convert back to Q0 from Q16 */ + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->Gains[ k ] = Gains_Q16[ k ] * ( 1.0f / 65536.0f ); + } + + /*****************************************/ + /* Noise shaping quantization */ + /*****************************************/ + silk_NSQ_wrapper_FLP( psEnc, psEncCtrl, psIndices_LBRR, &sNSQ_LBRR, + psEnc->sCmn.pulses_LBRR[ psEnc->sCmn.nFramesEncoded ], xfw ); + + /* Restore original gains */ + silk_memcpy( psEncCtrl->Gains, TempGains, psEnc->sCmn.nb_subfr * sizeof( silk_float ) ); + } +} diff --git a/code/opus-1.0.2/silk/float/energy_FLP.c b/code/opus-1.0.2/silk/float/energy_FLP.c new file mode 100644 index 00000000..e3eedf97 --- /dev/null +++ b/code/opus-1.0.2/silk/float/energy_FLP.c @@ -0,0 +1,60 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FLP.h" + +/* sum of squares of a silk_float array, with result as double */ +double silk_energy_FLP( + const silk_float *data, + opus_int dataSize +) +{ + opus_int i, dataSize4; + double result; + + /* 4x unrolled loop */ + result = 0.0; + dataSize4 = dataSize & 0xFFFC; + for( i = 0; i < dataSize4; i += 4 ) { + result += data[ i + 0 ] * (double)data[ i + 0 ] + + data[ i + 1 ] * (double)data[ i + 1 ] + + data[ i + 2 ] * (double)data[ i + 2 ] + + data[ i + 3 ] * (double)data[ i + 3 ]; + } + + /* add any remaining products */ + for( ; i < dataSize; i++ ) { + result += data[ i ] * (double)data[ i ]; + } + + silk_assert( result >= 0.0 ); + return result; +} diff --git a/code/opus-1.0.2/silk/float/find_LPC_FLP.c b/code/opus-1.0.2/silk/float/find_LPC_FLP.c new file mode 100644 index 00000000..66fa7dd4 --- /dev/null +++ b/code/opus-1.0.2/silk/float/find_LPC_FLP.c @@ -0,0 +1,104 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "define.h" +#include "main_FLP.h" +#include "tuning_parameters.h" + +/* LPC analysis */ +void silk_find_LPC_FLP( + silk_encoder_state *psEncC, /* I/O Encoder state */ + opus_int16 NLSF_Q15[], /* O NLSFs */ + const silk_float x[], /* I Input signal */ + const silk_float minInvGain /* I Inverse of max prediction gain */ +) +{ + opus_int k, subfr_length; + silk_float a[ MAX_LPC_ORDER ]; + + /* Used only for NLSF interpolation */ + silk_float res_nrg, res_nrg_2nd, res_nrg_interp; + opus_int16 NLSF0_Q15[ MAX_LPC_ORDER ]; + silk_float a_tmp[ MAX_LPC_ORDER ]; + silk_float LPC_res[ MAX_FRAME_LENGTH + MAX_NB_SUBFR * MAX_LPC_ORDER ]; + + subfr_length = psEncC->subfr_length + psEncC->predictLPCOrder; + + /* Default: No interpolation */ + psEncC->indices.NLSFInterpCoef_Q2 = 4; + + /* Burg AR analysis for the full frame */ + res_nrg = silk_burg_modified_FLP( a, x, minInvGain, subfr_length, psEncC->nb_subfr, psEncC->predictLPCOrder ); + + if( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) { + /* Optimal solution for last 10 ms; subtract residual energy here, as that's easier than */ + /* adding it to the residual energy of the first 10 ms in each iteration of the search below */ + res_nrg -= silk_burg_modified_FLP( a_tmp, x + ( MAX_NB_SUBFR / 2 ) * subfr_length, minInvGain, subfr_length, MAX_NB_SUBFR / 2, psEncC->predictLPCOrder ); + + /* Convert to NLSFs */ + silk_A2NLSF_FLP( NLSF_Q15, a_tmp, psEncC->predictLPCOrder ); + + /* Search over interpolation indices to find the one with lowest residual energy */ + res_nrg_2nd = silk_float_MAX; + for( k = 3; k >= 0; k-- ) { + /* Interpolate NLSFs for first half */ + silk_interpolate( NLSF0_Q15, psEncC->prev_NLSFq_Q15, NLSF_Q15, k, psEncC->predictLPCOrder ); + + /* Convert to LPC for residual energy evaluation */ + silk_NLSF2A_FLP( a_tmp, NLSF0_Q15, psEncC->predictLPCOrder ); + + /* Calculate residual energy with LSF interpolation */ + silk_LPC_analysis_filter_FLP( LPC_res, a_tmp, x, 2 * subfr_length, psEncC->predictLPCOrder ); + res_nrg_interp = (silk_float)( + silk_energy_FLP( LPC_res + psEncC->predictLPCOrder, subfr_length - psEncC->predictLPCOrder ) + + silk_energy_FLP( LPC_res + psEncC->predictLPCOrder + subfr_length, subfr_length - psEncC->predictLPCOrder ) ); + + /* Determine whether current interpolated NLSFs are best so far */ + if( res_nrg_interp < res_nrg ) { + /* Interpolation has lower residual energy */ + res_nrg = res_nrg_interp; + psEncC->indices.NLSFInterpCoef_Q2 = (opus_int8)k; + } else if( res_nrg_interp > res_nrg_2nd ) { + /* No reason to continue iterating - residual energies will continue to climb */ + break; + } + res_nrg_2nd = res_nrg_interp; + } + } + + if( psEncC->indices.NLSFInterpCoef_Q2 == 4 ) { + /* NLSF interpolation is currently inactive, calculate NLSFs from full frame AR coefficients */ + silk_A2NLSF_FLP( NLSF_Q15, a, psEncC->predictLPCOrder ); + } + + silk_assert( psEncC->indices.NLSFInterpCoef_Q2 == 4 || + ( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) ); +} diff --git a/code/opus-1.0.2/silk/float/find_LTP_FLP.c b/code/opus-1.0.2/silk/float/find_LTP_FLP.c new file mode 100644 index 00000000..0a3c71bb --- /dev/null +++ b/code/opus-1.0.2/silk/float/find_LTP_FLP.c @@ -0,0 +1,132 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" +#include "tuning_parameters.h" + +void silk_find_LTP_FLP( + silk_float b[ MAX_NB_SUBFR * LTP_ORDER ], /* O LTP coefs */ + silk_float WLTP[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Weight for LTP quantization */ + silk_float *LTPredCodGain, /* O LTP coding gain */ + const silk_float r_lpc[], /* I LPC residual */ + const opus_int lag[ MAX_NB_SUBFR ], /* I LTP lags */ + const silk_float Wght[ MAX_NB_SUBFR ], /* I Weights */ + const opus_int subfr_length, /* I Subframe length */ + const opus_int nb_subfr, /* I number of subframes */ + const opus_int mem_offset /* I Number of samples in LTP memory */ +) +{ + opus_int i, k; + silk_float *b_ptr, temp, *WLTP_ptr; + silk_float LPC_res_nrg, LPC_LTP_res_nrg; + silk_float d[ MAX_NB_SUBFR ], m, g, delta_b[ LTP_ORDER ]; + silk_float w[ MAX_NB_SUBFR ], nrg[ MAX_NB_SUBFR ], regu; + silk_float Rr[ LTP_ORDER ], rr[ MAX_NB_SUBFR ]; + const silk_float *r_ptr, *lag_ptr; + + b_ptr = b; + WLTP_ptr = WLTP; + r_ptr = &r_lpc[ mem_offset ]; + for( k = 0; k < nb_subfr; k++ ) { + lag_ptr = r_ptr - ( lag[ k ] + LTP_ORDER / 2 ); + + silk_corrMatrix_FLP( lag_ptr, subfr_length, LTP_ORDER, WLTP_ptr ); + silk_corrVector_FLP( lag_ptr, r_ptr, subfr_length, LTP_ORDER, Rr ); + + rr[ k ] = ( silk_float )silk_energy_FLP( r_ptr, subfr_length ); + regu = 1.0f + rr[ k ] + + matrix_ptr( WLTP_ptr, 0, 0, LTP_ORDER ) + + matrix_ptr( WLTP_ptr, LTP_ORDER-1, LTP_ORDER-1, LTP_ORDER ); + regu *= LTP_DAMPING / 3; + silk_regularize_correlations_FLP( WLTP_ptr, &rr[ k ], regu, LTP_ORDER ); + silk_solve_LDL_FLP( WLTP_ptr, LTP_ORDER, Rr, b_ptr ); + + /* Calculate residual energy */ + nrg[ k ] = silk_residual_energy_covar_FLP( b_ptr, WLTP_ptr, Rr, rr[ k ], LTP_ORDER ); + + temp = Wght[ k ] / ( nrg[ k ] * Wght[ k ] + 0.01f * subfr_length ); + silk_scale_vector_FLP( WLTP_ptr, temp, LTP_ORDER * LTP_ORDER ); + w[ k ] = matrix_ptr( WLTP_ptr, LTP_ORDER / 2, LTP_ORDER / 2, LTP_ORDER ); + + r_ptr += subfr_length; + b_ptr += LTP_ORDER; + WLTP_ptr += LTP_ORDER * LTP_ORDER; + } + + /* Compute LTP coding gain */ + if( LTPredCodGain != NULL ) { + LPC_LTP_res_nrg = 1e-6f; + LPC_res_nrg = 0.0f; + for( k = 0; k < nb_subfr; k++ ) { + LPC_res_nrg += rr[ k ] * Wght[ k ]; + LPC_LTP_res_nrg += nrg[ k ] * Wght[ k ]; + } + + silk_assert( LPC_LTP_res_nrg > 0 ); + *LTPredCodGain = 3.0f * silk_log2( LPC_res_nrg / LPC_LTP_res_nrg ); + } + + /* Smoothing */ + /* d = sum( B, 1 ); */ + b_ptr = b; + for( k = 0; k < nb_subfr; k++ ) { + d[ k ] = 0; + for( i = 0; i < LTP_ORDER; i++ ) { + d[ k ] += b_ptr[ i ]; + } + b_ptr += LTP_ORDER; + } + /* m = ( w * d' ) / ( sum( w ) + 1e-3 ); */ + temp = 1e-3f; + for( k = 0; k < nb_subfr; k++ ) { + temp += w[ k ]; + } + m = 0; + for( k = 0; k < nb_subfr; k++ ) { + m += d[ k ] * w[ k ]; + } + m = m / temp; + + b_ptr = b; + for( k = 0; k < nb_subfr; k++ ) { + g = LTP_SMOOTHING / ( LTP_SMOOTHING + w[ k ] ) * ( m - d[ k ] ); + temp = 0; + for( i = 0; i < LTP_ORDER; i++ ) { + delta_b[ i ] = silk_max_float( b_ptr[ i ], 0.1f ); + temp += delta_b[ i ]; + } + temp = g / temp; + for( i = 0; i < LTP_ORDER; i++ ) { + b_ptr[ i ] = b_ptr[ i ] + delta_b[ i ] * temp; + } + b_ptr += LTP_ORDER; + } +} diff --git a/code/opus-1.0.2/silk/float/find_pitch_lags_FLP.c b/code/opus-1.0.2/silk/float/find_pitch_lags_FLP.c new file mode 100644 index 00000000..00862a6d --- /dev/null +++ b/code/opus-1.0.2/silk/float/find_pitch_lags_FLP.c @@ -0,0 +1,131 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "main_FLP.h" +#include "tuning_parameters.h" + +void silk_find_pitch_lags_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + silk_float res[], /* O Residual */ + const silk_float x[] /* I Speech signal */ +) +{ + opus_int buf_len; + silk_float thrhld, res_nrg; + const silk_float *x_buf_ptr, *x_buf; + silk_float auto_corr[ MAX_FIND_PITCH_LPC_ORDER + 1 ]; + silk_float A[ MAX_FIND_PITCH_LPC_ORDER ]; + silk_float refl_coef[ MAX_FIND_PITCH_LPC_ORDER ]; + silk_float Wsig[ FIND_PITCH_LPC_WIN_MAX ]; + silk_float *Wsig_ptr; + + /******************************************/ + /* Set up buffer lengths etc based on Fs */ + /******************************************/ + buf_len = psEnc->sCmn.la_pitch + psEnc->sCmn.frame_length + psEnc->sCmn.ltp_mem_length; + + /* Safety check */ + silk_assert( buf_len >= psEnc->sCmn.pitch_LPC_win_length ); + + x_buf = x - psEnc->sCmn.ltp_mem_length; + + /******************************************/ + /* Estimate LPC AR coeficients */ + /******************************************/ + + /* Calculate windowed signal */ + + /* First LA_LTP samples */ + x_buf_ptr = x_buf + buf_len - psEnc->sCmn.pitch_LPC_win_length; + Wsig_ptr = Wsig; + silk_apply_sine_window_FLP( Wsig_ptr, x_buf_ptr, 1, psEnc->sCmn.la_pitch ); + + /* Middle non-windowed samples */ + Wsig_ptr += psEnc->sCmn.la_pitch; + x_buf_ptr += psEnc->sCmn.la_pitch; + silk_memcpy( Wsig_ptr, x_buf_ptr, ( psEnc->sCmn.pitch_LPC_win_length - ( psEnc->sCmn.la_pitch << 1 ) ) * sizeof( silk_float ) ); + + /* Last LA_LTP samples */ + Wsig_ptr += psEnc->sCmn.pitch_LPC_win_length - ( psEnc->sCmn.la_pitch << 1 ); + x_buf_ptr += psEnc->sCmn.pitch_LPC_win_length - ( psEnc->sCmn.la_pitch << 1 ); + silk_apply_sine_window_FLP( Wsig_ptr, x_buf_ptr, 2, psEnc->sCmn.la_pitch ); + + /* Calculate autocorrelation sequence */ + silk_autocorrelation_FLP( auto_corr, Wsig, psEnc->sCmn.pitch_LPC_win_length, psEnc->sCmn.pitchEstimationLPCOrder + 1 ); + + /* Add white noise, as a fraction of the energy */ + auto_corr[ 0 ] += auto_corr[ 0 ] * FIND_PITCH_WHITE_NOISE_FRACTION + 1; + + /* Calculate the reflection coefficients using Schur */ + res_nrg = silk_schur_FLP( refl_coef, auto_corr, psEnc->sCmn.pitchEstimationLPCOrder ); + + /* Prediction gain */ + psEncCtrl->predGain = auto_corr[ 0 ] / silk_max_float( res_nrg, 1.0f ); + + /* Convert reflection coefficients to prediction coefficients */ + silk_k2a_FLP( A, refl_coef, psEnc->sCmn.pitchEstimationLPCOrder ); + + /* Bandwidth expansion */ + silk_bwexpander_FLP( A, psEnc->sCmn.pitchEstimationLPCOrder, FIND_PITCH_BANDWIDTH_EXPANSION ); + + /*****************************************/ + /* LPC analysis filtering */ + /*****************************************/ + silk_LPC_analysis_filter_FLP( res, A, x_buf, buf_len, psEnc->sCmn.pitchEstimationLPCOrder ); + + if( psEnc->sCmn.indices.signalType != TYPE_NO_VOICE_ACTIVITY && psEnc->sCmn.first_frame_after_reset == 0 ) { + /* Threshold for pitch estimator */ + thrhld = 0.6f; + thrhld -= 0.004f * psEnc->sCmn.pitchEstimationLPCOrder; + thrhld -= 0.1f * psEnc->sCmn.speech_activity_Q8 * ( 1.0f / 256.0f ); + thrhld -= 0.15f * (psEnc->sCmn.prevSignalType >> 1); + thrhld -= 0.1f * psEnc->sCmn.input_tilt_Q15 * ( 1.0f / 32768.0f ); + + /*****************************************/ + /* Call Pitch estimator */ + /*****************************************/ + if( silk_pitch_analysis_core_FLP( res, psEncCtrl->pitchL, &psEnc->sCmn.indices.lagIndex, + &psEnc->sCmn.indices.contourIndex, &psEnc->LTPCorr, psEnc->sCmn.prevLag, psEnc->sCmn.pitchEstimationThreshold_Q16 / 65536.0f, + thrhld, psEnc->sCmn.fs_kHz, psEnc->sCmn.pitchEstimationComplexity, psEnc->sCmn.nb_subfr ) == 0 ) + { + psEnc->sCmn.indices.signalType = TYPE_VOICED; + } else { + psEnc->sCmn.indices.signalType = TYPE_UNVOICED; + } + } else { + silk_memset( psEncCtrl->pitchL, 0, sizeof( psEncCtrl->pitchL ) ); + psEnc->sCmn.indices.lagIndex = 0; + psEnc->sCmn.indices.contourIndex = 0; + psEnc->LTPCorr = 0; + } +} diff --git a/code/opus-1.0.2/silk/float/find_pred_coefs_FLP.c b/code/opus-1.0.2/silk/float/find_pred_coefs_FLP.c new file mode 100644 index 00000000..2156893a --- /dev/null +++ b/code/opus-1.0.2/silk/float/find_pred_coefs_FLP.c @@ -0,0 +1,116 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" + +/* Find LPC and LTP coefficients */ +void silk_find_pred_coefs_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + const silk_float res_pitch[], /* I Residual from pitch analysis */ + const silk_float x[], /* I Speech signal */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + opus_int i; + silk_float WLTP[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ]; + silk_float invGains[ MAX_NB_SUBFR ], Wght[ MAX_NB_SUBFR ]; + opus_int16 NLSF_Q15[ MAX_LPC_ORDER ]; + const silk_float *x_ptr; + silk_float *x_pre_ptr, LPC_in_pre[ MAX_NB_SUBFR * MAX_LPC_ORDER + MAX_FRAME_LENGTH ]; + silk_float minInvGain; + + /* Weighting for weighted least squares */ + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + silk_assert( psEncCtrl->Gains[ i ] > 0.0f ); + invGains[ i ] = 1.0f / psEncCtrl->Gains[ i ]; + Wght[ i ] = invGains[ i ] * invGains[ i ]; + } + + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /**********/ + /* VOICED */ + /**********/ + silk_assert( psEnc->sCmn.ltp_mem_length - psEnc->sCmn.predictLPCOrder >= psEncCtrl->pitchL[ 0 ] + LTP_ORDER / 2 ); + + /* LTP analysis */ + silk_find_LTP_FLP( psEncCtrl->LTPCoef, WLTP, &psEncCtrl->LTPredCodGain, res_pitch, + psEncCtrl->pitchL, Wght, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.ltp_mem_length ); + + /* Quantize LTP gain parameters */ + silk_quant_LTP_gains_FLP( psEncCtrl->LTPCoef, psEnc->sCmn.indices.LTPIndex, &psEnc->sCmn.indices.PERIndex, + WLTP, psEnc->sCmn.mu_LTP_Q9, psEnc->sCmn.LTPQuantLowComplexity, psEnc->sCmn.nb_subfr ); + + /* Control LTP scaling */ + silk_LTP_scale_ctrl_FLP( psEnc, psEncCtrl, condCoding ); + + /* Create LTP residual */ + silk_LTP_analysis_filter_FLP( LPC_in_pre, x - psEnc->sCmn.predictLPCOrder, psEncCtrl->LTPCoef, + psEncCtrl->pitchL, invGains, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.predictLPCOrder ); + } else { + /************/ + /* UNVOICED */ + /************/ + /* Create signal with prepended subframes, scaled by inverse gains */ + x_ptr = x - psEnc->sCmn.predictLPCOrder; + x_pre_ptr = LPC_in_pre; + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + silk_scale_copy_vector_FLP( x_pre_ptr, x_ptr, invGains[ i ], + psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder ); + x_pre_ptr += psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder; + x_ptr += psEnc->sCmn.subfr_length; + } + silk_memset( psEncCtrl->LTPCoef, 0, psEnc->sCmn.nb_subfr * LTP_ORDER * sizeof( silk_float ) ); + psEncCtrl->LTPredCodGain = 0.0f; + } + + /* Limit on total predictive coding gain */ + if( psEnc->sCmn.first_frame_after_reset ) { + minInvGain = 1.0f / MAX_PREDICTION_POWER_GAIN_AFTER_RESET; + } else { + minInvGain = (silk_float)pow( 2, psEncCtrl->LTPredCodGain / 3 ) / MAX_PREDICTION_POWER_GAIN; + minInvGain /= 0.25f + 0.75f * psEncCtrl->coding_quality; + } + + /* LPC_in_pre contains the LTP-filtered input for voiced, and the unfiltered input for unvoiced */ + silk_find_LPC_FLP( &psEnc->sCmn, NLSF_Q15, LPC_in_pre, minInvGain ); + + /* Quantize LSFs */ + silk_process_NLSFs_FLP( &psEnc->sCmn, psEncCtrl->PredCoef, NLSF_Q15, psEnc->sCmn.prev_NLSFq_Q15 ); + + /* Calculate residual energy using quantized LPC coefficients */ + silk_residual_energy_FLP( psEncCtrl->ResNrg, LPC_in_pre, psEncCtrl->PredCoef, psEncCtrl->Gains, + psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.predictLPCOrder ); + + /* Copy to prediction struct for use in next frame for interpolation */ + silk_memcpy( psEnc->sCmn.prev_NLSFq_Q15, NLSF_Q15, sizeof( psEnc->sCmn.prev_NLSFq_Q15 ) ); +} + diff --git a/code/opus-1.0.2/silk/float/inner_product_FLP.c b/code/opus-1.0.2/silk/float/inner_product_FLP.c new file mode 100644 index 00000000..60823d6e --- /dev/null +++ b/code/opus-1.0.2/silk/float/inner_product_FLP.c @@ -0,0 +1,60 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FLP.h" + +/* inner product of two silk_float arrays, with result as double */ +double silk_inner_product_FLP( + const silk_float *data1, + const silk_float *data2, + opus_int dataSize +) +{ + opus_int i, dataSize4; + double result; + + /* 4x unrolled loop */ + result = 0.0; + dataSize4 = dataSize & 0xFFFC; + for( i = 0; i < dataSize4; i += 4 ) { + result += data1[ i + 0 ] * (double)data2[ i + 0 ] + + data1[ i + 1 ] * (double)data2[ i + 1 ] + + data1[ i + 2 ] * (double)data2[ i + 2 ] + + data1[ i + 3 ] * (double)data2[ i + 3 ]; + } + + /* add any remaining products */ + for( ; i < dataSize; i++ ) { + result += data1[ i ] * (double)data2[ i ]; + } + + return result; +} diff --git a/code/opus-1.0.2/silk/float/k2a_FLP.c b/code/opus-1.0.2/silk/float/k2a_FLP.c new file mode 100644 index 00000000..6f05d4b9 --- /dev/null +++ b/code/opus-1.0.2/silk/float/k2a_FLP.c @@ -0,0 +1,53 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FLP.h" + +/* step up function, converts reflection coefficients to prediction coefficients */ +void silk_k2a_FLP( + silk_float *A, /* O prediction coefficients [order] */ + const silk_float *rc, /* I reflection coefficients [order] */ + opus_int32 order /* I prediction order */ +) +{ + opus_int k, n; + silk_float Atmp[ SILK_MAX_ORDER_LPC ]; + + for( k = 0; k < order; k++ ) { + for( n = 0; n < k; n++ ) { + Atmp[ n ] = A[ n ]; + } + for( n = 0; n < k; n++ ) { + A[ n ] += Atmp[ k - n - 1 ] * rc[ k ]; + } + A[ k ] = -rc[ k ]; + } +} diff --git a/code/opus-1.0.2/silk/float/levinsondurbin_FLP.c b/code/opus-1.0.2/silk/float/levinsondurbin_FLP.c new file mode 100644 index 00000000..b4cd34e2 --- /dev/null +++ b/code/opus-1.0.2/silk/float/levinsondurbin_FLP.c @@ -0,0 +1,81 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FLP.h" + +/* Solve the normal equations using the Levinson-Durbin recursion */ +silk_float silk_levinsondurbin_FLP( /* O prediction error energy */ + silk_float A[], /* O prediction coefficients [order] */ + const silk_float corr[], /* I input auto-correlations [order + 1] */ + const opus_int order /* I prediction order */ +) +{ + opus_int i, mHalf, m; + silk_float min_nrg, nrg, t, km, Atmp1, Atmp2; + + min_nrg = 1e-12f * corr[ 0 ] + 1e-9f; + nrg = corr[ 0 ]; + nrg = silk_max_float(min_nrg, nrg); + A[ 0 ] = corr[ 1 ] / nrg; + nrg -= A[ 0 ] * corr[ 1 ]; + nrg = silk_max_float(min_nrg, nrg); + + for( m = 1; m < order; m++ ) + { + t = corr[ m + 1 ]; + for( i = 0; i < m; i++ ) { + t -= A[ i ] * corr[ m - i ]; + } + + /* reflection coefficient */ + km = t / nrg; + + /* residual energy */ + nrg -= km * t; + nrg = silk_max_float(min_nrg, nrg); + + mHalf = m >> 1; + for( i = 0; i < mHalf; i++ ) { + Atmp1 = A[ i ]; + Atmp2 = A[ m - i - 1 ]; + A[ m - i - 1 ] -= km * Atmp1; + A[ i ] -= km * Atmp2; + } + if( m & 1 ) { + A[ mHalf ] -= km * A[ mHalf ]; + } + A[ m ] = km; + } + + /* return the residual energy */ + return nrg; +} + diff --git a/code/opus-1.0.2/silk/float/main_FLP.h b/code/opus-1.0.2/silk/float/main_FLP.h new file mode 100644 index 00000000..93455d4d --- /dev/null +++ b/code/opus-1.0.2/silk/float/main_FLP.h @@ -0,0 +1,309 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (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 SILK_MAIN_FLP_H +#define SILK_MAIN_FLP_H + +#include "SigProc_FLP.h" +#include "SigProc_FIX.h" +#include "structs_FLP.h" +#include "main.h" +#include "define.h" +#include "debug.h" +#include "entenc.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define silk_encoder_state_Fxx silk_encoder_state_FLP +#define silk_encode_do_VAD_Fxx silk_encode_do_VAD_FLP +#define silk_encode_frame_Fxx silk_encode_frame_FLP + +/*********************/ +/* Encoder Functions */ +/*********************/ + +/* High-pass filter with cutoff frequency adaptation based on pitch lag statistics */ +void silk_HP_variable_cutoff( + silk_encoder_state_Fxx state_Fxx[] /* I/O Encoder states */ +); + +/* Encoder main function */ +void silk_encode_do_VAD_FLP( + silk_encoder_state_FLP *psEnc /* I/O Encoder state FLP */ +); + +/* Encoder main function */ +opus_int silk_encode_frame_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + opus_int32 *pnBytesOut, /* O Number of payload bytes; */ + ec_enc *psRangeEnc, /* I/O compressor data structure */ + opus_int condCoding, /* I The type of conditional coding to use */ + opus_int maxBits, /* I If > 0: maximum number of output bits */ + opus_int useCBR /* I Flag to force constant-bitrate operation */ +); + +/* Initializes the Silk encoder state */ +opus_int silk_init_encoder( + silk_encoder_state_FLP *psEnc /* I/O Encoder state FLP */ +); + +/* Control the Silk encoder */ +opus_int silk_control_encoder( + silk_encoder_state_FLP *psEnc, /* I/O Pointer to Silk encoder state FLP */ + silk_EncControlStruct *encControl, /* I Control structure */ + const opus_int32 TargetRate_bps, /* I Target max bitrate (bps) */ + const opus_int allow_bw_switch, /* I Flag to allow switching audio bandwidth */ + const opus_int channelNb, /* I Channel number */ + const opus_int force_fs_kHz +); + +/****************/ +/* Prefiltering */ +/****************/ +void silk_prefilter_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + const silk_encoder_control_FLP *psEncCtrl, /* I Encoder control FLP */ + silk_float xw[], /* O Weighted signal */ + const silk_float x[] /* I Speech signal */ +); + +/**************************/ +/* Noise shaping analysis */ +/**************************/ +/* Compute noise shaping coefficients and initial gain values */ +void silk_noise_shape_analysis_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + const silk_float *pitch_res, /* I LPC residual from pitch analysis */ + const silk_float *x /* I Input signal [frame_length + la_shape] */ +); + +/* Autocorrelations for a warped frequency axis */ +void silk_warped_autocorrelation_FLP( + silk_float *corr, /* O Result [order + 1] */ + const silk_float *input, /* I Input data to correlate */ + const silk_float warping, /* I Warping coefficient */ + const opus_int length, /* I Length of input */ + const opus_int order /* I Correlation order (even) */ +); + +/* Calculation of LTP state scaling */ +void silk_LTP_scale_ctrl_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/**********************************************/ +/* Prediction Analysis */ +/**********************************************/ +/* Find pitch lags */ +void silk_find_pitch_lags_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + silk_float res[], /* O Residual */ + const silk_float x[] /* I Speech signal */ +); + +/* Find LPC and LTP coefficients */ +void silk_find_pred_coefs_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + const silk_float res_pitch[], /* I Residual from pitch analysis */ + const silk_float x[], /* I Speech signal */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/* LPC analysis */ +void silk_find_LPC_FLP( + silk_encoder_state *psEncC, /* I/O Encoder state */ + opus_int16 NLSF_Q15[], /* O NLSFs */ + const silk_float x[], /* I Input signal */ + const silk_float minInvGain /* I Prediction gain from LTP (dB) */ +); + +/* LTP analysis */ +void silk_find_LTP_FLP( + silk_float b[ MAX_NB_SUBFR * LTP_ORDER ], /* O LTP coefs */ + silk_float WLTP[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Weight for LTP quantization */ + silk_float *LTPredCodGain, /* O LTP coding gain */ + const silk_float r_lpc[], /* I LPC residual */ + const opus_int lag[ MAX_NB_SUBFR ], /* I LTP lags */ + const silk_float Wght[ MAX_NB_SUBFR ], /* I Weights */ + const opus_int subfr_length, /* I Subframe length */ + const opus_int nb_subfr, /* I number of subframes */ + const opus_int mem_offset /* I Number of samples in LTP memory */ +); + +void silk_LTP_analysis_filter_FLP( + silk_float *LTP_res, /* O LTP res MAX_NB_SUBFR*(pre_lgth+subfr_lngth) */ + const silk_float *x, /* I Input signal, with preceding samples */ + const silk_float B[ LTP_ORDER * MAX_NB_SUBFR ], /* I LTP coefficients for each subframe */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const silk_float invGains[ MAX_NB_SUBFR ], /* I Inverse quantization gains */ + const opus_int subfr_length, /* I Length of each subframe */ + const opus_int nb_subfr, /* I number of subframes */ + const opus_int pre_length /* I Preceding samples for each subframe */ +); + +/* Calculates residual energies of input subframes where all subframes have LPC_order */ +/* of preceding samples */ +void silk_residual_energy_FLP( + silk_float nrgs[ MAX_NB_SUBFR ], /* O Residual energy per subframe */ + const silk_float x[], /* I Input signal */ + silk_float a[ 2 ][ MAX_LPC_ORDER ], /* I AR coefs for each frame half */ + const silk_float gains[], /* I Quantization gains */ + const opus_int subfr_length, /* I Subframe length */ + const opus_int nb_subfr, /* I number of subframes */ + const opus_int LPC_order /* I LPC order */ +); + +/* 16th order LPC analysis filter */ +void silk_LPC_analysis_filter_FLP( + silk_float r_LPC[], /* O LPC residual signal */ + const silk_float PredCoef[], /* I LPC coefficients */ + const silk_float s[], /* I Input signal */ + const opus_int length, /* I Length of input signal */ + const opus_int Order /* I LPC order */ +); + +/* LTP tap quantizer */ +void silk_quant_LTP_gains_FLP( + silk_float B[ MAX_NB_SUBFR * LTP_ORDER ], /* I/O (Un-)quantized LTP gains */ + opus_int8 cbk_index[ MAX_NB_SUBFR ], /* O Codebook index */ + opus_int8 *periodicity_index, /* O Periodicity index */ + const silk_float W[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* I Error weights */ + const opus_int mu_Q10, /* I Mu value (R/D tradeoff) */ + const opus_int lowComplexity, /* I Flag for low complexity */ + const opus_int nb_subfr /* I number of subframes */ +); + +/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */ +silk_float silk_residual_energy_covar_FLP( /* O Weighted residual energy */ + const silk_float *c, /* I Filter coefficients */ + silk_float *wXX, /* I/O Weighted correlation matrix, reg. out */ + const silk_float *wXx, /* I Weighted correlation vector */ + const silk_float wxx, /* I Weighted correlation value */ + const opus_int D /* I Dimension */ +); + +/* Processing of gains */ +void silk_process_gains_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/******************/ +/* Linear Algebra */ +/******************/ +/* Calculates correlation matrix X'*X */ +void silk_corrMatrix_FLP( + const silk_float *x, /* I x vector [ L+order-1 ] used to create X */ + const opus_int L, /* I Length of vectors */ + const opus_int Order, /* I Max lag for correlation */ + silk_float *XX /* O X'*X correlation matrix [order x order] */ +); + +/* Calculates correlation vector X'*t */ +void silk_corrVector_FLP( + const silk_float *x, /* I x vector [L+order-1] used to create X */ + const silk_float *t, /* I Target vector [L] */ + const opus_int L, /* I Length of vecors */ + const opus_int Order, /* I Max lag for correlation */ + silk_float *Xt /* O X'*t correlation vector [order] */ +); + +/* Add noise to matrix diagonal */ +void silk_regularize_correlations_FLP( + silk_float *XX, /* I/O Correlation matrices */ + silk_float *xx, /* I/O Correlation values */ + const silk_float noise, /* I Noise energy to add */ + const opus_int D /* I Dimension of XX */ +); + +/* Function to solve linear equation Ax = b, where A is an MxM symmetric matrix */ +void silk_solve_LDL_FLP( + silk_float *A, /* I/O Symmetric square matrix, out: reg. */ + const opus_int M, /* I Size of matrix */ + const silk_float *b, /* I Pointer to b vector */ + silk_float *x /* O Pointer to x solution vector */ +); + +/* Apply sine window to signal vector. */ +/* Window types: */ +/* 1 -> sine window from 0 to pi/2 */ +/* 2 -> sine window from pi/2 to pi */ +void silk_apply_sine_window_FLP( + silk_float px_win[], /* O Pointer to windowed signal */ + const silk_float px[], /* I Pointer to input signal */ + const opus_int win_type, /* I Selects a window type */ + const opus_int length /* I Window length, multiple of 4 */ +); + +/* Wrapper functions. Call flp / fix code */ + +/* Convert AR filter coefficients to NLSF parameters */ +void silk_A2NLSF_FLP( + opus_int16 *NLSF_Q15, /* O NLSF vector [ LPC_order ] */ + const silk_float *pAR, /* I LPC coefficients [ LPC_order ] */ + const opus_int LPC_order /* I LPC order */ +); + +/* Convert NLSF parameters to AR prediction filter coefficients */ +void silk_NLSF2A_FLP( + silk_float *pAR, /* O LPC coefficients [ LPC_order ] */ + const opus_int16 *NLSF_Q15, /* I NLSF vector [ LPC_order ] */ + const opus_int LPC_order /* I LPC order */ +); + +/* Limit, stabilize, and quantize NLSFs */ +void silk_process_NLSFs_FLP( + silk_encoder_state *psEncC, /* I/O Encoder state */ + silk_float PredCoef[ 2 ][ MAX_LPC_ORDER ], /* O Prediction coefficients */ + opus_int16 NLSF_Q15[ MAX_LPC_ORDER ], /* I/O Normalized LSFs (quant out) (0 - (2^15-1)) */ + const opus_int16 prev_NLSF_Q15[ MAX_LPC_ORDER ] /* I Previous Normalized LSFs (0 - (2^15-1)) */ +); + +/* Floating-point Silk NSQ wrapper */ +void silk_NSQ_wrapper_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + SideInfoIndices *psIndices, /* I/O Quantization indices */ + silk_nsq_state *psNSQ, /* I/O Noise Shaping Quantzation state */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const silk_float x[] /* I Prefiltered input signal */ +); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/code/opus-1.0.2/silk/float/noise_shape_analysis_FLP.c b/code/opus-1.0.2/silk/float/noise_shape_analysis_FLP.c new file mode 100644 index 00000000..33bfd20d --- /dev/null +++ b/code/opus-1.0.2/silk/float/noise_shape_analysis_FLP.c @@ -0,0 +1,365 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" +#include "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.) */ +/* Note: A monic filter is one with the first coefficient equal to 1.0. In Silk we omit the first */ +/* coefficient in an array of coefficients, for monic filters. */ +static inline silk_float warped_gain( + const silk_float *coefs, + silk_float lambda, + opus_int order +) { + opus_int i; + silk_float gain; + + lambda = -lambda; + gain = coefs[ order - 1 ]; + for( i = order - 2; i >= 0; i-- ) { + gain = lambda * gain + coefs[ i ]; + } + return (silk_float)( 1.0f / ( 1.0f - lambda * gain ) ); +} + +/* Convert warped filter coefficients to monic pseudo-warped coefficients and limit maximum */ +/* amplitude of monic warped coefficients by using bandwidth expansion on the true coefficients */ +static inline void warped_true2monic_coefs( + silk_float *coefs_syn, + silk_float *coefs_ana, + silk_float lambda, + silk_float limit, + opus_int order +) { + opus_int i, iter, ind = 0; + silk_float tmp, maxabs, chirp, gain_syn, gain_ana; + + /* Convert to monic coefficients */ + for( i = order - 1; i > 0; i-- ) { + coefs_syn[ i - 1 ] -= lambda * coefs_syn[ i ]; + coefs_ana[ i - 1 ] -= lambda * coefs_ana[ i ]; + } + gain_syn = ( 1.0f - lambda * lambda ) / ( 1.0f + lambda * coefs_syn[ 0 ] ); + gain_ana = ( 1.0f - lambda * lambda ) / ( 1.0f + lambda * coefs_ana[ 0 ] ); + for( i = 0; i < order; i++ ) { + coefs_syn[ i ] *= gain_syn; + coefs_ana[ i ] *= gain_ana; + } + + /* Limit */ + for( iter = 0; iter < 10; iter++ ) { + /* Find maximum absolute value */ + maxabs = -1.0f; + for( i = 0; i < order; i++ ) { + tmp = silk_max( silk_abs_float( coefs_syn[ i ] ), silk_abs_float( coefs_ana[ i ] ) ); + if( tmp > maxabs ) { + maxabs = tmp; + ind = i; + } + } + if( maxabs <= limit ) { + /* Coefficients are within range - done */ + return; + } + + /* Convert back to true warped coefficients */ + for( i = 1; i < order; i++ ) { + coefs_syn[ i - 1 ] += lambda * coefs_syn[ i ]; + coefs_ana[ i - 1 ] += lambda * coefs_ana[ i ]; + } + gain_syn = 1.0f / gain_syn; + gain_ana = 1.0f / gain_ana; + for( i = 0; i < order; i++ ) { + coefs_syn[ i ] *= gain_syn; + coefs_ana[ i ] *= gain_ana; + } + + /* Apply bandwidth expansion */ + chirp = 0.99f - ( 0.8f + 0.1f * iter ) * ( maxabs - limit ) / ( maxabs * ( ind + 1 ) ); + silk_bwexpander_FLP( coefs_syn, order, chirp ); + silk_bwexpander_FLP( coefs_ana, order, chirp ); + + /* Convert to monic warped coefficients */ + for( i = order - 1; i > 0; i-- ) { + coefs_syn[ i - 1 ] -= lambda * coefs_syn[ i ]; + coefs_ana[ i - 1 ] -= lambda * coefs_ana[ i ]; + } + gain_syn = ( 1.0f - lambda * lambda ) / ( 1.0f + lambda * coefs_syn[ 0 ] ); + gain_ana = ( 1.0f - lambda * lambda ) / ( 1.0f + lambda * coefs_ana[ 0 ] ); + for( i = 0; i < order; i++ ) { + coefs_syn[ i ] *= gain_syn; + coefs_ana[ i ] *= gain_ana; + } + } + silk_assert( 0 ); +} + +/* Compute noise shaping coefficients and initial gain values */ +void silk_noise_shape_analysis_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + const silk_float *pitch_res, /* I LPC residual from pitch analysis */ + const silk_float *x /* I Input signal [frame_length + la_shape] */ +) +{ + silk_shape_state_FLP *psShapeSt = &psEnc->sShape; + opus_int k, nSamples; + silk_float SNR_adj_dB, HarmBoost, HarmShapeGain, Tilt; + silk_float nrg, pre_nrg, log_energy, log_energy_prev, energy_variation; + silk_float delta, BWExp1, BWExp2, gain_mult, gain_add, strength, b, warping; + silk_float x_windowed[ SHAPE_LPC_WIN_MAX ]; + silk_float auto_corr[ MAX_SHAPE_LPC_ORDER + 1 ]; + const silk_float *x_ptr, *pitch_res_ptr; + + /* Point to start of first LPC analysis block */ + x_ptr = x - psEnc->sCmn.la_shape; + + /****************/ + /* GAIN CONTROL */ + /****************/ + SNR_adj_dB = psEnc->sCmn.SNR_dB_Q7 * ( 1 / 128.0f ); + + /* Input quality is the average of the quality in the lowest two VAD bands */ + psEncCtrl->input_quality = 0.5f * ( psEnc->sCmn.input_quality_bands_Q15[ 0 ] + psEnc->sCmn.input_quality_bands_Q15[ 1 ] ) * ( 1.0f / 32768.0f ); + + /* Coding quality level, between 0.0 and 1.0 */ + psEncCtrl->coding_quality = silk_sigmoid( 0.25f * ( SNR_adj_dB - 20.0f ) ); + + if( psEnc->sCmn.useCBR == 0 ) { + /* Reduce coding SNR during low speech activity */ + b = 1.0f - psEnc->sCmn.speech_activity_Q8 * ( 1.0f / 256.0f ); + SNR_adj_dB -= BG_SNR_DECR_dB * psEncCtrl->coding_quality * ( 0.5f + 0.5f * psEncCtrl->input_quality ) * b * b; + } + + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Reduce gains for periodic signals */ + SNR_adj_dB += HARM_SNR_INCR_dB * psEnc->LTPCorr; + } else { + /* For unvoiced signals and low-quality input, adjust the quality slower than SNR_dB setting */ + SNR_adj_dB += ( -0.4f * psEnc->sCmn.SNR_dB_Q7 * ( 1 / 128.0f ) + 6.0f ) * ( 1.0f - psEncCtrl->input_quality ); + } + + /*************************/ + /* SPARSENESS PROCESSING */ + /*************************/ + /* Set quantizer offset */ + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Initially set to 0; may be overruled in process_gains(..) */ + psEnc->sCmn.indices.quantOffsetType = 0; + psEncCtrl->sparseness = 0.0f; + } else { + /* Sparseness measure, based on relative fluctuations of energy per 2 milliseconds */ + nSamples = 2 * psEnc->sCmn.fs_kHz; + energy_variation = 0.0f; + log_energy_prev = 0.0f; + pitch_res_ptr = pitch_res; + for( k = 0; k < silk_SMULBB( SUB_FRAME_LENGTH_MS, psEnc->sCmn.nb_subfr ) / 2; k++ ) { + nrg = ( silk_float )nSamples + ( silk_float )silk_energy_FLP( pitch_res_ptr, nSamples ); + log_energy = silk_log2( nrg ); + if( k > 0 ) { + energy_variation += silk_abs_float( log_energy - log_energy_prev ); + } + log_energy_prev = log_energy; + pitch_res_ptr += nSamples; + } + psEncCtrl->sparseness = silk_sigmoid( 0.4f * ( energy_variation - 5.0f ) ); + + /* Set quantization offset depending on sparseness measure */ + if( psEncCtrl->sparseness > SPARSENESS_THRESHOLD_QNT_OFFSET ) { + psEnc->sCmn.indices.quantOffsetType = 0; + } else { + psEnc->sCmn.indices.quantOffsetType = 1; + } + + /* Increase coding SNR for sparse signals */ + SNR_adj_dB += SPARSE_SNR_INCR_dB * ( psEncCtrl->sparseness - 0.5f ); + } + + /*******************************/ + /* Control bandwidth expansion */ + /*******************************/ + /* More BWE for signals with high prediction gain */ + strength = FIND_PITCH_WHITE_NOISE_FRACTION * psEncCtrl->predGain; /* between 0.0 and 1.0 */ + BWExp1 = BWExp2 = BANDWIDTH_EXPANSION / ( 1.0f + strength * strength ); + delta = LOW_RATE_BANDWIDTH_EXPANSION_DELTA * ( 1.0f - 0.75f * psEncCtrl->coding_quality ); + BWExp1 -= delta; + BWExp2 += delta; + /* BWExp1 will be applied after BWExp2, so make it relative */ + BWExp1 /= BWExp2; + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Slightly more warping in analysis will move quantization noise up in frequency, where it's better masked */ + warping = (silk_float)psEnc->sCmn.warping_Q16 / 65536.0f + 0.01f * psEncCtrl->coding_quality; + } else { + warping = 0.0f; + } + + /********************************************/ + /* Compute noise shaping AR coefs and gains */ + /********************************************/ + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + /* Apply window: sine slope followed by flat part followed by cosine slope */ + opus_int shift, slope_part, flat_part; + flat_part = psEnc->sCmn.fs_kHz * 3; + slope_part = ( psEnc->sCmn.shapeWinLength - flat_part ) / 2; + + silk_apply_sine_window_FLP( x_windowed, x_ptr, 1, slope_part ); + shift = slope_part; + silk_memcpy( x_windowed + shift, x_ptr + shift, flat_part * sizeof(silk_float) ); + shift += flat_part; + silk_apply_sine_window_FLP( x_windowed + shift, x_ptr + shift, 2, slope_part ); + + /* Update pointer: next LPC analysis block */ + x_ptr += psEnc->sCmn.subfr_length; + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Calculate warped auto correlation */ + silk_warped_autocorrelation_FLP( auto_corr, x_windowed, warping, + psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder ); + } else { + /* Calculate regular auto correlation */ + silk_autocorrelation_FLP( auto_corr, x_windowed, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder + 1 ); + } + + /* Add white noise, as a fraction of energy */ + auto_corr[ 0 ] += auto_corr[ 0 ] * SHAPE_WHITE_NOISE_FRACTION; + + /* Convert correlations to prediction coefficients, and compute residual energy */ + nrg = silk_levinsondurbin_FLP( &psEncCtrl->AR2[ k * MAX_SHAPE_LPC_ORDER ], auto_corr, psEnc->sCmn.shapingLPCOrder ); + psEncCtrl->Gains[ k ] = ( silk_float )sqrt( nrg ); + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Adjust gain for warping */ + psEncCtrl->Gains[ k ] *= warped_gain( &psEncCtrl->AR2[ k * MAX_SHAPE_LPC_ORDER ], warping, psEnc->sCmn.shapingLPCOrder ); + } + + /* Bandwidth expansion for synthesis filter shaping */ + silk_bwexpander_FLP( &psEncCtrl->AR2[ k * MAX_SHAPE_LPC_ORDER ], psEnc->sCmn.shapingLPCOrder, BWExp2 ); + + /* Compute noise shaping filter coefficients */ + silk_memcpy( + &psEncCtrl->AR1[ k * MAX_SHAPE_LPC_ORDER ], + &psEncCtrl->AR2[ k * MAX_SHAPE_LPC_ORDER ], + psEnc->sCmn.shapingLPCOrder * sizeof( silk_float ) ); + + /* Bandwidth expansion for analysis filter shaping */ + silk_bwexpander_FLP( &psEncCtrl->AR1[ k * MAX_SHAPE_LPC_ORDER ], psEnc->sCmn.shapingLPCOrder, BWExp1 ); + + /* Ratio of prediction gains, in energy domain */ + pre_nrg = silk_LPC_inverse_pred_gain_FLP( &psEncCtrl->AR2[ k * MAX_SHAPE_LPC_ORDER ], psEnc->sCmn.shapingLPCOrder ); + nrg = silk_LPC_inverse_pred_gain_FLP( &psEncCtrl->AR1[ k * MAX_SHAPE_LPC_ORDER ], psEnc->sCmn.shapingLPCOrder ); + psEncCtrl->GainsPre[ k ] = 1.0f - 0.7f * ( 1.0f - pre_nrg / nrg ); + + /* Convert to monic warped prediction coefficients and limit absolute values */ + warped_true2monic_coefs( &psEncCtrl->AR2[ k * MAX_SHAPE_LPC_ORDER ], &psEncCtrl->AR1[ k * MAX_SHAPE_LPC_ORDER ], + warping, 3.999f, psEnc->sCmn.shapingLPCOrder ); + } + + /*****************/ + /* Gain tweaking */ + /*****************/ + /* Increase gains during low speech activity */ + gain_mult = (silk_float)pow( 2.0f, -0.16f * SNR_adj_dB ); + gain_add = (silk_float)pow( 2.0f, 0.16f * MIN_QGAIN_DB ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->Gains[ k ] *= gain_mult; + psEncCtrl->Gains[ k ] += gain_add; + } + + gain_mult = 1.0f + INPUT_TILT + psEncCtrl->coding_quality * HIGH_RATE_INPUT_TILT; + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->GainsPre[ k ] *= gain_mult; + } + + /************************************************/ + /* Control low-frequency shaping and noise tilt */ + /************************************************/ + /* Less low frequency shaping for noisy inputs */ + strength = LOW_FREQ_SHAPING * ( 1.0f + LOW_QUALITY_LOW_FREQ_SHAPING_DECR * ( psEnc->sCmn.input_quality_bands_Q15[ 0 ] * ( 1.0f / 32768.0f ) - 1.0f ) ); + strength *= psEnc->sCmn.speech_activity_Q8 * ( 1.0f / 256.0f ); + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Reduce low frequencies quantization noise for periodic signals, depending on pitch lag */ + /*f = 400; freqz([1, -0.98 + 2e-4 * f], [1, -0.97 + 7e-4 * f], 2^12, Fs); axis([0, 1000, -10, 1])*/ + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + b = 0.2f / psEnc->sCmn.fs_kHz + 3.0f / psEncCtrl->pitchL[ k ]; + psEncCtrl->LF_MA_shp[ k ] = -1.0f + b; + psEncCtrl->LF_AR_shp[ k ] = 1.0f - b - b * strength; + } + Tilt = - HP_NOISE_COEF - + (1 - HP_NOISE_COEF) * HARM_HP_NOISE_COEF * psEnc->sCmn.speech_activity_Q8 * ( 1.0f / 256.0f ); + } else { + b = 1.3f / psEnc->sCmn.fs_kHz; + psEncCtrl->LF_MA_shp[ 0 ] = -1.0f + b; + psEncCtrl->LF_AR_shp[ 0 ] = 1.0f - b - b * strength * 0.6f; + for( k = 1; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->LF_MA_shp[ k ] = psEncCtrl->LF_MA_shp[ 0 ]; + psEncCtrl->LF_AR_shp[ k ] = psEncCtrl->LF_AR_shp[ 0 ]; + } + Tilt = -HP_NOISE_COEF; + } + + /****************************/ + /* HARMONIC SHAPING CONTROL */ + /****************************/ + /* Control boosting of harmonic frequencies */ + HarmBoost = LOW_RATE_HARMONIC_BOOST * ( 1.0f - psEncCtrl->coding_quality ) * psEnc->LTPCorr; + + /* More harmonic boost for noisy input signals */ + HarmBoost += LOW_INPUT_QUALITY_HARMONIC_BOOST * ( 1.0f - psEncCtrl->input_quality ); + + if( USE_HARM_SHAPING && psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Harmonic noise shaping */ + HarmShapeGain = HARMONIC_SHAPING; + + /* More harmonic noise shaping for high bitrates or noisy input */ + HarmShapeGain += HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING * + ( 1.0f - ( 1.0f - psEncCtrl->coding_quality ) * psEncCtrl->input_quality ); + + /* Less harmonic noise shaping for less periodic signals */ + HarmShapeGain *= ( silk_float )sqrt( psEnc->LTPCorr ); + } else { + HarmShapeGain = 0.0f; + } + + /*************************/ + /* Smooth over subframes */ + /*************************/ + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psShapeSt->HarmBoost_smth += SUBFR_SMTH_COEF * ( HarmBoost - psShapeSt->HarmBoost_smth ); + psEncCtrl->HarmBoost[ k ] = psShapeSt->HarmBoost_smth; + psShapeSt->HarmShapeGain_smth += SUBFR_SMTH_COEF * ( HarmShapeGain - psShapeSt->HarmShapeGain_smth ); + psEncCtrl->HarmShapeGain[ k ] = psShapeSt->HarmShapeGain_smth; + psShapeSt->Tilt_smth += SUBFR_SMTH_COEF * ( Tilt - psShapeSt->Tilt_smth ); + psEncCtrl->Tilt[ k ] = psShapeSt->Tilt_smth; + } +} diff --git a/code/opus-1.0.2/silk/float/pitch_analysis_core_FLP.c b/code/opus-1.0.2/silk/float/pitch_analysis_core_FLP.c new file mode 100644 index 00000000..fbff90c3 --- /dev/null +++ b/code/opus-1.0.2/silk/float/pitch_analysis_core_FLP.c @@ -0,0 +1,630 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/***************************************************************************** +* Pitch analyser function +******************************************************************************/ +#include "SigProc_FLP.h" +#include "SigProc_FIX.h" +#include "pitch_est_defines.h" + +#define SCRATCH_SIZE 22 +#define eps 1.192092896e-07f + +/************************************************************/ +/* Internally used functions */ +/************************************************************/ +static void silk_P_Ana_calc_corr_st3( + silk_float cross_corr_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ], /* O 3 DIM correlation array */ + const silk_float frame[], /* I vector to correlate */ + opus_int start_lag, /* I start lag */ + opus_int sf_length, /* I sub frame length */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity /* I Complexity setting */ +); + +static void silk_P_Ana_calc_energy_st3( + silk_float energies_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ], /* O 3 DIM correlation array */ + const silk_float frame[], /* I vector to correlate */ + opus_int start_lag, /* I start lag */ + opus_int sf_length, /* I sub frame length */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity /* I Complexity setting */ +); + +/************************************************************/ +/* CORE PITCH ANALYSIS FUNCTION */ +/************************************************************/ +opus_int silk_pitch_analysis_core_FLP( /* O Voicing estimate: 0 voiced, 1 unvoiced */ + const silk_float *frame, /* I Signal of length PE_FRAME_LENGTH_MS*Fs_kHz */ + opus_int *pitch_out, /* O Pitch lag values [nb_subfr] */ + opus_int16 *lagIndex, /* O Lag Index */ + opus_int8 *contourIndex, /* O Pitch contour Index */ + silk_float *LTPCorr, /* I/O Normalized correlation; input: value from previous frame */ + opus_int prevLag, /* I Last lag of previous frame; set to zero is unvoiced */ + const silk_float search_thres1, /* I First stage threshold for lag candidates 0 - 1 */ + const silk_float search_thres2, /* I Final threshold for lag candidates 0 - 1 */ + const opus_int Fs_kHz, /* I sample frequency (kHz) */ + const opus_int complexity, /* I Complexity setting, 0-2, where 2 is highest */ + const opus_int nb_subfr /* I Number of 5 ms subframes */ +) +{ + opus_int i, k, d, j; + silk_float frame_8kHz[ PE_MAX_FRAME_LENGTH_MS * 8 ]; + silk_float frame_4kHz[ PE_MAX_FRAME_LENGTH_MS * 4 ]; + opus_int16 frame_8_FIX[ PE_MAX_FRAME_LENGTH_MS * 8 ]; + opus_int16 frame_4_FIX[ PE_MAX_FRAME_LENGTH_MS * 4 ]; + opus_int32 filt_state[ 6 ]; + silk_float threshold, contour_bias; + silk_float C[ PE_MAX_NB_SUBFR][ (PE_MAX_LAG >> 1) + 5 ]; + silk_float CC[ PE_NB_CBKS_STAGE2_EXT ]; + const silk_float *target_ptr, *basis_ptr; + double cross_corr, normalizer, energy, energy_tmp; + opus_int d_srch[ PE_D_SRCH_LENGTH ]; + opus_int16 d_comp[ (PE_MAX_LAG >> 1) + 5 ]; + opus_int length_d_srch, length_d_comp; + silk_float Cmax, CCmax, CCmax_b, CCmax_new_b, CCmax_new; + opus_int CBimax, CBimax_new, lag, start_lag, end_lag, lag_new; + opus_int cbk_size; + silk_float lag_log2, prevLag_log2, delta_lag_log2_sqr; + silk_float energies_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ]; + silk_float cross_corr_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ]; + opus_int lag_counter; + opus_int frame_length, frame_length_8kHz, frame_length_4kHz; + opus_int sf_length, sf_length_8kHz, sf_length_4kHz; + opus_int min_lag, min_lag_8kHz, min_lag_4kHz; + opus_int max_lag, max_lag_8kHz, max_lag_4kHz; + opus_int nb_cbk_search; + const opus_int8 *Lag_CB_ptr; + + /* Check for valid sampling frequency */ + silk_assert( Fs_kHz == 8 || Fs_kHz == 12 || Fs_kHz == 16 ); + + /* Check for valid complexity setting */ + silk_assert( complexity >= SILK_PE_MIN_COMPLEX ); + silk_assert( complexity <= SILK_PE_MAX_COMPLEX ); + + silk_assert( search_thres1 >= 0.0f && search_thres1 <= 1.0f ); + silk_assert( search_thres2 >= 0.0f && search_thres2 <= 1.0f ); + + /* Set up frame lengths max / min lag for the sampling frequency */ + frame_length = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * Fs_kHz; + frame_length_4kHz = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * 4; + frame_length_8kHz = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * 8; + sf_length = PE_SUBFR_LENGTH_MS * Fs_kHz; + sf_length_4kHz = PE_SUBFR_LENGTH_MS * 4; + sf_length_8kHz = PE_SUBFR_LENGTH_MS * 8; + min_lag = PE_MIN_LAG_MS * Fs_kHz; + min_lag_4kHz = PE_MIN_LAG_MS * 4; + min_lag_8kHz = PE_MIN_LAG_MS * 8; + max_lag = PE_MAX_LAG_MS * Fs_kHz - 1; + max_lag_4kHz = PE_MAX_LAG_MS * 4; + max_lag_8kHz = PE_MAX_LAG_MS * 8 - 1; + + silk_memset(C, 0, sizeof(silk_float) * nb_subfr * ((PE_MAX_LAG >> 1) + 5)); + + /* Resample from input sampled at Fs_kHz to 8 kHz */ + if( Fs_kHz == 16 ) { + /* Resample to 16 -> 8 khz */ + opus_int16 frame_16_FIX[ 16 * PE_MAX_FRAME_LENGTH_MS ]; + silk_float2short_array( frame_16_FIX, frame, frame_length ); + silk_memset( filt_state, 0, 2 * sizeof( opus_int32 ) ); + silk_resampler_down2( filt_state, frame_8_FIX, frame_16_FIX, frame_length ); + silk_short2float_array( frame_8kHz, frame_8_FIX, frame_length_8kHz ); + } else if( Fs_kHz == 12 ) { + /* Resample to 12 -> 8 khz */ + opus_int16 frame_12_FIX[ 12 * PE_MAX_FRAME_LENGTH_MS ]; + silk_float2short_array( frame_12_FIX, frame, frame_length ); + silk_memset( filt_state, 0, 6 * sizeof( opus_int32 ) ); + silk_resampler_down2_3( filt_state, frame_8_FIX, frame_12_FIX, frame_length ); + silk_short2float_array( frame_8kHz, frame_8_FIX, frame_length_8kHz ); + } else { + silk_assert( Fs_kHz == 8 ); + silk_float2short_array( frame_8_FIX, frame, frame_length_8kHz ); + } + + /* Decimate again to 4 kHz */ + silk_memset( filt_state, 0, 2 * sizeof( opus_int32 ) ); + silk_resampler_down2( filt_state, frame_4_FIX, frame_8_FIX, frame_length_8kHz ); + silk_short2float_array( frame_4kHz, frame_4_FIX, frame_length_4kHz ); + + /* Low-pass filter */ + for( i = frame_length_4kHz - 1; i > 0; i-- ) { + frame_4kHz[ i ] += frame_4kHz[ i - 1 ]; + } + + /****************************************************************************** + * FIRST STAGE, operating in 4 khz + ******************************************************************************/ + target_ptr = &frame_4kHz[ silk_LSHIFT( sf_length_4kHz, 2 ) ]; + for( k = 0; k < nb_subfr >> 1; k++ ) { + /* Check that we are within range of the array */ + silk_assert( target_ptr >= frame_4kHz ); + silk_assert( target_ptr + sf_length_8kHz <= frame_4kHz + frame_length_4kHz ); + + basis_ptr = target_ptr - min_lag_4kHz; + + /* Check that we are within range of the array */ + silk_assert( basis_ptr >= frame_4kHz ); + silk_assert( basis_ptr + sf_length_8kHz <= frame_4kHz + frame_length_4kHz ); + + /* Calculate first vector products before loop */ + cross_corr = silk_inner_product_FLP( target_ptr, basis_ptr, sf_length_8kHz ); + normalizer = silk_energy_FLP( basis_ptr, sf_length_8kHz ) + sf_length_8kHz * 4000.0f; + + C[ 0 ][ min_lag_4kHz ] += (silk_float)(cross_corr / sqrt(normalizer)); + + /* From now on normalizer is computed recursively */ + for(d = min_lag_4kHz + 1; d <= max_lag_4kHz; d++) { + basis_ptr--; + + /* Check that we are within range of the array */ + silk_assert( basis_ptr >= frame_4kHz ); + silk_assert( basis_ptr + sf_length_8kHz <= frame_4kHz + frame_length_4kHz ); + + cross_corr = silk_inner_product_FLP(target_ptr, basis_ptr, sf_length_8kHz); + + /* Add contribution of new sample and remove contribution from oldest sample */ + normalizer += + basis_ptr[ 0 ] * (double)basis_ptr[ 0 ] - + basis_ptr[ sf_length_8kHz ] * (double)basis_ptr[ sf_length_8kHz ]; + C[ 0 ][ d ] += (silk_float)(cross_corr / sqrt( normalizer )); + } + /* Update target pointer */ + target_ptr += sf_length_8kHz; + } + + /* Apply short-lag bias */ + for( i = max_lag_4kHz; i >= min_lag_4kHz; i-- ) { + C[ 0 ][ i ] -= C[ 0 ][ i ] * i / 4096.0f; + } + + /* Sort */ + length_d_srch = 4 + 2 * complexity; + silk_assert( 3 * length_d_srch <= PE_D_SRCH_LENGTH ); + silk_insertion_sort_decreasing_FLP( &C[ 0 ][ min_lag_4kHz ], d_srch, max_lag_4kHz - min_lag_4kHz + 1, length_d_srch ); + + /* Escape if correlation is very low already here */ + Cmax = C[ 0 ][ min_lag_4kHz ]; + target_ptr = &frame_4kHz[ silk_SMULBB( sf_length_4kHz, nb_subfr ) ]; + energy = 1000.0f; + for( i = 0; i < silk_LSHIFT( sf_length_4kHz, 2 ); i++ ) { + energy += target_ptr[i] * (double)target_ptr[i]; + } + threshold = Cmax * Cmax; + if( energy / 16.0f > threshold ) { + silk_memset( pitch_out, 0, nb_subfr * sizeof( opus_int ) ); + *LTPCorr = 0.0f; + *lagIndex = 0; + *contourIndex = 0; + return 1; + } + + threshold = search_thres1 * Cmax; + for( i = 0; i < length_d_srch; i++ ) { + /* Convert to 8 kHz indices for the sorted correlation that exceeds the threshold */ + if( C[ 0 ][ min_lag_4kHz + i ] > threshold ) { + d_srch[ i ] = silk_LSHIFT( d_srch[ i ] + min_lag_4kHz, 1 ); + } else { + length_d_srch = i; + break; + } + } + silk_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 ] = (opus_int16)( i - 2 ); + length_d_comp++; + } + } + + /********************************************************************************** + ** SECOND STAGE, operating at 8 kHz, on lag sections with high correlation + *************************************************************************************/ + /********************************************************************************* + * Find energy of each subframe projected onto its history, for a range of delays + *********************************************************************************/ + silk_memset( C, 0, PE_MAX_NB_SUBFR*((PE_MAX_LAG >> 1) + 5) * sizeof(silk_float)); + + if( Fs_kHz == 8 ) { + target_ptr = &frame[ PE_LTP_MEM_LENGTH_MS * 8 ]; + } else { + target_ptr = &frame_8kHz[ PE_LTP_MEM_LENGTH_MS * 8 ]; + } + for( k = 0; k < nb_subfr; k++ ) { + energy_tmp = silk_energy_FLP( target_ptr, sf_length_8kHz ); + for( j = 0; j < length_d_comp; j++ ) { + d = d_comp[ j ]; + basis_ptr = target_ptr - d; + cross_corr = silk_inner_product_FLP( basis_ptr, target_ptr, sf_length_8kHz ); + energy = silk_energy_FLP( basis_ptr, sf_length_8kHz ); + if( cross_corr > 0.0f ) { + C[ k ][ d ] = (silk_float)(cross_corr * cross_corr / (energy * energy_tmp + eps)); + } else { + C[ k ][ d ] = 0.0f; + } + } + target_ptr += sf_length_8kHz; + } + + /* search over lag range and lags codebook */ + /* scale factor for lag codebook, as a function of center lag */ + + CCmax = 0.0f; /* This value doesn't matter */ + CCmax_b = -1000.0f; + + CBimax = 0; /* To avoid returning undefined lag values */ + lag = -1; /* To check if lag with strong enough correlation has been found */ + + if( prevLag > 0 ) { + if( Fs_kHz == 12 ) { + prevLag = silk_LSHIFT( prevLag, 1 ) / 3; + } else if( Fs_kHz == 16 ) { + prevLag = silk_RSHIFT( prevLag, 1 ); + } + prevLag_log2 = silk_log2((silk_float)prevLag); + } else { + prevLag_log2 = 0; + } + + /* Set up stage 2 codebook based on number of subframes */ + if( nb_subfr == PE_MAX_NB_SUBFR ) { + cbk_size = PE_NB_CBKS_STAGE2_EXT; + Lag_CB_ptr = &silk_CB_lags_stage2[ 0 ][ 0 ]; + if( Fs_kHz == 8 && complexity > SILK_PE_MIN_COMPLEX ) { + /* If input is 8 khz use a larger codebook here because it is last stage */ + nb_cbk_search = PE_NB_CBKS_STAGE2_EXT; + } else { + nb_cbk_search = PE_NB_CBKS_STAGE2; + } + } else { + cbk_size = PE_NB_CBKS_STAGE2_10MS; + Lag_CB_ptr = &silk_CB_lags_stage2_10_ms[ 0 ][ 0 ]; + nb_cbk_search = PE_NB_CBKS_STAGE2_10MS; + } + + for( k = 0; k < length_d_srch; k++ ) { + d = d_srch[ k ]; + for( j = 0; j < nb_cbk_search; j++ ) { + CC[j] = 0.0f; + for( i = 0; i < nb_subfr; i++ ) { + /* Try all codebooks */ + CC[ j ] += C[ i ][ d + matrix_ptr( Lag_CB_ptr, i, j, cbk_size )]; + } + } + /* Find best codebook */ + CCmax_new = -1000.0f; + CBimax_new = 0; + for( i = 0; i < nb_cbk_search; i++ ) { + if( CC[ i ] > CCmax_new ) { + CCmax_new = CC[ i ]; + CBimax_new = i; + } + } + CCmax_new = silk_max_float(CCmax_new, 0.0f); /* To avoid taking square root of negative number later */ + CCmax_new_b = CCmax_new; + + /* Bias towards shorter lags */ + lag_log2 = silk_log2((silk_float)d); + CCmax_new_b -= PE_SHORTLAG_BIAS * nb_subfr * lag_log2; + + /* Bias towards previous lag */ + if( prevLag > 0 ) { + delta_lag_log2_sqr = lag_log2 - prevLag_log2; + delta_lag_log2_sqr *= delta_lag_log2_sqr; + CCmax_new_b -= PE_PREVLAG_BIAS * nb_subfr * (*LTPCorr) * delta_lag_log2_sqr / (delta_lag_log2_sqr + 0.5f); + } + + if( CCmax_new_b > CCmax_b && /* Find maximum biased correlation */ + CCmax_new > nb_subfr * search_thres2 * search_thres2 && /* Correlation needs to be high enough to be voiced */ + 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 */ + silk_memset( pitch_out, 0, PE_MAX_NB_SUBFR * sizeof(opus_int) ); + *LTPCorr = 0.0f; + *lagIndex = 0; + *contourIndex = 0; + return 1; + } + + if( Fs_kHz > 8 ) { + /* Search in original signal */ + + /* Compensate for decimation */ + silk_assert( lag == silk_SAT16( lag ) ); + if( Fs_kHz == 12 ) { + lag = silk_RSHIFT_ROUND( silk_SMULBB( lag, 3 ), 1 ); + } else { /* Fs_kHz == 16 */ + lag = silk_LSHIFT( lag, 1 ); + } + + lag = silk_LIMIT_int( lag, min_lag, max_lag ); + start_lag = silk_max_int( lag - 2, min_lag ); + end_lag = silk_min_int( lag + 2, max_lag ); + lag_new = lag; /* to avoid undefined lag */ + CBimax = 0; /* to avoid undefined lag */ + silk_assert( CCmax >= 0.0f ); + *LTPCorr = (silk_float)sqrt( CCmax / nb_subfr ); /* Output normalized correlation */ + + CCmax = -1000.0f; + + /* Calculate the correlations and energies needed in stage 3 */ + silk_P_Ana_calc_corr_st3( cross_corr_st3, frame, start_lag, sf_length, nb_subfr, complexity ); + silk_P_Ana_calc_energy_st3( energies_st3, frame, start_lag, sf_length, nb_subfr, complexity ); + + lag_counter = 0; + silk_assert( lag == silk_SAT16( lag ) ); + contour_bias = PE_FLATCONTOUR_BIAS / lag; + + /* Set up cbk parameters according to complexity setting and frame length */ + if( nb_subfr == PE_MAX_NB_SUBFR ) { + nb_cbk_search = (opus_int)silk_nb_cbk_searchs_stage3[ complexity ]; + cbk_size = PE_NB_CBKS_STAGE3_MAX; + Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ]; + } else { + nb_cbk_search = PE_NB_CBKS_STAGE3_10MS; + cbk_size = PE_NB_CBKS_STAGE3_10MS; + Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ]; + } + + for( d = start_lag; d <= end_lag; d++ ) { + for( j = 0; j < nb_cbk_search; j++ ) { + cross_corr = 0.0; + energy = eps; + for( k = 0; k < nb_subfr; k++ ) { + energy += energies_st3[ k ][ j ][ lag_counter ]; + cross_corr += cross_corr_st3[ k ][ j ][ lag_counter ]; + } + if( cross_corr > 0.0 ) { + CCmax_new = (silk_float)(cross_corr * cross_corr / energy); + /* Reduce depending on flatness of contour */ + CCmax_new *= 1.0f - contour_bias * j; + } else { + CCmax_new = 0.0f; + } + + if( CCmax_new > CCmax && + ( d + (opus_int)silk_CB_lags_stage3[ 0 ][ j ] ) <= max_lag + ) { + CCmax = CCmax_new; + lag_new = d; + CBimax = j; + } + } + lag_counter++; + } + + for( k = 0; k < nb_subfr; k++ ) { + pitch_out[ k ] = lag_new + matrix_ptr( Lag_CB_ptr, k, CBimax, cbk_size ); + pitch_out[ k ] = silk_LIMIT( pitch_out[ k ], min_lag, PE_MAX_LAG_MS * Fs_kHz ); + } + *lagIndex = (opus_int16)( lag_new - min_lag ); + *contourIndex = (opus_int8)CBimax; + } else { /* Fs_kHz == 8 */ + /* Save Lags and correlation */ + silk_assert( CCmax >= 0.0f ); + *LTPCorr = (silk_float)sqrt( CCmax / nb_subfr ); /* Output normalized correlation */ + for( k = 0; k < nb_subfr; k++ ) { + pitch_out[ k ] = lag + matrix_ptr( Lag_CB_ptr, k, CBimax, cbk_size ); + pitch_out[ k ] = silk_LIMIT( pitch_out[ k ], min_lag_8kHz, PE_MAX_LAG_MS * Fs_kHz ); + } + *lagIndex = (opus_int16)( lag - min_lag_8kHz ); + *contourIndex = (opus_int8)CBimax; + } + silk_assert( *lagIndex >= 0 ); + /* return as voiced */ + return 0; +} + +static void silk_P_Ana_calc_corr_st3( + silk_float cross_corr_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ], /* O 3 DIM correlation array */ + const silk_float frame[], /* I vector to correlate */ + opus_int start_lag, /* I start lag */ + opus_int sf_length, /* I sub frame length */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity /* I Complexity setting */ +) + /*********************************************************************** + Calculates the correlations used in stage 3 search. In order to cover + the whole lag codebook for all the searched offset lags (lag +- 2), + the following correlations are needed in each sub frame: + + sf1: lag range [-8,...,7] total 16 correlations + sf2: lag range [-4,...,4] total 9 correlations + sf3: lag range [-3,....4] total 8 correltions + sf4: lag range [-6,....8] total 15 correlations + + In total 48 correlations. The direct implementation computed in worst case + 4*12*5 = 240 correlations, but more likely around 120. + **********************************************************************/ +{ + const silk_float *target_ptr, *basis_ptr; + opus_int i, j, k, lag_counter, lag_low, lag_high; + opus_int nb_cbk_search, delta, idx, cbk_size; + silk_float scratch_mem[ SCRATCH_SIZE ]; + const opus_int8 *Lag_range_ptr, *Lag_CB_ptr; + + silk_assert( complexity >= SILK_PE_MIN_COMPLEX ); + silk_assert( complexity <= SILK_PE_MAX_COMPLEX ); + + if( nb_subfr == PE_MAX_NB_SUBFR ) { + Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ]; + nb_cbk_search = silk_nb_cbk_searchs_stage3[ complexity ]; + cbk_size = PE_NB_CBKS_STAGE3_MAX; + } else { + silk_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1); + Lag_range_ptr = &silk_Lag_range_stage3_10_ms[ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ]; + nb_cbk_search = PE_NB_CBKS_STAGE3_10MS; + cbk_size = PE_NB_CBKS_STAGE3_10MS; + } + + target_ptr = &frame[ silk_LSHIFT( sf_length, 2 ) ]; /* Pointer to middle of frame */ + for( k = 0; k < nb_subfr; k++ ) { + lag_counter = 0; + + /* Calculate the correlations for each subframe */ + lag_low = matrix_ptr( Lag_range_ptr, k, 0, 2 ); + lag_high = matrix_ptr( Lag_range_ptr, k, 1, 2 ); + for( j = lag_low; j <= lag_high; j++ ) { + basis_ptr = target_ptr - ( start_lag + j ); + silk_assert( lag_counter < SCRATCH_SIZE ); + scratch_mem[ lag_counter ] = (silk_float)silk_inner_product_FLP( target_ptr, basis_ptr, sf_length ); + lag_counter++; + } + + delta = matrix_ptr( Lag_range_ptr, k, 0, 2 ); + for( i = 0; i < nb_cbk_search; i++ ) { + /* Fill out the 3 dim array that stores the correlations for */ + /* each code_book vector for each start lag */ + idx = matrix_ptr( Lag_CB_ptr, k, i, cbk_size ) - delta; + for( j = 0; j < PE_NB_STAGE3_LAGS; j++ ) { + silk_assert( idx + j < SCRATCH_SIZE ); + silk_assert( idx + j < lag_counter ); + cross_corr_st3[ k ][ i ][ j ] = scratch_mem[ idx + j ]; + } + } + target_ptr += sf_length; + } +} + +static void silk_P_Ana_calc_energy_st3( + silk_float energies_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ], /* O 3 DIM correlation array */ + const silk_float frame[], /* I vector to correlate */ + opus_int start_lag, /* I start lag */ + opus_int sf_length, /* I sub frame length */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity /* I Complexity setting */ +) +/**************************************************************** +Calculate the energies for first two subframes. The energies are +calculated recursively. +****************************************************************/ +{ + const silk_float *target_ptr, *basis_ptr; + double energy; + opus_int k, i, j, lag_counter; + opus_int nb_cbk_search, delta, idx, cbk_size, lag_diff; + silk_float scratch_mem[ SCRATCH_SIZE ]; + const opus_int8 *Lag_range_ptr, *Lag_CB_ptr; + + silk_assert( complexity >= SILK_PE_MIN_COMPLEX ); + silk_assert( complexity <= SILK_PE_MAX_COMPLEX ); + + if( nb_subfr == PE_MAX_NB_SUBFR ) { + Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ]; + nb_cbk_search = silk_nb_cbk_searchs_stage3[ complexity ]; + cbk_size = PE_NB_CBKS_STAGE3_MAX; + } else { + silk_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1); + Lag_range_ptr = &silk_Lag_range_stage3_10_ms[ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ]; + nb_cbk_search = PE_NB_CBKS_STAGE3_10MS; + cbk_size = PE_NB_CBKS_STAGE3_10MS; + } + + target_ptr = &frame[ silk_LSHIFT( sf_length, 2 ) ]; + for( k = 0; k < nb_subfr; k++ ) { + lag_counter = 0; + + /* Calculate the energy for first lag */ + basis_ptr = target_ptr - ( start_lag + matrix_ptr( Lag_range_ptr, k, 0, 2 ) ); + energy = silk_energy_FLP( basis_ptr, sf_length ) + 1e-3; + silk_assert( energy >= 0.0 ); + scratch_mem[lag_counter] = (silk_float)energy; + lag_counter++; + + lag_diff = ( matrix_ptr( Lag_range_ptr, k, 1, 2 ) - matrix_ptr( Lag_range_ptr, k, 0, 2 ) + 1 ); + for( i = 1; i < lag_diff; i++ ) { + /* remove part outside new window */ + energy -= basis_ptr[sf_length - i] * (double)basis_ptr[sf_length - i]; + silk_assert( energy >= 0.0 ); + + /* add part that comes into window */ + energy += basis_ptr[ -i ] * (double)basis_ptr[ -i ]; + silk_assert( energy >= 0.0 ); + silk_assert( lag_counter < SCRATCH_SIZE ); + scratch_mem[lag_counter] = (silk_float)energy; + lag_counter++; + } + + delta = matrix_ptr( Lag_range_ptr, k, 0, 2 ); + for( i = 0; i < nb_cbk_search; i++ ) { + /* Fill out the 3 dim array that stores the correlations for */ + /* each code_book vector for each start lag */ + idx = matrix_ptr( Lag_CB_ptr, k, i, cbk_size ) - delta; + for( j = 0; j < PE_NB_STAGE3_LAGS; j++ ) { + silk_assert( idx + j < SCRATCH_SIZE ); + silk_assert( idx + j < lag_counter ); + energies_st3[ k ][ i ][ j ] = scratch_mem[ idx + j ]; + silk_assert( energies_st3[ k ][ i ][ j ] >= 0.0f ); + } + } + target_ptr += sf_length; + } +} diff --git a/code/opus-1.0.2/silk/float/prefilter_FLP.c b/code/opus-1.0.2/silk/float/prefilter_FLP.c new file mode 100644 index 00000000..d6c84398 --- /dev/null +++ b/code/opus-1.0.2/silk/float/prefilter_FLP.c @@ -0,0 +1,206 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" +#include "tuning_parameters.h" + +/* +* Prefilter for finding Quantizer input signal +*/ +static inline void silk_prefilt_FLP( + silk_prefilter_state_FLP *P, /* I/O state */ + silk_float st_res[], /* I */ + silk_float xw[], /* O */ + silk_float *HarmShapeFIR, /* I */ + silk_float Tilt, /* I */ + silk_float LF_MA_shp, /* I */ + silk_float LF_AR_shp, /* I */ + opus_int lag, /* I */ + opus_int length /* I */ +); + +static void silk_warped_LPC_analysis_filter_FLP( + silk_float state[], /* I/O State [order + 1] */ + silk_float res[], /* O Residual signal [length] */ + const silk_float coef[], /* I Coefficients [order] */ + const silk_float input[], /* I Input signal [length] */ + const silk_float lambda, /* I Warping factor */ + const opus_int length, /* I Length of input signal */ + const opus_int order /* I Filter order (even) */ +) +{ + opus_int n, i; + silk_float acc, tmp1, tmp2; + + /* Order must be even */ + silk_assert( ( order & 1 ) == 0 ); + + for( n = 0; n < length; n++ ) { + /* Output of lowpass section */ + tmp2 = state[ 0 ] + lambda * state[ 1 ]; + state[ 0 ] = input[ n ]; + /* Output of allpass section */ + tmp1 = state[ 1 ] + lambda * ( state[ 2 ] - tmp2 ); + state[ 1 ] = tmp2; + acc = coef[ 0 ] * tmp2; + /* Loop over allpass sections */ + for( i = 2; i < order; i += 2 ) { + /* Output of allpass section */ + tmp2 = state[ i ] + lambda * ( state[ i + 1 ] - tmp1 ); + state[ i ] = tmp1; + acc += coef[ i - 1 ] * tmp1; + /* Output of allpass section */ + tmp1 = state[ i + 1 ] + lambda * ( state[ i + 2 ] - tmp2 ); + state[ i + 1 ] = tmp2; + acc += coef[ i ] * tmp2; + } + state[ order ] = tmp1; + acc += coef[ order - 1 ] * tmp1; + res[ n ] = input[ n ] - acc; + } +} + +/* +* silk_prefilter. Main prefilter function +*/ +void silk_prefilter_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + const silk_encoder_control_FLP *psEncCtrl, /* I Encoder control FLP */ + silk_float xw[], /* O Weighted signal */ + const silk_float x[] /* I Speech signal */ +) +{ + silk_prefilter_state_FLP *P = &psEnc->sPrefilt; + opus_int j, k, lag; + silk_float HarmShapeGain, Tilt, LF_MA_shp, LF_AR_shp; + silk_float B[ 2 ]; + const silk_float *AR1_shp; + const silk_float *px; + silk_float *pxw; + silk_float HarmShapeFIR[ 3 ]; + silk_float st_res[ MAX_SUB_FRAME_LENGTH + MAX_LPC_ORDER ]; + + /* Set up pointers */ + px = x; + pxw = xw; + lag = P->lagPrev; + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + /* Update Variables that change per sub frame */ + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + lag = psEncCtrl->pitchL[ k ]; + } + + /* Noise shape parameters */ + HarmShapeGain = psEncCtrl->HarmShapeGain[ k ] * ( 1.0f - psEncCtrl->HarmBoost[ k ] ); + HarmShapeFIR[ 0 ] = 0.25f * HarmShapeGain; + HarmShapeFIR[ 1 ] = 32767.0f / 65536.0f * HarmShapeGain; + HarmShapeFIR[ 2 ] = 0.25f * HarmShapeGain; + Tilt = psEncCtrl->Tilt[ k ]; + LF_MA_shp = psEncCtrl->LF_MA_shp[ k ]; + LF_AR_shp = psEncCtrl->LF_AR_shp[ k ]; + AR1_shp = &psEncCtrl->AR1[ k * MAX_SHAPE_LPC_ORDER ]; + + /* Short term FIR filtering */ + silk_warped_LPC_analysis_filter_FLP( P->sAR_shp, st_res, AR1_shp, px, + (silk_float)psEnc->sCmn.warping_Q16 / 65536.0f, psEnc->sCmn.subfr_length, psEnc->sCmn.shapingLPCOrder ); + + /* Reduce (mainly) low frequencies during harmonic emphasis */ + B[ 0 ] = psEncCtrl->GainsPre[ k ]; + B[ 1 ] = -psEncCtrl->GainsPre[ k ] * + ( psEncCtrl->HarmBoost[ k ] * HarmShapeGain + INPUT_TILT + psEncCtrl->coding_quality * HIGH_RATE_INPUT_TILT ); + pxw[ 0 ] = B[ 0 ] * st_res[ 0 ] + B[ 1 ] * P->sHarmHP; + for( j = 1; j < psEnc->sCmn.subfr_length; j++ ) { + pxw[ j ] = B[ 0 ] * st_res[ j ] + B[ 1 ] * st_res[ j - 1 ]; + } + P->sHarmHP = st_res[ psEnc->sCmn.subfr_length - 1 ]; + + silk_prefilt_FLP( P, pxw, pxw, HarmShapeFIR, Tilt, LF_MA_shp, LF_AR_shp, lag, psEnc->sCmn.subfr_length ); + + px += psEnc->sCmn.subfr_length; + pxw += psEnc->sCmn.subfr_length; + } + P->lagPrev = psEncCtrl->pitchL[ psEnc->sCmn.nb_subfr - 1 ]; +} + +/* +* Prefilter for finding Quantizer input signal +*/ +static inline void silk_prefilt_FLP( + silk_prefilter_state_FLP *P, /* I/O state */ + silk_float st_res[], /* I */ + silk_float xw[], /* O */ + silk_float *HarmShapeFIR, /* I */ + silk_float Tilt, /* I */ + silk_float LF_MA_shp, /* I */ + silk_float LF_AR_shp, /* I */ + opus_int lag, /* I */ + opus_int length /* I */ +) +{ + opus_int i; + opus_int idx, LTP_shp_buf_idx; + silk_float n_Tilt, n_LF, n_LTP; + silk_float sLF_AR_shp, sLF_MA_shp; + silk_float *LTP_shp_buf; + + /* To speed up use temp variables instead of using the struct */ + LTP_shp_buf = P->sLTP_shp; + LTP_shp_buf_idx = P->sLTP_shp_buf_idx; + sLF_AR_shp = P->sLF_AR_shp; + sLF_MA_shp = P->sLF_MA_shp; + + for( i = 0; i < length; i++ ) { + if( lag > 0 ) { + silk_assert( HARM_SHAPE_FIR_TAPS == 3 ); + idx = lag + LTP_shp_buf_idx; + n_LTP = LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 - 1) & LTP_MASK ] * HarmShapeFIR[ 0 ]; + n_LTP += LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 ) & LTP_MASK ] * HarmShapeFIR[ 1 ]; + n_LTP += LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 + 1) & LTP_MASK ] * HarmShapeFIR[ 2 ]; + } else { + n_LTP = 0; + } + + n_Tilt = sLF_AR_shp * Tilt; + n_LF = sLF_AR_shp * LF_AR_shp + sLF_MA_shp * LF_MA_shp; + + sLF_AR_shp = st_res[ i ] - n_Tilt; + sLF_MA_shp = sLF_AR_shp - n_LF; + + LTP_shp_buf_idx = ( LTP_shp_buf_idx - 1 ) & LTP_MASK; + LTP_shp_buf[ LTP_shp_buf_idx ] = sLF_MA_shp; + + xw[ i ] = sLF_MA_shp - n_LTP; + } + /* Copy temp variable back to state */ + P->sLF_AR_shp = sLF_AR_shp; + P->sLF_MA_shp = sLF_MA_shp; + P->sLTP_shp_buf_idx = LTP_shp_buf_idx; +} diff --git a/code/opus-1.0.2/silk/float/process_gains_FLP.c b/code/opus-1.0.2/silk/float/process_gains_FLP.c new file mode 100644 index 00000000..d572a4cd --- /dev/null +++ b/code/opus-1.0.2/silk/float/process_gains_FLP.c @@ -0,0 +1,103 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" +#include "tuning_parameters.h" + +/* Processing of gains */ +void silk_process_gains_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + silk_shape_state_FLP *psShapeSt = &psEnc->sShape; + opus_int k; + opus_int32 pGains_Q16[ MAX_NB_SUBFR ]; + silk_float s, InvMaxSqrVal, gain, quant_offset; + + /* Gain reduction when LTP coding gain is high */ + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + s = 1.0f - 0.5f * silk_sigmoid( 0.25f * ( psEncCtrl->LTPredCodGain - 12.0f ) ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->Gains[ k ] *= s; + } + } + + /* Limit the quantized signal */ + InvMaxSqrVal = ( silk_float )( pow( 2.0f, 0.33f * ( 21.0f - psEnc->sCmn.SNR_dB_Q7 * ( 1 / 128.0f ) ) ) / psEnc->sCmn.subfr_length ); + + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + /* Soft limit on ratio residual energy and squared gains */ + gain = psEncCtrl->Gains[ k ]; + gain = ( silk_float )sqrt( gain * gain + psEncCtrl->ResNrg[ k ] * InvMaxSqrVal ); + psEncCtrl->Gains[ k ] = silk_min_float( gain, 32767.0f ); + } + + /* Prepare gains for noise shaping quantization */ + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + pGains_Q16[ k ] = (opus_int32)( psEncCtrl->Gains[ k ] * 65536.0f ); + } + + /* Save unquantized gains and gain Index */ + silk_memcpy( psEncCtrl->GainsUnq_Q16, pGains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) ); + psEncCtrl->lastGainIndexPrev = psShapeSt->LastGainIndex; + + /* Quantize gains */ + silk_gains_quant( psEnc->sCmn.indices.GainsIndices, pGains_Q16, + &psShapeSt->LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr ); + + /* Overwrite unquantized gains with quantized gains and convert back to Q0 from Q16 */ + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->Gains[ k ] = pGains_Q16[ k ] / 65536.0f; + } + + /* Set quantizer offset for voiced signals. Larger offset when LTP coding gain is low or tilt is high (ie low-pass) */ + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + if( psEncCtrl->LTPredCodGain + psEnc->sCmn.input_tilt_Q15 * ( 1.0f / 32768.0f ) > 1.0f ) { + psEnc->sCmn.indices.quantOffsetType = 0; + } else { + psEnc->sCmn.indices.quantOffsetType = 1; + } + } + + /* Quantizer boundary adjustment */ + quant_offset = silk_Quantization_Offsets_Q10[ psEnc->sCmn.indices.signalType >> 1 ][ psEnc->sCmn.indices.quantOffsetType ] / 1024.0f; + psEncCtrl->Lambda = LAMBDA_OFFSET + + LAMBDA_DELAYED_DECISIONS * psEnc->sCmn.nStatesDelayedDecision + + LAMBDA_SPEECH_ACT * psEnc->sCmn.speech_activity_Q8 * ( 1.0f / 256.0f ) + + LAMBDA_INPUT_QUALITY * psEncCtrl->input_quality + + LAMBDA_CODING_QUALITY * psEncCtrl->coding_quality + + LAMBDA_QUANT_OFFSET * quant_offset; + + silk_assert( psEncCtrl->Lambda > 0.0f ); + silk_assert( psEncCtrl->Lambda < 2.0f ); +} diff --git a/code/opus-1.0.2/silk/float/regularize_correlations_FLP.c b/code/opus-1.0.2/silk/float/regularize_correlations_FLP.c new file mode 100644 index 00000000..f5684637 --- /dev/null +++ b/code/opus-1.0.2/silk/float/regularize_correlations_FLP.c @@ -0,0 +1,48 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" + +/* Add noise to matrix diagonal */ +void silk_regularize_correlations_FLP( + silk_float *XX, /* I/O Correlation matrices */ + silk_float *xx, /* I/O Correlation values */ + const silk_float noise, /* I Noise energy to add */ + const opus_int D /* I Dimension of XX */ +) +{ + opus_int i; + + for( i = 0; i < D; i++ ) { + matrix_ptr( &XX[ 0 ], i, i, D ) += noise; + } + xx[ 0 ] += noise; +} diff --git a/code/opus-1.0.2/silk/float/residual_energy_FLP.c b/code/opus-1.0.2/silk/float/residual_energy_FLP.c new file mode 100644 index 00000000..e65457ab --- /dev/null +++ b/code/opus-1.0.2/silk/float/residual_energy_FLP.c @@ -0,0 +1,117 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" + +#define MAX_ITERATIONS_RESIDUAL_NRG 10 +#define REGULARIZATION_FACTOR 1e-8f + +/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */ +silk_float silk_residual_energy_covar_FLP( /* O Weighted residual energy */ + const silk_float *c, /* I Filter coefficients */ + silk_float *wXX, /* I/O Weighted correlation matrix, reg. out */ + const silk_float *wXx, /* I Weighted correlation vector */ + const silk_float wxx, /* I Weighted correlation value */ + const opus_int D /* I Dimension */ +) +{ + opus_int i, j, k; + silk_float tmp, nrg = 0.0f, regularization; + + /* Safety checks */ + silk_assert( D >= 0 ); + + regularization = REGULARIZATION_FACTOR * ( wXX[ 0 ] + wXX[ D * D - 1 ] ); + for( k = 0; k < MAX_ITERATIONS_RESIDUAL_NRG; k++ ) { + nrg = wxx; + + tmp = 0.0f; + for( i = 0; i < D; i++ ) { + tmp += wXx[ i ] * c[ i ]; + } + nrg -= 2.0f * tmp; + + /* compute c' * wXX * c, assuming wXX is symmetric */ + for( i = 0; i < D; i++ ) { + tmp = 0.0f; + for( j = i + 1; j < D; j++ ) { + tmp += matrix_c_ptr( wXX, i, j, D ) * c[ j ]; + } + nrg += c[ i ] * ( 2.0f * tmp + matrix_c_ptr( wXX, i, i, D ) * c[ i ] ); + } + if( nrg > 0 ) { + break; + } else { + /* Add white noise */ + for( i = 0; i < D; i++ ) { + matrix_c_ptr( wXX, i, i, D ) += regularization; + } + /* Increase noise for next run */ + regularization *= 2.0f; + } + } + if( k == MAX_ITERATIONS_RESIDUAL_NRG ) { + silk_assert( nrg == 0 ); + nrg = 1.0f; + } + + return nrg; +} + +/* Calculates residual energies of input subframes where all subframes have LPC_order */ +/* of preceding samples */ +void silk_residual_energy_FLP( + silk_float nrgs[ MAX_NB_SUBFR ], /* O Residual energy per subframe */ + const silk_float x[], /* I Input signal */ + silk_float a[ 2 ][ MAX_LPC_ORDER ], /* I AR coefs for each frame half */ + const silk_float gains[], /* I Quantization gains */ + const opus_int subfr_length, /* I Subframe length */ + const opus_int nb_subfr, /* I number of subframes */ + const opus_int LPC_order /* I LPC order */ +) +{ + opus_int shift; + silk_float *LPC_res_ptr, LPC_res[ ( MAX_FRAME_LENGTH + MAX_NB_SUBFR * MAX_LPC_ORDER ) / 2 ]; + + LPC_res_ptr = LPC_res + LPC_order; + shift = LPC_order + subfr_length; + + /* Filter input to create the LPC residual for each frame half, and measure subframe energies */ + silk_LPC_analysis_filter_FLP( LPC_res, a[ 0 ], x + 0 * shift, 2 * shift, LPC_order ); + nrgs[ 0 ] = ( silk_float )( gains[ 0 ] * gains[ 0 ] * silk_energy_FLP( LPC_res_ptr + 0 * shift, subfr_length ) ); + nrgs[ 1 ] = ( silk_float )( gains[ 1 ] * gains[ 1 ] * silk_energy_FLP( LPC_res_ptr + 1 * shift, subfr_length ) ); + + if( nb_subfr == MAX_NB_SUBFR ) { + silk_LPC_analysis_filter_FLP( LPC_res, a[ 1 ], x + 2 * shift, 2 * shift, LPC_order ); + nrgs[ 2 ] = ( silk_float )( gains[ 2 ] * gains[ 2 ] * silk_energy_FLP( LPC_res_ptr + 0 * shift, subfr_length ) ); + nrgs[ 3 ] = ( silk_float )( gains[ 3 ] * gains[ 3 ] * silk_energy_FLP( LPC_res_ptr + 1 * shift, subfr_length ) ); + } +} diff --git a/code/opus-1.0.2/silk/float/scale_copy_vector_FLP.c b/code/opus-1.0.2/silk/float/scale_copy_vector_FLP.c new file mode 100644 index 00000000..988795a6 --- /dev/null +++ b/code/opus-1.0.2/silk/float/scale_copy_vector_FLP.c @@ -0,0 +1,57 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FLP.h" + +/* copy and multiply a vector by a constant */ +void silk_scale_copy_vector_FLP( + silk_float *data_out, + const silk_float *data_in, + silk_float gain, + opus_int dataSize +) +{ + opus_int i, dataSize4; + + /* 4x unrolled loop */ + dataSize4 = dataSize & 0xFFFC; + for( i = 0; i < dataSize4; i += 4 ) { + data_out[ i + 0 ] = gain * data_in[ i + 0 ]; + data_out[ i + 1 ] = gain * data_in[ i + 1 ]; + data_out[ i + 2 ] = gain * data_in[ i + 2 ]; + data_out[ i + 3 ] = gain * data_in[ i + 3 ]; + } + + /* any remaining elements */ + for( ; i < dataSize; i++ ) { + data_out[ i ] = gain * data_in[ i ]; + } +} diff --git a/code/opus-1.0.2/silk/float/scale_vector_FLP.c b/code/opus-1.0.2/silk/float/scale_vector_FLP.c new file mode 100644 index 00000000..387eb4ba --- /dev/null +++ b/code/opus-1.0.2/silk/float/scale_vector_FLP.c @@ -0,0 +1,56 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FLP.h" + +/* multiply a vector by a constant */ +void silk_scale_vector_FLP( + silk_float *data1, + silk_float gain, + opus_int dataSize +) +{ + opus_int i, dataSize4; + + /* 4x unrolled loop */ + dataSize4 = dataSize & 0xFFFC; + for( i = 0; i < dataSize4; i += 4 ) { + data1[ i + 0 ] *= gain; + data1[ i + 1 ] *= gain; + data1[ i + 2 ] *= gain; + data1[ i + 3 ] *= gain; + } + + /* any remaining elements */ + for( ; i < dataSize; i++ ) { + data1[ i ] *= gain; + } +} diff --git a/code/opus-1.0.2/silk/float/schur_FLP.c b/code/opus-1.0.2/silk/float/schur_FLP.c new file mode 100644 index 00000000..90c3a18b --- /dev/null +++ b/code/opus-1.0.2/silk/float/schur_FLP.c @@ -0,0 +1,70 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FLP.h" + +silk_float silk_schur_FLP( /* O returns residual energy */ + silk_float refl_coef[], /* O reflection coefficients (length order) */ + const silk_float auto_corr[], /* I autocorrelation sequence (length order+1) */ + opus_int order /* I order */ +) +{ + opus_int k, n; + silk_float C[ SILK_MAX_ORDER_LPC + 1 ][ 2 ]; + silk_float Ctmp1, Ctmp2, rc_tmp; + + silk_assert( order==6||order==8||order==10||order==12||order==14||order==16 ); + + /* Copy correlations */ + for( k = 0; k < order+1; k++ ) { + C[ k ][ 0 ] = C[ k ][ 1 ] = auto_corr[ k ]; + } + + for( k = 0; k < order; k++ ) { + /* Get reflection coefficient */ + rc_tmp = -C[ k + 1 ][ 0 ] / silk_max_float( C[ 0 ][ 1 ], 1e-9f ); + + /* Save the output */ + refl_coef[ k ] = rc_tmp; + + /* Update correlations */ + for( n = 0; n < order - k; n++ ) { + Ctmp1 = C[ n + k + 1 ][ 0 ]; + Ctmp2 = C[ n ][ 1 ]; + C[ n + k + 1 ][ 0 ] = Ctmp1 + Ctmp2 * rc_tmp; + C[ n ][ 1 ] = Ctmp2 + Ctmp1 * rc_tmp; + } + } + + /* Return residual energy */ + return C[ 0 ][ 1 ]; +} + diff --git a/code/opus-1.0.2/silk/float/solve_LS_FLP.c b/code/opus-1.0.2/silk/float/solve_LS_FLP.c new file mode 100644 index 00000000..a4bb0525 --- /dev/null +++ b/code/opus-1.0.2/silk/float/solve_LS_FLP.c @@ -0,0 +1,207 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" +#include "tuning_parameters.h" + +/********************************************************************** + * LDL Factorisation. Finds the upper triangular matrix L and the diagonal + * Matrix D (only the diagonal elements returned in a vector)such that + * the symmetric matric A is given by A = L*D*L'. + **********************************************************************/ +static inline void silk_LDL_FLP( + silk_float *A, /* I/O Pointer to Symetric Square Matrix */ + opus_int M, /* I Size of Matrix */ + silk_float *L, /* I/O Pointer to Square Upper triangular Matrix */ + silk_float *Dinv /* I/O Pointer to vector holding the inverse diagonal elements of D */ +); + +/********************************************************************** + * Function to solve linear equation Ax = b, when A is a MxM lower + * triangular matrix, with ones on the diagonal. + **********************************************************************/ +static inline void silk_SolveWithLowerTriangularWdiagOnes_FLP( + const silk_float *L, /* I Pointer to Lower Triangular Matrix */ + opus_int M, /* I Dim of Matrix equation */ + const silk_float *b, /* I b Vector */ + silk_float *x /* O x Vector */ +); + +/********************************************************************** + * Function to solve linear equation (A^T)x = b, when A is a MxM lower + * triangular, with ones on the diagonal. (ie then A^T is upper triangular) + **********************************************************************/ +static inline void silk_SolveWithUpperTriangularFromLowerWdiagOnes_FLP( + const silk_float *L, /* I Pointer to Lower Triangular Matrix */ + opus_int M, /* I Dim of Matrix equation */ + const silk_float *b, /* I b Vector */ + silk_float *x /* O x Vector */ +); + +/********************************************************************** + * Function to solve linear equation Ax = b, when A is a MxM + * symmetric square matrix - using LDL factorisation + **********************************************************************/ +void silk_solve_LDL_FLP( + silk_float *A, /* I/O Symmetric square matrix, out: reg. */ + const opus_int M, /* I Size of matrix */ + const silk_float *b, /* I Pointer to b vector */ + silk_float *x /* O Pointer to x solution vector */ +) +{ + opus_int i; + silk_float L[ MAX_MATRIX_SIZE ][ MAX_MATRIX_SIZE ]; + silk_float T[ MAX_MATRIX_SIZE ]; + silk_float Dinv[ MAX_MATRIX_SIZE ]; /* inverse diagonal elements of D*/ + + silk_assert( M <= MAX_MATRIX_SIZE ); + + /*************************************************** + Factorize A by LDL such that A = L*D*(L^T), + where L is lower triangular with ones on diagonal + ****************************************************/ + silk_LDL_FLP( A, M, &L[ 0 ][ 0 ], Dinv ); + + /**************************************************** + * substitute D*(L^T) = T. ie: + L*D*(L^T)*x = b => L*T = b <=> T = inv(L)*b + ******************************************************/ + silk_SolveWithLowerTriangularWdiagOnes_FLP( &L[ 0 ][ 0 ], M, b, T ); + + /**************************************************** + D*(L^T)*x = T <=> (L^T)*x = inv(D)*T, because D is + diagonal just multiply with 1/d_i + ****************************************************/ + for( i = 0; i < M; i++ ) { + T[ i ] = T[ i ] * Dinv[ i ]; + } + /**************************************************** + x = inv(L') * inv(D) * T + *****************************************************/ + silk_SolveWithUpperTriangularFromLowerWdiagOnes_FLP( &L[ 0 ][ 0 ], M, T, x ); +} + +static inline void silk_SolveWithUpperTriangularFromLowerWdiagOnes_FLP( + const silk_float *L, /* I Pointer to Lower Triangular Matrix */ + opus_int M, /* I Dim of Matrix equation */ + const silk_float *b, /* I b Vector */ + silk_float *x /* O x Vector */ +) +{ + opus_int i, j; + silk_float temp; + const silk_float *ptr1; + + for( i = M - 1; i >= 0; i-- ) { + ptr1 = matrix_adr( L, 0, i, M ); + temp = 0; + for( j = M - 1; j > i ; j-- ) { + temp += ptr1[ j * M ] * x[ j ]; + } + temp = b[ i ] - temp; + x[ i ] = temp; + } +} + +static inline void silk_SolveWithLowerTriangularWdiagOnes_FLP( + const silk_float *L, /* I Pointer to Lower Triangular Matrix */ + opus_int M, /* I Dim of Matrix equation */ + const silk_float *b, /* I b Vector */ + silk_float *x /* O x Vector */ +) +{ + opus_int i, j; + silk_float temp; + const silk_float *ptr1; + + for( i = 0; i < M; i++ ) { + ptr1 = matrix_adr( L, i, 0, M ); + temp = 0; + for( j = 0; j < i; j++ ) { + temp += ptr1[ j ] * x[ j ]; + } + temp = b[ i ] - temp; + x[ i ] = temp; + } +} + +static inline void silk_LDL_FLP( + silk_float *A, /* I/O Pointer to Symetric Square Matrix */ + opus_int M, /* I Size of Matrix */ + silk_float *L, /* I/O Pointer to Square Upper triangular Matrix */ + silk_float *Dinv /* I/O Pointer to vector holding the inverse diagonal elements of D */ +) +{ + opus_int i, j, k, loop_count, err = 1; + silk_float *ptr1, *ptr2; + double temp, diag_min_value; + silk_float v[ MAX_MATRIX_SIZE ], D[ MAX_MATRIX_SIZE ]; /* temp arrays*/ + + silk_assert( M <= MAX_MATRIX_SIZE ); + + diag_min_value = FIND_LTP_COND_FAC * 0.5f * ( A[ 0 ] + A[ M * M - 1 ] ); + for( loop_count = 0; loop_count < M && err == 1; loop_count++ ) { + err = 0; + for( j = 0; j < M; j++ ) { + ptr1 = matrix_adr( L, j, 0, M ); + temp = matrix_ptr( A, j, j, M ); /* element in row j column j*/ + for( i = 0; i < j; i++ ) { + v[ i ] = ptr1[ i ] * D[ i ]; + temp -= ptr1[ i ] * v[ i ]; + } + if( temp < diag_min_value ) { + /* Badly conditioned matrix: add white noise and run again */ + temp = ( loop_count + 1 ) * diag_min_value - temp; + for( i = 0; i < M; i++ ) { + matrix_ptr( A, i, i, M ) += ( silk_float )temp; + } + err = 1; + break; + } + D[ j ] = ( silk_float )temp; + Dinv[ j ] = ( silk_float )( 1.0f / temp ); + matrix_ptr( L, j, j, M ) = 1.0f; + + ptr1 = matrix_adr( A, j, 0, M ); + ptr2 = matrix_adr( L, j + 1, 0, M); + for( i = j + 1; i < M; i++ ) { + temp = 0.0; + for( k = 0; k < j; k++ ) { + temp += ptr2[ k ] * v[ k ]; + } + matrix_ptr( L, i, j, M ) = ( silk_float )( ( ptr1[ i ] - temp ) * Dinv[ j ] ); + ptr2 += M; /* go to next column*/ + } + } + } + silk_assert( err == 0 ); +} + diff --git a/code/opus-1.0.2/silk/float/sort_FLP.c b/code/opus-1.0.2/silk/float/sort_FLP.c new file mode 100644 index 00000000..e290c380 --- /dev/null +++ b/code/opus-1.0.2/silk/float/sort_FLP.c @@ -0,0 +1,83 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* 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 "typedef.h" +#include "SigProc_FLP.h" + +void silk_insertion_sort_decreasing_FLP( + silk_float *a, /* I/O Unsorted / Sorted vector */ + opus_int *idx, /* O Index vector for the sorted elements */ + const opus_int L, /* I Vector length */ + const opus_int K /* I Number of correctly sorted positions */ +) +{ + silk_float value; + opus_int i, j; + + /* Safety checks */ + silk_assert( K > 0 ); + silk_assert( L > 0 ); + silk_assert( L >= K ); + + /* Write start indices in index vector */ + for( i = 0; i < K; i++ ) { + idx[ 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 */ + idx[ j + 1 ] = idx[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + idx[ j + 1 ] = i; /* Write index */ + } + + /* If less than L values are asked check the remaining values, */ + /* but only spend CPU to ensure that the K first values are correct */ + for( i = K; i < L; i++ ) { + value = a[ i ]; + if( value > a[ K - 1 ] ) { + for( j = K - 2; ( j >= 0 ) && ( value > a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + idx[ j + 1 ] = idx[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + idx[ j + 1 ] = i; /* Write index */ + } + } +} diff --git a/code/opus-1.0.2/silk/float/structs_FLP.h b/code/opus-1.0.2/silk/float/structs_FLP.h new file mode 100644 index 00000000..c71e7bc3 --- /dev/null +++ b/code/opus-1.0.2/silk/float/structs_FLP.h @@ -0,0 +1,131 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (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 SILK_STRUCTS_FLP_H +#define SILK_STRUCTS_FLP_H + +#include "typedef.h" +#include "main.h" +#include "structs.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************/ +/* Noise shaping analysis state */ +/********************************/ +typedef struct { + opus_int8 LastGainIndex; + silk_float HarmBoost_smth; + silk_float HarmShapeGain_smth; + silk_float Tilt_smth; +} silk_shape_state_FLP; + +/********************************/ +/* Prefilter state */ +/********************************/ +typedef struct { + silk_float sLTP_shp[ LTP_BUF_LENGTH ]; + silk_float sAR_shp[ MAX_SHAPE_LPC_ORDER + 1 ]; + opus_int sLTP_shp_buf_idx; + silk_float sLF_AR_shp; + silk_float sLF_MA_shp; + silk_float sHarmHP; + opus_int32 rand_seed; + opus_int lagPrev; +} silk_prefilter_state_FLP; + +/********************************/ +/* Encoder state FLP */ +/********************************/ +typedef struct { + silk_encoder_state sCmn; /* Common struct, shared with fixed-point code */ + silk_shape_state_FLP sShape; /* Noise shaping state */ + silk_prefilter_state_FLP sPrefilt; /* Prefilter State */ + + /* Buffer for find pitch and noise shape analysis */ + silk_float x_buf[ 2 * MAX_FRAME_LENGTH + LA_SHAPE_MAX ];/* Buffer for find pitch and noise shape analysis */ + silk_float LTPCorr; /* Normalized correlation from pitch lag estimator */ +} silk_encoder_state_FLP; + +/************************/ +/* Encoder control FLP */ +/************************/ +typedef struct { + /* Prediction and coding parameters */ + silk_float Gains[ MAX_NB_SUBFR ]; + silk_float PredCoef[ 2 ][ MAX_LPC_ORDER ]; /* holds interpolated and final coefficients */ + silk_float LTPCoef[LTP_ORDER * MAX_NB_SUBFR]; + silk_float LTP_scale; + opus_int pitchL[ MAX_NB_SUBFR ]; + + /* Noise shaping parameters */ + silk_float AR1[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ]; + silk_float AR2[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ]; + silk_float LF_MA_shp[ MAX_NB_SUBFR ]; + silk_float LF_AR_shp[ MAX_NB_SUBFR ]; + silk_float GainsPre[ MAX_NB_SUBFR ]; + silk_float HarmBoost[ MAX_NB_SUBFR ]; + silk_float Tilt[ MAX_NB_SUBFR ]; + silk_float HarmShapeGain[ MAX_NB_SUBFR ]; + silk_float Lambda; + silk_float input_quality; + silk_float coding_quality; + + /* Measures */ + silk_float sparseness; + silk_float predGain; + silk_float LTPredCodGain; + silk_float ResNrg[ MAX_NB_SUBFR ]; /* Residual energy per subframe */ + + /* Parameters for CBR mode */ + opus_int32 GainsUnq_Q16[ MAX_NB_SUBFR ]; + opus_int8 lastGainIndexPrev; +} silk_encoder_control_FLP; + +/************************/ +/* Encoder Super Struct */ +/************************/ +typedef struct { + silk_encoder_state_FLP state_Fxx[ ENCODER_NUM_CHANNELS ]; + stereo_enc_state sStereo; + opus_int32 nBitsExceeded; + opus_int nChannelsAPI; + opus_int nChannelsInternal; + opus_int nPrevChannelsInternal; + opus_int timeSinceSwitchAllowed_ms; + opus_int allowBandwidthSwitch; + opus_int prev_decode_only_middle; +} silk_encoder; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/code/opus-1.0.2/silk/float/warped_autocorrelation_FLP.c b/code/opus-1.0.2/silk/float/warped_autocorrelation_FLP.c new file mode 100644 index 00000000..e9ecc2a3 --- /dev/null +++ b/code/opus-1.0.2/silk/float/warped_autocorrelation_FLP.c @@ -0,0 +1,73 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" + +/* Autocorrelations for a warped frequency axis */ +void silk_warped_autocorrelation_FLP( + silk_float *corr, /* O Result [order + 1] */ + const silk_float *input, /* I Input data to correlate */ + const silk_float warping, /* I Warping coefficient */ + const opus_int length, /* I Length of input */ + const opus_int order /* I Correlation order (even) */ +) +{ + opus_int n, i; + double tmp1, tmp2; + double state[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; + double C[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; + + /* Order must be even */ + silk_assert( ( order & 1 ) == 0 ); + + /* Loop over samples */ + for( n = 0; n < length; n++ ) { + tmp1 = input[ n ]; + /* Loop over allpass sections */ + for( i = 0; i < order; i += 2 ) { + /* Output of allpass section */ + tmp2 = state[ i ] + warping * ( state[ i + 1 ] - tmp1 ); + state[ i ] = tmp1; + C[ i ] += state[ 0 ] * tmp1; + /* Output of allpass section */ + tmp1 = state[ i + 1 ] + warping * ( state[ i + 2 ] - tmp2 ); + state[ i + 1 ] = tmp2; + C[ i + 1 ] += state[ 0 ] * tmp2; + } + state[ order ] = tmp1; + C[ order ] += state[ 0 ] * tmp1; + } + + /* Copy correlations in silk_float output format */ + for( i = 0; i < order + 1; i++ ) { + corr[ i ] = ( silk_float )C[ i ]; + } +} diff --git a/code/opus-1.0.2/silk/float/wrappers_FLP.c b/code/opus-1.0.2/silk/float/wrappers_FLP.c new file mode 100644 index 00000000..4259e90e --- /dev/null +++ b/code/opus-1.0.2/silk/float/wrappers_FLP.c @@ -0,0 +1,200 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main_FLP.h" + +/* Wrappers. Calls flp / fix code */ + +/* Convert AR filter coefficients to NLSF parameters */ +void silk_A2NLSF_FLP( + opus_int16 *NLSF_Q15, /* O NLSF vector [ LPC_order ] */ + const silk_float *pAR, /* I LPC coefficients [ LPC_order ] */ + const opus_int LPC_order /* I LPC order */ +) +{ + opus_int i; + opus_int32 a_fix_Q16[ MAX_LPC_ORDER ]; + + for( i = 0; i < LPC_order; i++ ) { + a_fix_Q16[ i ] = silk_float2int( pAR[ i ] * 65536.0f ); + } + + silk_A2NLSF( NLSF_Q15, a_fix_Q16, LPC_order ); +} + +/* Convert LSF parameters to AR prediction filter coefficients */ +void silk_NLSF2A_FLP( + silk_float *pAR, /* O LPC coefficients [ LPC_order ] */ + const opus_int16 *NLSF_Q15, /* I NLSF vector [ LPC_order ] */ + const opus_int LPC_order /* I LPC order */ +) +{ + opus_int i; + opus_int16 a_fix_Q12[ MAX_LPC_ORDER ]; + + silk_NLSF2A( a_fix_Q12, NLSF_Q15, LPC_order ); + + for( i = 0; i < LPC_order; i++ ) { + pAR[ i ] = ( silk_float )a_fix_Q12[ i ] * ( 1.0f / 4096.0f ); + } +} + +/******************************************/ +/* Floating-point NLSF processing wrapper */ +/******************************************/ +void silk_process_NLSFs_FLP( + silk_encoder_state *psEncC, /* I/O Encoder state */ + silk_float PredCoef[ 2 ][ MAX_LPC_ORDER ], /* O Prediction coefficients */ + opus_int16 NLSF_Q15[ MAX_LPC_ORDER ], /* I/O Normalized LSFs (quant out) (0 - (2^15-1)) */ + const opus_int16 prev_NLSF_Q15[ MAX_LPC_ORDER ] /* I Previous Normalized LSFs (0 - (2^15-1)) */ +) +{ + opus_int i, j; + opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ]; + + silk_process_NLSFs( psEncC, PredCoef_Q12, NLSF_Q15, prev_NLSF_Q15); + + for( j = 0; j < 2; j++ ) { + for( i = 0; i < psEncC->predictLPCOrder; i++ ) { + PredCoef[ j ][ i ] = ( silk_float )PredCoef_Q12[ j ][ i ] * ( 1.0f / 4096.0f ); + } + } +} + +/****************************************/ +/* Floating-point Silk NSQ wrapper */ +/****************************************/ +void silk_NSQ_wrapper_FLP( + silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */ + silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */ + SideInfoIndices *psIndices, /* I/O Quantization indices */ + silk_nsq_state *psNSQ, /* I/O Noise Shaping Quantzation state */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const silk_float x[] /* I Prefiltered input signal */ +) +{ + opus_int i, j; + opus_int32 x_Q3[ MAX_FRAME_LENGTH ]; + opus_int32 Gains_Q16[ MAX_NB_SUBFR ]; + silk_DWORD_ALIGN opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ]; + opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ]; + opus_int LTP_scale_Q14; + + /* Noise shaping parameters */ + opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ]; + opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ]; /* Packs two int16 coefficients per int32 value */ + opus_int Lambda_Q10; + opus_int Tilt_Q14[ MAX_NB_SUBFR ]; + opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ]; + + /* Convert control struct to fix control struct */ + /* Noise shape parameters */ + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + for( j = 0; j < psEnc->sCmn.shapingLPCOrder; j++ ) { + AR2_Q13[ i * MAX_SHAPE_LPC_ORDER + j ] = silk_float2int( psEncCtrl->AR2[ i * MAX_SHAPE_LPC_ORDER + j ] * 8192.0f ); + } + } + + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + LF_shp_Q14[ i ] = silk_LSHIFT32( silk_float2int( psEncCtrl->LF_AR_shp[ i ] * 16384.0f ), 16 ) | + (opus_uint16)silk_float2int( psEncCtrl->LF_MA_shp[ i ] * 16384.0f ); + Tilt_Q14[ i ] = (opus_int)silk_float2int( psEncCtrl->Tilt[ i ] * 16384.0f ); + HarmShapeGain_Q14[ i ] = (opus_int)silk_float2int( psEncCtrl->HarmShapeGain[ i ] * 16384.0f ); + } + Lambda_Q10 = ( opus_int )silk_float2int( psEncCtrl->Lambda * 1024.0f ); + + /* prediction and coding parameters */ + for( i = 0; i < psEnc->sCmn.nb_subfr * LTP_ORDER; i++ ) { + LTPCoef_Q14[ i ] = (opus_int16)silk_float2int( psEncCtrl->LTPCoef[ i ] * 16384.0f ); + } + + for( j = 0; j < 2; j++ ) { + for( i = 0; i < psEnc->sCmn.predictLPCOrder; i++ ) { + PredCoef_Q12[ j ][ i ] = (opus_int16)silk_float2int( psEncCtrl->PredCoef[ j ][ i ] * 4096.0f ); + } + } + + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + Gains_Q16[ i ] = silk_float2int( psEncCtrl->Gains[ i ] * 65536.0f ); + silk_assert( Gains_Q16[ i ] > 0 ); + } + + if( psIndices->signalType == TYPE_VOICED ) { + LTP_scale_Q14 = silk_LTPScales_table_Q14[ psIndices->LTP_scaleIndex ]; + } else { + LTP_scale_Q14 = 0; + } + + /* Convert input to fix */ + for( i = 0; i < psEnc->sCmn.frame_length; i++ ) { + x_Q3[ i ] = silk_float2int( 8.0f * x[ i ] ); + } + + /* Call NSQ */ + if( psEnc->sCmn.nStatesDelayedDecision > 1 || psEnc->sCmn.warping_Q16 > 0 ) { + silk_NSQ_del_dec( &psEnc->sCmn, psNSQ, psIndices, x_Q3, pulses, PredCoef_Q12[ 0 ], LTPCoef_Q14, + AR2_Q13, HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, psEncCtrl->pitchL, Lambda_Q10, LTP_scale_Q14 ); + } else { + silk_NSQ( &psEnc->sCmn, psNSQ, psIndices, x_Q3, pulses, PredCoef_Q12[ 0 ], LTPCoef_Q14, + AR2_Q13, HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, psEncCtrl->pitchL, Lambda_Q10, LTP_scale_Q14 ); + } +} + +/***********************************************/ +/* Floating-point Silk LTP quantiation wrapper */ +/***********************************************/ +void silk_quant_LTP_gains_FLP( + silk_float B[ MAX_NB_SUBFR * LTP_ORDER ], /* I/O (Un-)quantized LTP gains */ + opus_int8 cbk_index[ MAX_NB_SUBFR ], /* O Codebook index */ + opus_int8 *periodicity_index, /* O Periodicity index */ + const silk_float W[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* I Error weights */ + const opus_int mu_Q10, /* I Mu value (R/D tradeoff) */ + const opus_int lowComplexity, /* I Flag for low complexity */ + const opus_int nb_subfr /* I number of subframes */ +) +{ + opus_int i; + opus_int16 B_Q14[ MAX_NB_SUBFR * LTP_ORDER ]; + opus_int32 W_Q18[ MAX_NB_SUBFR*LTP_ORDER*LTP_ORDER ]; + + for( i = 0; i < nb_subfr * LTP_ORDER; i++ ) { + B_Q14[ i ] = (opus_int16)silk_float2int( B[ i ] * 16384.0f ); + } + for( i = 0; i < nb_subfr * LTP_ORDER * LTP_ORDER; i++ ) { + W_Q18[ i ] = (opus_int32)silk_float2int( W[ i ] * 262144.0f ); + } + + silk_quant_LTP_gains( B_Q14, cbk_index, periodicity_index, W_Q18, mu_Q10, lowComplexity, nb_subfr ); + + for( i = 0; i < nb_subfr * LTP_ORDER; i++ ) { + B[ i ] = (silk_float)B_Q14[ i ] * ( 1.0f / 16384.0f ); + } +} diff --git a/code/opus-1.0.2/silk/gain_quant.c b/code/opus-1.0.2/silk/gain_quant.c new file mode 100644 index 00000000..b2f73735 --- /dev/null +++ b/code/opus-1.0.2/silk/gain_quant.c @@ -0,0 +1,141 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "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 silk_gains_quant( + opus_int8 ind[ MAX_NB_SUBFR ], /* O gain indices */ + opus_int32 gain_Q16[ MAX_NB_SUBFR ], /* I/O gains (quantized out) */ + opus_int8 *prev_ind, /* I/O last index in previous frame */ + const opus_int conditional, /* I first gain is delta coded if 1 */ + const opus_int nb_subfr /* I number of subframes */ +) +{ + opus_int k, double_step_size_threshold; + + for( k = 0; k < nb_subfr; k++ ) { + /* Convert to log scale, scale, floor() */ + ind[ k ] = silk_SMULWB( SCALE_Q16, silk_lin2log( gain_Q16[ k ] ) - OFFSET ); + + /* Round towards previous quantized gain (hysteresis) */ + if( ind[ k ] < *prev_ind ) { + ind[ k ]++; + } + ind[ k ] = silk_LIMIT_int( ind[ k ], 0, N_LEVELS_QGAIN - 1 ); + + /* Compute delta indices and limit */ + if( k == 0 && conditional == 0 ) { + /* Full index */ + ind[ k ] = silk_LIMIT_int( ind[ k ], *prev_ind + MIN_DELTA_GAIN_QUANT, N_LEVELS_QGAIN - 1 ); + *prev_ind = ind[ k ]; + } else { + /* Delta index */ + ind[ k ] = ind[ k ] - *prev_ind; + + /* Double the quantization step size for large gain increases, so that the max gain level can be reached */ + double_step_size_threshold = 2 * MAX_DELTA_GAIN_QUANT - N_LEVELS_QGAIN + *prev_ind; + if( ind[ k ] > double_step_size_threshold ) { + ind[ k ] = double_step_size_threshold + silk_RSHIFT( ind[ k ] - double_step_size_threshold + 1, 1 ); + } + + ind[ k ] = silk_LIMIT_int( ind[ k ], MIN_DELTA_GAIN_QUANT, MAX_DELTA_GAIN_QUANT ); + + /* Accumulate deltas */ + if( ind[ k ] > double_step_size_threshold ) { + *prev_ind += silk_LSHIFT( ind[ k ], 1 ) - double_step_size_threshold; + } else { + *prev_ind += ind[ k ]; + } + + /* Shift to make non-negative */ + ind[ k ] -= MIN_DELTA_GAIN_QUANT; + } + + /* Scale and convert to linear scale */ + gain_Q16[ k ] = silk_log2lin( silk_min_32( silk_SMULWB( INV_SCALE_Q16, *prev_ind ) + OFFSET, 3967 ) ); /* 3967 = 31 in Q7 */ + } +} + +/* Gains scalar dequantization, uniform on log scale */ +void silk_gains_dequant( + opus_int32 gain_Q16[ MAX_NB_SUBFR ], /* O quantized gains */ + const opus_int8 ind[ MAX_NB_SUBFR ], /* I gain indices */ + opus_int8 *prev_ind, /* I/O last index in previous frame */ + const opus_int conditional, /* I first gain is delta coded if 1 */ + const opus_int nb_subfr /* I number of subframes */ +) +{ + opus_int k, ind_tmp, double_step_size_threshold; + + for( k = 0; k < nb_subfr; k++ ) { + if( k == 0 && conditional == 0 ) { + /* Gain index is not allowed to go down more than 16 steps (~21.8 dB) */ + *prev_ind = silk_max_int( ind[ k ], *prev_ind - 16 ); + } else { + /* Delta index */ + ind_tmp = ind[ k ] + MIN_DELTA_GAIN_QUANT; + + /* Accumulate deltas */ + double_step_size_threshold = 2 * MAX_DELTA_GAIN_QUANT - N_LEVELS_QGAIN + *prev_ind; + if( ind_tmp > double_step_size_threshold ) { + *prev_ind += silk_LSHIFT( ind_tmp, 1 ) - double_step_size_threshold; + } else { + *prev_ind += ind_tmp; + } + } + *prev_ind = silk_LIMIT_int( *prev_ind, 0, N_LEVELS_QGAIN - 1 ); + + /* Scale and convert to linear scale */ + gain_Q16[ k ] = silk_log2lin( silk_min_32( silk_SMULWB( INV_SCALE_Q16, *prev_ind ) + OFFSET, 3967 ) ); /* 3967 = 31 in Q7 */ + } +} + +/* Compute unique identifier of gain indices vector */ +opus_int32 silk_gains_ID( /* O returns unique identifier of gains */ + const opus_int8 ind[ MAX_NB_SUBFR ], /* I gain indices */ + const opus_int nb_subfr /* I number of subframes */ +) +{ + opus_int k; + opus_int32 gainsID; + + gainsID = 0; + for( k = 0; k < nb_subfr; k++ ) { + gainsID = silk_ADD_LSHIFT32( ind[ k ], gainsID, 8 ); + } + + return gainsID; +} diff --git a/code/opus-1.0.2/silk/init_decoder.c b/code/opus-1.0.2/silk/init_decoder.c new file mode 100644 index 00000000..47834890 --- /dev/null +++ b/code/opus-1.0.2/silk/init_decoder.c @@ -0,0 +1,56 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/************************/ +/* Init Decoder State */ +/************************/ +opus_int silk_init_decoder( + silk_decoder_state *psDec /* I/O Decoder state pointer */ +) +{ + /* Clear the entire encoder state, except anything copied */ + silk_memset( psDec, 0, sizeof( silk_decoder_state ) ); + + /* Used to deactivate LSF interpolation */ + psDec->first_frame_after_reset = 1; + psDec->prev_gain_Q16 = 65536; + + /* Reset CNG state */ + silk_CNG_Reset( psDec ); + + /* Reset PLC state */ + silk_PLC_Reset( psDec ); + + return(0); +} + diff --git a/code/opus-1.0.2/silk/init_encoder.c b/code/opus-1.0.2/silk/init_encoder.c new file mode 100644 index 00000000..fe3fe968 --- /dev/null +++ b/code/opus-1.0.2/silk/init_encoder.c @@ -0,0 +1,60 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef FIXED_POINT +#include "main_FIX.h" +#else +#include "main_FLP.h" +#endif +#include "tuning_parameters.h" + +/*********************************/ +/* Initialize Silk Encoder state */ +/*********************************/ +opus_int silk_init_encoder( + silk_encoder_state_Fxx *psEnc /* I/O Pointer to Silk FIX encoder state */ +) +{ + opus_int ret = 0; + + /* Clear the entire encoder state */ + silk_memset( psEnc, 0, sizeof( silk_encoder_state_Fxx ) ); + + psEnc->sCmn.variable_HP_smth1_Q15 = silk_LSHIFT( silk_lin2log( SILK_FIX_CONST( VARIABLE_HP_MIN_CUTOFF_HZ, 16 ) ) - ( 16 << 7 ), 8 ); + psEnc->sCmn.variable_HP_smth2_Q15 = psEnc->sCmn.variable_HP_smth1_Q15; + + /* Used to deactivate LSF interpolation, pitch prediction */ + psEnc->sCmn.first_frame_after_reset = 1; + + /* Initialize Silk VAD */ + ret += silk_VAD_Init( &psEnc->sCmn.sVAD ); + + return ret; +} diff --git a/code/opus-1.0.2/silk/inner_prod_aligned.c b/code/opus-1.0.2/silk/inner_prod_aligned.c new file mode 100644 index 00000000..fe20a2b1 --- /dev/null +++ b/code/opus-1.0.2/silk/inner_prod_aligned.c @@ -0,0 +1,47 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +opus_int32 silk_inner_prod_aligned_scale( + const opus_int16 *const inVec1, /* I input vector 1 */ + const opus_int16 *const inVec2, /* I input vector 2 */ + const opus_int scale, /* I number of bits to shift */ + const opus_int len /* I vector lengths */ +) +{ + opus_int i; + opus_int32 sum = 0; + for( i = 0; i < len; i++ ) { + sum = silk_ADD_RSHIFT32( sum, silk_SMULBB( inVec1[ i ], inVec2[ i ] ), scale ); + } + return sum; +} diff --git a/code/opus-1.0.2/silk/interpolate.c b/code/opus-1.0.2/silk/interpolate.c new file mode 100644 index 00000000..226488b9 --- /dev/null +++ b/code/opus-1.0.2/silk/interpolate.c @@ -0,0 +1,51 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Interpolate two vectors */ +void silk_interpolate( + opus_int16 xi[ MAX_LPC_ORDER ], /* O interpolated vector */ + const opus_int16 x0[ MAX_LPC_ORDER ], /* I first vector */ + const opus_int16 x1[ MAX_LPC_ORDER ], /* I second vector */ + const opus_int ifact_Q2, /* I interp. factor, weight on 2nd vector */ + const opus_int d /* I number of parameters */ +) +{ + opus_int i; + + silk_assert( ifact_Q2 >= 0 ); + silk_assert( ifact_Q2 <= 4 ); + + for( i = 0; i < d; i++ ) { + xi[ i ] = (opus_int16)silk_ADD_RSHIFT( x0[ i ], silk_SMULBB( x1[ i ] - x0[ i ], ifact_Q2 ), 2 ); + } +} diff --git a/code/opus-1.0.2/silk/lin2log.c b/code/opus-1.0.2/silk/lin2log.c new file mode 100644 index 00000000..212b670d --- /dev/null +++ b/code/opus-1.0.2/silk/lin2log.c @@ -0,0 +1,46 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +/* Approximation of 128 * log2() (very close inverse of silk_log2lin()) */ +/* Convert input to a log scale */ +opus_int32 silk_lin2log( + const opus_int32 inLin /* I input in linear scale */ +) +{ + opus_int32 lz, frac_Q7; + + silk_CLZ_FRAC( inLin, &lz, &frac_Q7 ); + + /* Piece-wise parabolic approximation */ + return silk_LSHIFT( 31 - lz, 7 ) + silk_SMLAWB( frac_Q7, silk_MUL( frac_Q7, 128 - frac_Q7 ), 179 ); +} + diff --git a/code/opus-1.0.2/silk/log2lin.c b/code/opus-1.0.2/silk/log2lin.c new file mode 100644 index 00000000..33a19ad1 --- /dev/null +++ b/code/opus-1.0.2/silk/log2lin.c @@ -0,0 +1,56 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Approximation of 2^() (very close inverse of silk_lin2log()) */ +/* Convert input to a linear scale */ +opus_int32 silk_log2lin( + const opus_int32 inLog_Q7 /* I input on log scale */ +) +{ + opus_int32 out, frac_Q7; + + if( inLog_Q7 < 0 ) { + return 0; + } + + out = silk_LSHIFT( 1, silk_RSHIFT( inLog_Q7, 7 ) ); + frac_Q7 = inLog_Q7 & 0x7F; + if( inLog_Q7 < 2048 ) { + /* Piece-wise parabolic approximation */ + out = silk_ADD_RSHIFT32( out, silk_MUL( out, silk_SMLAWB( frac_Q7, silk_SMULBB( frac_Q7, 128 - frac_Q7 ), -174 ) ), 7 ); + } else { + /* Piece-wise parabolic approximation */ + out = silk_MLA( out, silk_RSHIFT( out, 7 ), silk_SMLAWB( frac_Q7, silk_SMULBB( frac_Q7, 128 - frac_Q7 ), -174 ) ); + } + return out; +} diff --git a/code/opus-1.0.2/silk/macros.h b/code/opus-1.0.2/silk/macros.h new file mode 100644 index 00000000..2612fc7a --- /dev/null +++ b/code/opus-1.0.2/silk/macros.h @@ -0,0 +1,135 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (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 SILK_MACROS_H +#define SILK_MACROS_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* This is an inline header file for general platform. */ + +/* (a32 * (opus_int32)((opus_int16)(b32))) >> 16 output have to be 32bit int */ +#define silk_SMULWB(a32, b32) ((((a32) >> 16) * (opus_int32)((opus_int16)(b32))) + ((((a32) & 0x0000FFFF) * (opus_int32)((opus_int16)(b32))) >> 16)) + +/* a32 + (b32 * (opus_int32)((opus_int16)(c32))) >> 16 output have to be 32bit int */ +#define silk_SMLAWB(a32, b32, c32) ((a32) + ((((b32) >> 16) * (opus_int32)((opus_int16)(c32))) + ((((b32) & 0x0000FFFF) * (opus_int32)((opus_int16)(c32))) >> 16))) + +/* (a32 * (b32 >> 16)) >> 16 */ +#define silk_SMULWT(a32, b32) (((a32) >> 16) * ((b32) >> 16) + ((((a32) & 0x0000FFFF) * ((b32) >> 16)) >> 16)) + +/* a32 + (b32 * (c32 >> 16)) >> 16 */ +#define silk_SMLAWT(a32, b32, c32) ((a32) + (((b32) >> 16) * ((c32) >> 16)) + ((((b32) & 0x0000FFFF) * ((c32) >> 16)) >> 16)) + +/* (opus_int32)((opus_int16)(a3))) * (opus_int32)((opus_int16)(b32)) output have to be 32bit int */ +#define silk_SMULBB(a32, b32) ((opus_int32)((opus_int16)(a32)) * (opus_int32)((opus_int16)(b32))) + +/* a32 + (opus_int32)((opus_int16)(b32)) * (opus_int32)((opus_int16)(c32)) output have to be 32bit int */ +#define silk_SMLABB(a32, b32, c32) ((a32) + ((opus_int32)((opus_int16)(b32))) * (opus_int32)((opus_int16)(c32))) + +/* (opus_int32)((opus_int16)(a32)) * (b32 >> 16) */ +#define silk_SMULBT(a32, b32) ((opus_int32)((opus_int16)(a32)) * ((b32) >> 16)) + +/* a32 + (opus_int32)((opus_int16)(b32)) * (c32 >> 16) */ +#define silk_SMLABT(a32, b32, c32) ((a32) + ((opus_int32)((opus_int16)(b32))) * ((c32) >> 16)) + +/* a64 + (b32 * c32) */ +#define silk_SMLAL(a64, b32, c32) (silk_ADD64((a64), ((opus_int64)(b32) * (opus_int64)(c32)))) + +/* (a32 * b32) >> 16 */ +#define silk_SMULWW(a32, b32) silk_MLA(silk_SMULWB((a32), (b32)), (a32), silk_RSHIFT_ROUND((b32), 16)) + +/* a32 + ((b32 * c32) >> 16) */ +#define silk_SMLAWW(a32, b32, c32) silk_MLA(silk_SMLAWB((a32), (b32), (c32)), (b32), silk_RSHIFT_ROUND((c32), 16)) + +/* add/subtract with output saturated */ +#define silk_ADD_SAT32(a, b) ((((opus_uint32)(a) + (opus_uint32)(b)) & 0x80000000) == 0 ? \ + ((((a) & (b)) & 0x80000000) != 0 ? silk_int32_MIN : (a)+(b)) : \ + ((((a) | (b)) & 0x80000000) == 0 ? silk_int32_MAX : (a)+(b)) ) + +#define silk_SUB_SAT32(a, b) ((((opus_uint32)(a)-(opus_uint32)(b)) & 0x80000000) == 0 ? \ + (( (a) & ((b)^0x80000000) & 0x80000000) ? silk_int32_MIN : (a)-(b)) : \ + ((((a)^0x80000000) & (b) & 0x80000000) ? silk_int32_MAX : (a)-(b)) ) + +static inline opus_int32 silk_CLZ16(opus_int16 in16) +{ + opus_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; + } +} + +static inline opus_int32 silk_CLZ32(opus_int32 in32) +{ + /* test highest 16 bits and convert to opus_int16 */ + if( in32 & 0xFFFF0000 ) { + return silk_CLZ16((opus_int16)(in32 >> 16)); + } else { + return silk_CLZ16((opus_int16)in32) + 16; + } +} + +/* 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 + +#endif /* SILK_MACROS_H */ + diff --git a/code/opus-1.0.2/silk/main.h b/code/opus-1.0.2/silk/main.h new file mode 100644 index 00000000..32675f69 --- /dev/null +++ b/code/opus-1.0.2/silk/main.h @@ -0,0 +1,434 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (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 SILK_MAIN_H +#define SILK_MAIN_H + +#include "SigProc_FIX.h" +#include "define.h" +#include "structs.h" +#include "tables.h" +#include "PLC.h" +#include "control.h" +#include "debug.h" +#include "entenc.h" +#include "entdec.h" + +/* Convert Left/Right stereo signal to adaptive Mid/Side representation */ +void silk_stereo_LR_to_MS( + stereo_enc_state *state, /* I/O State */ + opus_int16 x1[], /* I/O Left input signal, becomes mid signal */ + opus_int16 x2[], /* I/O Right input signal, becomes side signal */ + opus_int8 ix[ 2 ][ 3 ], /* O Quantization indices */ + opus_int8 *mid_only_flag, /* O Flag: only mid signal coded */ + opus_int32 mid_side_rates_bps[], /* O Bitrates for mid and side signals */ + opus_int32 total_rate_bps, /* I Total bitrate */ + opus_int prev_speech_act_Q8, /* I Speech activity level in previous frame */ + opus_int toMono, /* I Last frame before a stereo->mono transition */ + opus_int fs_kHz, /* I Sample rate (kHz) */ + opus_int frame_length /* I Number of samples */ +); + +/* Convert adaptive Mid/Side representation to Left/Right stereo signal */ +void silk_stereo_MS_to_LR( + stereo_dec_state *state, /* I/O State */ + opus_int16 x1[], /* I/O Left input signal, becomes mid signal */ + opus_int16 x2[], /* I/O Right input signal, becomes side signal */ + const opus_int32 pred_Q13[], /* I Predictors */ + opus_int fs_kHz, /* I Samples rate (kHz) */ + opus_int frame_length /* I Number of samples */ +); + +/* Find least-squares prediction gain for one signal based on another and quantize it */ +opus_int32 silk_stereo_find_predictor( /* O Returns predictor in Q13 */ + opus_int32 *ratio_Q14, /* O Ratio of residual and mid energies */ + const opus_int16 x[], /* I Basis signal */ + const opus_int16 y[], /* I Target signal */ + opus_int32 mid_res_amp_Q0[], /* I/O Smoothed mid, residual norms */ + opus_int length, /* I Number of samples */ + opus_int smooth_coef_Q16 /* I Smoothing coefficient */ +); + +/* Quantize mid/side predictors */ +void silk_stereo_quant_pred( + opus_int32 pred_Q13[], /* I/O Predictors (out: quantized) */ + opus_int8 ix[ 2 ][ 3 ] /* O Quantization indices */ +); + +/* Entropy code the mid/side quantization indices */ +void silk_stereo_encode_pred( + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int8 ix[ 2 ][ 3 ] /* I Quantization indices */ +); + +/* Entropy code the mid-only flag */ +void silk_stereo_encode_mid_only( + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int8 mid_only_flag +); + +/* Decode mid/side predictors */ +void silk_stereo_decode_pred( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int32 pred_Q13[] /* O Predictors */ +); + +/* Decode mid-only flag */ +void silk_stereo_decode_mid_only( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int *decode_only_mid /* O Flag that only mid channel has been coded */ +); + +/* Encodes signs of excitation */ +void silk_encode_signs( + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + const opus_int8 pulses[], /* I pulse signal */ + opus_int length, /* I length of input */ + const opus_int signalType, /* I Signal type */ + const opus_int quantOffsetType, /* I Quantization offset type */ + const opus_int sum_pulses[ MAX_NB_SHELL_BLOCKS ] /* I Sum of absolute pulses per block */ +); + +/* Decodes signs of excitation */ +void silk_decode_signs( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int pulses[], /* I/O pulse signal */ + opus_int length, /* I length of input */ + const opus_int signalType, /* I Signal type */ + const opus_int quantOffsetType, /* I Quantization offset type */ + const opus_int sum_pulses[ MAX_NB_SHELL_BLOCKS ] /* I Sum of absolute pulses per block */ +); + +/* Check encoder control struct */ +opus_int check_control_input( + silk_EncControlStruct *encControl /* I Control structure */ +); + +/* Control internal sampling rate */ +opus_int silk_control_audio_bandwidth( + silk_encoder_state *psEncC, /* I/O Pointer to Silk encoder state */ + silk_EncControlStruct *encControl /* I Control structure */ +); + +/* Control SNR of redidual quantizer */ +opus_int silk_control_SNR( + silk_encoder_state *psEncC, /* I/O Pointer to Silk encoder state */ + opus_int32 TargetRate_bps /* I Target max bitrate (bps) */ +); + +/***************/ +/* Shell coder */ +/***************/ + +/* Encode quantization indices of excitation */ +void silk_encode_pulses( + ec_enc *psRangeEnc, /* I/O compressor data structure */ + const opus_int signalType, /* I Signal type */ + const opus_int quantOffsetType, /* I quantOffsetType */ + opus_int8 pulses[], /* I quantization indices */ + const opus_int frame_length /* I Frame length */ +); + +/* Shell encoder, operates on one shell code frame of 16 pulses */ +void silk_shell_encoder( + ec_enc *psRangeEnc, /* I/O compressor data structure */ + const opus_int *pulses0 /* I data: nonnegative pulse amplitudes */ +); + +/* Shell decoder, operates on one shell code frame of 16 pulses */ +void silk_shell_decoder( + opus_int *pulses0, /* O data: nonnegative pulse amplitudes */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + const opus_int pulses4 /* I number of pulses per pulse-subframe */ +); + +/* Gain scalar quantization with hysteresis, uniform on log scale */ +void silk_gains_quant( + opus_int8 ind[ MAX_NB_SUBFR ], /* O gain indices */ + opus_int32 gain_Q16[ MAX_NB_SUBFR ], /* I/O gains (quantized out) */ + opus_int8 *prev_ind, /* I/O last index in previous frame */ + const opus_int conditional, /* I first gain is delta coded if 1 */ + const opus_int nb_subfr /* I number of subframes */ +); + +/* Gains scalar dequantization, uniform on log scale */ +void silk_gains_dequant( + opus_int32 gain_Q16[ MAX_NB_SUBFR ], /* O quantized gains */ + const opus_int8 ind[ MAX_NB_SUBFR ], /* I gain indices */ + opus_int8 *prev_ind, /* I/O last index in previous frame */ + const opus_int conditional, /* I first gain is delta coded if 1 */ + const opus_int nb_subfr /* I number of subframes */ +); + +/* Compute unique identifier of gain indices vector */ +opus_int32 silk_gains_ID( /* O returns unique identifier of gains */ + const opus_int8 ind[ MAX_NB_SUBFR ], /* I gain indices */ + const opus_int nb_subfr /* I number of subframes */ +); + +/* Interpolate two vectors */ +void silk_interpolate( + opus_int16 xi[ MAX_LPC_ORDER ], /* O interpolated vector */ + const opus_int16 x0[ MAX_LPC_ORDER ], /* I first vector */ + const opus_int16 x1[ MAX_LPC_ORDER ], /* I second vector */ + const opus_int ifact_Q2, /* I interp. factor, weight on 2nd vector */ + const opus_int d /* I number of parameters */ +); + +/* LTP tap quantizer */ +void silk_quant_LTP_gains( + opus_int16 B_Q14[ MAX_NB_SUBFR * LTP_ORDER ], /* I/O (un)quantized LTP gains */ + opus_int8 cbk_index[ MAX_NB_SUBFR ], /* O Codebook Index */ + opus_int8 *periodicity_index, /* O Periodicity Index */ + const opus_int32 W_Q18[ MAX_NB_SUBFR*LTP_ORDER*LTP_ORDER ], /* I Error Weights in Q18 */ + opus_int mu_Q9, /* I Mu value (R/D tradeoff) */ + opus_int lowComplexity, /* I Flag for low complexity */ + const opus_int nb_subfr /* I number of subframes */ +); + +/* Entropy constrained matrix-weighted VQ, for a single input data vector */ +void silk_VQ_WMat_EC( + opus_int8 *ind, /* O index of best codebook vector */ + opus_int32 *rate_dist_Q14, /* O best weighted quant error + mu * rate */ + const opus_int16 *in_Q14, /* I input vector to be quantized */ + const opus_int32 *W_Q18, /* I weighting matrix */ + const opus_int8 *cb_Q7, /* I codebook */ + const opus_uint8 *cl_Q5, /* I code length for each codebook vector */ + const opus_int mu_Q9, /* I tradeoff betw. weighted error and rate */ + opus_int L /* I number of vectors in codebook */ +); + +/************************************/ +/* Noise shaping quantization (NSQ) */ +/************************************/ +void silk_NSQ( + const silk_encoder_state *psEncC, /* I/O Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int32 x_Q3[], /* I Prefiltered input signal */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +); + +/* Noise shaping using delayed decision */ +void silk_NSQ_del_dec( + const silk_encoder_state *psEncC, /* I/O Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int32 x_Q3[], /* I Prefiltered input signal */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +); + +/************/ +/* Silk VAD */ +/************/ +/* Initialize the Silk VAD */ +opus_int silk_VAD_Init( /* O Return value, 0 if success */ + silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */ +); + +/* Get speech activity level in Q8 */ +opus_int silk_VAD_GetSA_Q8( /* O Return value, 0 if success */ + silk_encoder_state *psEncC, /* I/O Encoder state */ + const opus_int16 pIn[] /* I PCM input */ +); + +/* Low-pass filter with variable cutoff frequency based on */ +/* piece-wise linear interpolation between elliptic filters */ +/* Start by setting transition_frame_no = 1; */ +void silk_LP_variable_cutoff( + silk_LP_state *psLP, /* I/O LP filter state */ + opus_int16 *frame, /* I/O Low-pass filtered output signal */ + const opus_int frame_length /* I Frame length */ +); + +/******************/ +/* NLSF Quantizer */ +/******************/ +/* Limit, stabilize, convert and quantize NLSFs */ +void silk_process_NLSFs( + silk_encoder_state *psEncC, /* I/O Encoder state */ + opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ], /* O Prediction coefficients */ + opus_int16 pNLSF_Q15[ MAX_LPC_ORDER ], /* I/O Normalized LSFs (quant out) (0 - (2^15-1)) */ + const opus_int16 prev_NLSFq_Q15[ MAX_LPC_ORDER ] /* I Previous Normalized LSFs (0 - (2^15-1)) */ +); + +opus_int32 silk_NLSF_encode( /* O Returns RD value in Q25 */ + opus_int8 *NLSFIndices, /* I Codebook path vector [ LPC_ORDER + 1 ] */ + opus_int16 *pNLSF_Q15, /* I/O Quantized NLSF vector [ LPC_ORDER ] */ + const silk_NLSF_CB_struct *psNLSF_CB, /* I Codebook object */ + const opus_int16 *pW_QW, /* I NLSF weight vector [ LPC_ORDER ] */ + const opus_int NLSF_mu_Q20, /* I Rate weight for the RD optimization */ + const opus_int nSurvivors, /* I Max survivors after first stage */ + const opus_int signalType /* I Signal type: 0/1/2 */ +); + +/* Compute quantization errors for an LPC_order element input vector for a VQ codebook */ +void silk_NLSF_VQ( + opus_int32 err_Q26[], /* O Quantization errors [K] */ + const opus_int16 in_Q15[], /* I Input vectors to be quantized [LPC_order] */ + const opus_uint8 pCB_Q8[], /* I Codebook vectors [K*LPC_order] */ + const opus_int K, /* I Number of codebook vectors */ + const opus_int LPC_order /* I Number of LPCs */ +); + +/* Delayed-decision quantizer for NLSF residuals */ +opus_int32 silk_NLSF_del_dec_quant( /* O Returns RD value in Q25 */ + opus_int8 indices[], /* O Quantization indices [ order ] */ + const opus_int16 x_Q10[], /* I Input [ order ] */ + const opus_int16 w_Q5[], /* I Weights [ order ] */ + const opus_uint8 pred_coef_Q8[], /* I Backward predictor coefs [ order ] */ + const opus_int16 ec_ix[], /* I Indices to entropy coding tables [ order ] */ + const opus_uint8 ec_rates_Q5[], /* I Rates [] */ + const opus_int quant_step_size_Q16, /* I Quantization step size */ + const opus_int16 inv_quant_step_size_Q6, /* I Inverse quantization step size */ + const opus_int32 mu_Q20, /* I R/D tradeoff */ + const opus_int16 order /* I Number of input values */ +); + +/* Unpack predictor values and indices for entropy coding tables */ +void silk_NLSF_unpack( + opus_int16 ec_ix[], /* O Indices to entropy tables [ LPC_ORDER ] */ + opus_uint8 pred_Q8[], /* O LSF predictor [ LPC_ORDER ] */ + const silk_NLSF_CB_struct *psNLSF_CB, /* I Codebook object */ + const opus_int CB1_index /* I Index of vector in first LSF codebook */ +); + +/***********************/ +/* NLSF vector decoder */ +/***********************/ +void silk_NLSF_decode( + opus_int16 *pNLSF_Q15, /* O Quantized NLSF vector [ LPC_ORDER ] */ + opus_int8 *NLSFIndices, /* I Codebook path vector [ LPC_ORDER + 1 ] */ + const silk_NLSF_CB_struct *psNLSF_CB /* I Codebook object */ +); + +/****************************************************/ +/* Decoder Functions */ +/****************************************************/ +opus_int silk_init_decoder( + silk_decoder_state *psDec /* I/O Decoder state pointer */ +); + +/* Set decoder sampling rate */ +opus_int silk_decoder_set_fs( + silk_decoder_state *psDec, /* I/O Decoder state pointer */ + opus_int fs_kHz, /* I Sampling frequency (kHz) */ + opus_int32 fs_API_Hz /* I API Sampling frequency (Hz) */ +); + +/****************/ +/* Decode frame */ +/****************/ +opus_int silk_decode_frame( + silk_decoder_state *psDec, /* I/O Pointer to Silk decoder state */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int16 pOut[], /* O Pointer to output speech frame */ + opus_int32 *pN, /* O Pointer to size of output frame */ + opus_int lostFlag, /* I 0: no loss, 1 loss, 2 decode fec */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/* Decode indices from bitstream */ +void silk_decode_indices( + silk_decoder_state *psDec, /* I/O State */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int FrameIndex, /* I Frame number */ + opus_int decode_LBRR, /* I Flag indicating LBRR data is being decoded */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/* Decode parameters from payload */ +void silk_decode_parameters( + silk_decoder_state *psDec, /* I/O State */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/* Core decoder. Performs inverse NSQ operation LTP + LPC */ +void silk_decode_core( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I Decoder control */ + opus_int16 xq[], /* O Decoded speech */ + const opus_int pulses[ MAX_FRAME_LENGTH ] /* I Pulse signal */ +); + +/* Decode quantization indices of excitation (Shell coding) */ +void silk_decode_pulses( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int pulses[], /* O Excitation signal */ + const opus_int signalType, /* I Sigtype */ + const opus_int quantOffsetType, /* I quantOffsetType */ + const opus_int frame_length /* I Frame length */ +); + +/******************/ +/* CNG */ +/******************/ + +/* Reset CNG */ +void silk_CNG_Reset( + silk_decoder_state *psDec /* I/O Decoder state */ +); + +/* Updates CNG estimate, and applies the CNG when packet was lost */ +void silk_CNG( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int16 frame[], /* I/O Signal */ + opus_int length /* I Length of residual */ +); + +/* Encoding of various parameters */ +void silk_encode_indices( + silk_encoder_state *psEncC, /* I/O Encoder state */ + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int FrameIndex, /* I Frame number */ + opus_int encode_LBRR, /* I Flag indicating LBRR data is being encoded */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +#endif diff --git a/code/opus-1.0.2/silk/pitch_est_defines.h b/code/opus-1.0.2/silk/pitch_est_defines.h new file mode 100644 index 00000000..0b6770eb --- /dev/null +++ b/code/opus-1.0.2/silk/pitch_est_defines.h @@ -0,0 +1,88 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (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 SILK_PE_DEFINES_H +#define SILK_PE_DEFINES_H + +#include "SigProc_FIX.h" + +/********************************************************/ +/* Definitions for pitch estimator */ +/********************************************************/ + +#define PE_MAX_FS_KHZ 16 /* Maximum sampling frequency used */ + +#define PE_MAX_NB_SUBFR 4 +#define PE_SUBFR_LENGTH_MS 5 /* 5 ms */ + +#define PE_LTP_MEM_LENGTH_MS ( 4 * PE_SUBFR_LENGTH_MS ) + +#define PE_MAX_FRAME_LENGTH_MS ( PE_LTP_MEM_LENGTH_MS + PE_MAX_NB_SUBFR * PE_SUBFR_LENGTH_MS ) +#define PE_MAX_FRAME_LENGTH ( PE_MAX_FRAME_LENGTH_MS * PE_MAX_FS_KHZ ) +#define PE_MAX_FRAME_LENGTH_ST_1 ( PE_MAX_FRAME_LENGTH >> 2 ) +#define PE_MAX_FRAME_LENGTH_ST_2 ( PE_MAX_FRAME_LENGTH >> 1 ) + +#define PE_MAX_LAG_MS 18 /* 18 ms -> 56 Hz */ +#define PE_MIN_LAG_MS 2 /* 2 ms -> 500 Hz */ +#define PE_MAX_LAG ( PE_MAX_LAG_MS * PE_MAX_FS_KHZ ) +#define PE_MIN_LAG ( PE_MIN_LAG_MS * PE_MAX_FS_KHZ ) + +#define PE_D_SRCH_LENGTH 24 + +#define PE_NB_STAGE3_LAGS 5 + +#define PE_NB_CBKS_STAGE2 3 +#define PE_NB_CBKS_STAGE2_EXT 11 + +#define PE_NB_CBKS_STAGE3_MAX 34 +#define PE_NB_CBKS_STAGE3_MID 24 +#define PE_NB_CBKS_STAGE3_MIN 16 + +#define PE_NB_CBKS_STAGE3_10MS 12 +#define PE_NB_CBKS_STAGE2_10MS 3 + +#define PE_SHORTLAG_BIAS 0.2f /* for logarithmic weighting */ +#define PE_PREVLAG_BIAS 0.2f /* for logarithmic weighting */ +#define PE_FLATCONTOUR_BIAS 0.05f + +#define SILK_PE_MIN_COMPLEX 0 +#define SILK_PE_MID_COMPLEX 1 +#define SILK_PE_MAX_COMPLEX 2 + +/* Tables for 20 ms frames */ +extern const opus_int8 silk_CB_lags_stage2[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE2_EXT ]; +extern const opus_int8 silk_CB_lags_stage3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ]; +extern const opus_int8 silk_Lag_range_stage3[ SILK_PE_MAX_COMPLEX + 1 ] [ PE_MAX_NB_SUBFR ][ 2 ]; +extern const opus_int8 silk_nb_cbk_searchs_stage3[ SILK_PE_MAX_COMPLEX + 1 ]; + +/* Tables for 10 ms frames */ +extern const opus_int8 silk_CB_lags_stage2_10_ms[ PE_MAX_NB_SUBFR >> 1][ 3 ]; +extern const opus_int8 silk_CB_lags_stage3_10_ms[ PE_MAX_NB_SUBFR >> 1 ][ 12 ]; +extern const opus_int8 silk_Lag_range_stage3_10_ms[ PE_MAX_NB_SUBFR >> 1 ][ 2 ]; + +#endif + diff --git a/code/opus-1.0.2/silk/pitch_est_tables.c b/code/opus-1.0.2/silk/pitch_est_tables.c new file mode 100644 index 00000000..7b139ed2 --- /dev/null +++ b/code/opus-1.0.2/silk/pitch_est_tables.c @@ -0,0 +1,99 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "typedef.h" +#include "pitch_est_defines.h" + +const opus_int8 silk_CB_lags_stage2_10_ms[ PE_MAX_NB_SUBFR >> 1][ PE_NB_CBKS_STAGE2_10MS ] = +{ + {0, 1, 0}, + {0, 0, 1} +}; + +const opus_int8 silk_CB_lags_stage3_10_ms[ PE_MAX_NB_SUBFR >> 1 ][ PE_NB_CBKS_STAGE3_10MS ] = +{ + { 0, 0, 1,-1, 1,-1, 2,-2, 2,-2, 3,-3}, + { 0, 1, 0, 1,-1, 2,-1, 2,-2, 3,-2, 3} +}; + +const opus_int8 silk_Lag_range_stage3_10_ms[ PE_MAX_NB_SUBFR >> 1 ][ 2 ] = +{ + {-3, 7}, + {-2, 7} +}; + +const opus_int8 silk_CB_lags_stage2[ PE_MAX_NB_SUBFR ][ PE_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 opus_int8 silk_CB_lags_stage3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ] = +{ + {0, 0, 1,-1, 0, 1,-1, 0,-1, 1,-2, 2,-2,-2, 2,-3, 2, 3,-3,-4, 3,-4, 4, 4,-5, 5,-6,-5, 6,-7, 6, 5, 8,-9}, + {0, 0, 1, 0, 0, 0, 0, 0, 0, 0,-1, 1, 0, 0, 1,-1, 0, 1,-1,-1, 1,-1, 2, 1,-1, 2,-2,-2, 2,-2, 2, 2, 3,-3}, + {0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1,-1, 1, 0, 0, 2, 1,-1, 2,-1,-1, 2,-1, 2, 2,-1, 3,-2,-2,-2, 3}, + {0, 1, 0, 0, 1, 0, 1,-1, 2,-1, 2,-1, 2, 3,-2, 3,-2,-2, 4, 4,-3, 5,-3,-4, 6,-4, 6, 5,-5, 8,-6,-5,-7, 9} +}; + +const opus_int8 silk_Lag_range_stage3[ SILK_PE_MAX_COMPLEX + 1 ] [ PE_MAX_NB_SUBFR ][ 2 ] = +{ + /* Lags to search for low number of stage3 cbks */ + { + {-5,8}, + {-1,6}, + {-1,6}, + {-4,10} + }, + /* Lags to search for middle number of stage3 cbks */ + { + {-6,10}, + {-2,6}, + {-1,6}, + {-5,10} + }, + /* Lags to search for max number of stage3 cbks */ + { + {-9,12}, + {-3,7}, + {-2,7}, + {-7,13} + } +}; + +const opus_int8 silk_nb_cbk_searchs_stage3[ SILK_PE_MAX_COMPLEX + 1 ] = +{ + PE_NB_CBKS_STAGE3_MIN, + PE_NB_CBKS_STAGE3_MID, + PE_NB_CBKS_STAGE3_MAX +}; diff --git a/code/opus-1.0.2/silk/process_NLSFs.c b/code/opus-1.0.2/silk/process_NLSFs.c new file mode 100644 index 00000000..34ce7914 --- /dev/null +++ b/code/opus-1.0.2/silk/process_NLSFs.c @@ -0,0 +1,105 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Limit, stabilize, convert and quantize NLSFs */ +void silk_process_NLSFs( + silk_encoder_state *psEncC, /* I/O Encoder state */ + opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ], /* O Prediction coefficients */ + opus_int16 pNLSF_Q15[ MAX_LPC_ORDER ], /* I/O Normalized LSFs (quant out) (0 - (2^15-1)) */ + const opus_int16 prev_NLSFq_Q15[ MAX_LPC_ORDER ] /* I Previous Normalized LSFs (0 - (2^15-1)) */ +) +{ + opus_int i, doInterpolate; + opus_int NLSF_mu_Q20; + opus_int32 i_sqr_Q15; + opus_int16 pNLSF0_temp_Q15[ MAX_LPC_ORDER ]; + opus_int16 pNLSFW_QW[ MAX_LPC_ORDER ]; + opus_int16 pNLSFW0_temp_QW[ MAX_LPC_ORDER ]; + + silk_assert( psEncC->speech_activity_Q8 >= 0 ); + silk_assert( psEncC->speech_activity_Q8 <= SILK_FIX_CONST( 1.0, 8 ) ); + silk_assert( psEncC->useInterpolatedNLSFs == 1 || psEncC->indices.NLSFInterpCoef_Q2 == ( 1 << 2 ) ); + + /***********************/ + /* Calculate mu values */ + /***********************/ + /* NLSF_mu = 0.003 - 0.0015 * psEnc->speech_activity; */ + NLSF_mu_Q20 = silk_SMLAWB( SILK_FIX_CONST( 0.003, 20 ), SILK_FIX_CONST( -0.001, 28 ), psEncC->speech_activity_Q8 ); + if( psEncC->nb_subfr == 2 ) { + /* Multiply by 1.5 for 10 ms packets */ + NLSF_mu_Q20 = silk_ADD_RSHIFT( NLSF_mu_Q20, NLSF_mu_Q20, 1 ); + } + + silk_assert( NLSF_mu_Q20 > 0 ); + silk_assert( NLSF_mu_Q20 <= SILK_FIX_CONST( 0.005, 20 ) ); + + /* Calculate NLSF weights */ + silk_NLSF_VQ_weights_laroia( pNLSFW_QW, pNLSF_Q15, psEncC->predictLPCOrder ); + + /* Update NLSF weights for interpolated NLSFs */ + doInterpolate = ( psEncC->useInterpolatedNLSFs == 1 ) && ( psEncC->indices.NLSFInterpCoef_Q2 < 4 ); + if( doInterpolate ) { + /* Calculate the interpolated NLSF vector for the first half */ + silk_interpolate( pNLSF0_temp_Q15, prev_NLSFq_Q15, pNLSF_Q15, + psEncC->indices.NLSFInterpCoef_Q2, psEncC->predictLPCOrder ); + + /* Calculate first half NLSF weights for the interpolated NLSFs */ + silk_NLSF_VQ_weights_laroia( pNLSFW0_temp_QW, pNLSF0_temp_Q15, psEncC->predictLPCOrder ); + + /* Update NLSF weights with contribution from first half */ + i_sqr_Q15 = silk_LSHIFT( silk_SMULBB( psEncC->indices.NLSFInterpCoef_Q2, psEncC->indices.NLSFInterpCoef_Q2 ), 11 ); + for( i = 0; i < psEncC->predictLPCOrder; i++ ) { + pNLSFW_QW[ i ] = silk_SMLAWB( silk_RSHIFT( pNLSFW_QW[ i ], 1 ), (opus_int32)pNLSFW0_temp_QW[ i ], i_sqr_Q15 ); + silk_assert( pNLSFW_QW[ i ] >= 1 ); + } + } + + silk_NLSF_encode( psEncC->indices.NLSFIndices, pNLSF_Q15, psEncC->psNLSF_CB, pNLSFW_QW, + NLSF_mu_Q20, psEncC->NLSF_MSVQ_Survivors, psEncC->indices.signalType ); + + /* Convert quantized NLSFs back to LPC coefficients */ + silk_NLSF2A( PredCoef_Q12[ 1 ], pNLSF_Q15, psEncC->predictLPCOrder ); + + if( doInterpolate ) { + /* Calculate the interpolated, quantized LSF vector for the first half */ + silk_interpolate( pNLSF0_temp_Q15, prev_NLSFq_Q15, pNLSF_Q15, + psEncC->indices.NLSFInterpCoef_Q2, psEncC->predictLPCOrder ); + + /* Convert back to LPC coefficients */ + silk_NLSF2A( PredCoef_Q12[ 0 ], pNLSF0_temp_Q15, psEncC->predictLPCOrder ); + + } else { + /* Copy LPC coefficients for first half from second half */ + silk_memcpy( PredCoef_Q12[ 0 ], PredCoef_Q12[ 1 ], psEncC->predictLPCOrder * sizeof( opus_int16 ) ); + } +} diff --git a/code/opus-1.0.2/silk/quant_LTP_gains.c b/code/opus-1.0.2/silk/quant_LTP_gains.c new file mode 100644 index 00000000..f73c0f50 --- /dev/null +++ b/code/opus-1.0.2/silk/quant_LTP_gains.c @@ -0,0 +1,107 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +void silk_quant_LTP_gains( + opus_int16 B_Q14[ MAX_NB_SUBFR * LTP_ORDER ], /* I/O (un)quantized LTP gains */ + opus_int8 cbk_index[ MAX_NB_SUBFR ], /* O Codebook Index */ + opus_int8 *periodicity_index, /* O Periodicity Index */ + const opus_int32 W_Q18[ MAX_NB_SUBFR*LTP_ORDER*LTP_ORDER ], /* I Error Weights in Q18 */ + opus_int mu_Q9, /* I Mu value (R/D tradeoff) */ + opus_int lowComplexity, /* I Flag for low complexity */ + const opus_int nb_subfr /* I number of subframes */ +) +{ + opus_int j, k, cbk_size; + opus_int8 temp_idx[ MAX_NB_SUBFR ]; + const opus_uint8 *cl_ptr_Q5; + const opus_int8 *cbk_ptr_Q7; + const opus_int16 *b_Q14_ptr; + const opus_int32 *W_Q18_ptr; + opus_int32 rate_dist_Q14_subfr, rate_dist_Q14, min_rate_dist_Q14; + + /***************************************************/ + /* iterate over different codebooks with different */ + /* rates/distortions, and choose best */ + /***************************************************/ + min_rate_dist_Q14 = silk_int32_MAX; + for( k = 0; k < 3; k++ ) { + cl_ptr_Q5 = silk_LTP_gain_BITS_Q5_ptrs[ k ]; + cbk_ptr_Q7 = silk_LTP_vq_ptrs_Q7[ k ]; + cbk_size = silk_LTP_vq_sizes[ k ]; + + /* Set up pointer to first subframe */ + W_Q18_ptr = W_Q18; + b_Q14_ptr = B_Q14; + + rate_dist_Q14 = 0; + for( j = 0; j < nb_subfr; j++ ) { + silk_VQ_WMat_EC( + &temp_idx[ j ], /* O index of best codebook vector */ + &rate_dist_Q14_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_Q7, /* I codebook */ + cl_ptr_Q5, /* I code length for each codebook vector */ + mu_Q9, /* I tradeoff between weighted error and rate */ + cbk_size /* I number of vectors in codebook */ + ); + + rate_dist_Q14 = silk_ADD_POS_SAT32( rate_dist_Q14, rate_dist_Q14_subfr ); + + b_Q14_ptr += LTP_ORDER; + W_Q18_ptr += LTP_ORDER * LTP_ORDER; + } + + /* Avoid never finding a codebook */ + rate_dist_Q14 = silk_min( silk_int32_MAX - 1, rate_dist_Q14 ); + + if( rate_dist_Q14 < min_rate_dist_Q14 ) { + min_rate_dist_Q14 = rate_dist_Q14; + *periodicity_index = (opus_int8)k; + silk_memcpy( cbk_index, temp_idx, nb_subfr * sizeof( opus_int8 ) ); + } + + /* Break early in low-complexity mode if rate distortion is below threshold */ + if( lowComplexity && ( rate_dist_Q14 < silk_LTP_gain_middle_avg_RD_Q14 ) ) { + break; + } + } + + cbk_ptr_Q7 = silk_LTP_vq_ptrs_Q7[ *periodicity_index ]; + for( j = 0; j < nb_subfr; j++ ) { + for( k = 0; k < LTP_ORDER; k++ ) { + B_Q14[ j * LTP_ORDER + k ] = silk_LSHIFT( cbk_ptr_Q7[ cbk_index[ j ] * LTP_ORDER + k ], 7 ); + } + } +} + diff --git a/code/opus-1.0.2/silk/resampler.c b/code/opus-1.0.2/silk/resampler.c new file mode 100644 index 00000000..7e58332f --- /dev/null +++ b/code/opus-1.0.2/silk/resampler.c @@ -0,0 +1,215 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* + * Matrix of resampling methods used: + * Fs_out (kHz) + * 8 12 16 24 48 + * + * 8 C UF U UF UF + * 12 AF C UF U UF + * Fs_in (kHz) 16 D AF C UF UF + * 24 AF D AF C U + * 48 AF AF AF D C + * + * C -> Copy (no resampling) + * D -> Allpass-based 2x downsampling + * U -> Allpass-based 2x upsampling + * UF -> Allpass-based 2x upsampling followed by FIR interpolation + * AF -> AR2 filter followed by FIR interpolation + */ + +#include "resampler_private.h" + +/* Tables with delay compensation values to equalize total delay for different modes */ +static const opus_int8 delay_matrix_enc[ 5 ][ 3 ] = { +/* in \ out 8 12 16 */ +/* 8 */ { 6, 0, 3 }, +/* 12 */ { 0, 7, 3 }, +/* 16 */ { 0, 1, 10 }, +/* 24 */ { 0, 2, 6 }, +/* 48 */ { 18, 10, 12 } +}; + +static const opus_int8 delay_matrix_dec[ 3 ][ 5 ] = { +/* in \ out 8 12 16 24 48 */ +/* 8 */ { 4, 0, 2, 0, 0 }, +/* 12 */ { 0, 9, 4, 7, 4 }, +/* 16 */ { 0, 3, 12, 7, 7 } +}; + +/* Simple way to make [8000, 12000, 16000, 24000, 48000] to [0, 1, 2, 3, 4] */ +#define rateID(R) ( ( ( ((R)>>12) - ((R)>16000) ) >> ((R)>24000) ) - 1 ) + +#define USE_silk_resampler_copy (0) +#define USE_silk_resampler_private_up2_HQ_wrapper (1) +#define USE_silk_resampler_private_IIR_FIR (2) +#define USE_silk_resampler_private_down_FIR (3) + +/* Initialize/reset the resampler state for a given pair of input/output sampling rates */ +opus_int silk_resampler_init( + silk_resampler_state_struct *S, /* I/O Resampler state */ + opus_int32 Fs_Hz_in, /* I Input sampling rate (Hz) */ + opus_int32 Fs_Hz_out, /* I Output sampling rate (Hz) */ + opus_int forEnc /* I If 1: encoder; if 0: decoder */ +) +{ + opus_int up2x; + + /* Clear state */ + silk_memset( S, 0, sizeof( silk_resampler_state_struct ) ); + + /* Input checking */ + if( forEnc ) { + if( ( Fs_Hz_in != 8000 && Fs_Hz_in != 12000 && Fs_Hz_in != 16000 && Fs_Hz_in != 24000 && Fs_Hz_in != 48000 ) || + ( Fs_Hz_out != 8000 && Fs_Hz_out != 12000 && Fs_Hz_out != 16000 ) ) { + silk_assert( 0 ); + return -1; + } + S->inputDelay = delay_matrix_enc[ rateID( Fs_Hz_in ) ][ rateID( Fs_Hz_out ) ]; + } else { + if( ( Fs_Hz_in != 8000 && Fs_Hz_in != 12000 && Fs_Hz_in != 16000 ) || + ( Fs_Hz_out != 8000 && Fs_Hz_out != 12000 && Fs_Hz_out != 16000 && Fs_Hz_out != 24000 && Fs_Hz_out != 48000 ) ) { + silk_assert( 0 ); + return -1; + } + S->inputDelay = delay_matrix_dec[ rateID( Fs_Hz_in ) ][ rateID( Fs_Hz_out ) ]; + } + + S->Fs_in_kHz = silk_DIV32_16( Fs_Hz_in, 1000 ); + S->Fs_out_kHz = silk_DIV32_16( Fs_Hz_out, 1000 ); + + /* Number of samples processed per batch */ + S->batchSize = S->Fs_in_kHz * RESAMPLER_MAX_BATCH_SIZE_MS; + + /* Find resampler with the right sampling ratio */ + up2x = 0; + if( Fs_Hz_out > Fs_Hz_in ) { + /* Upsample */ + if( Fs_Hz_out == silk_MUL( Fs_Hz_in, 2 ) ) { /* Fs_out : Fs_in = 2 : 1 */ + /* Special case: directly use 2x upsampler */ + S->resampler_function = USE_silk_resampler_private_up2_HQ_wrapper; + } else { + /* Default resampler */ + S->resampler_function = USE_silk_resampler_private_IIR_FIR; + up2x = 1; + } + } else if ( Fs_Hz_out < Fs_Hz_in ) { + /* Downsample */ + S->resampler_function = USE_silk_resampler_private_down_FIR; + if( silk_MUL( Fs_Hz_out, 4 ) == silk_MUL( Fs_Hz_in, 3 ) ) { /* Fs_out : Fs_in = 3 : 4 */ + S->FIR_Fracs = 3; + S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR0; + S->Coefs = silk_Resampler_3_4_COEFS; + } else if( silk_MUL( Fs_Hz_out, 3 ) == silk_MUL( Fs_Hz_in, 2 ) ) { /* Fs_out : Fs_in = 2 : 3 */ + S->FIR_Fracs = 2; + S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR0; + S->Coefs = silk_Resampler_2_3_COEFS; + } else if( silk_MUL( Fs_Hz_out, 2 ) == Fs_Hz_in ) { /* Fs_out : Fs_in = 1 : 2 */ + S->FIR_Fracs = 1; + S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR1; + S->Coefs = silk_Resampler_1_2_COEFS; + } else if( silk_MUL( Fs_Hz_out, 3 ) == Fs_Hz_in ) { /* Fs_out : Fs_in = 1 : 3 */ + S->FIR_Fracs = 1; + S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR2; + S->Coefs = silk_Resampler_1_3_COEFS; + } else if( silk_MUL( Fs_Hz_out, 4 ) == Fs_Hz_in ) { /* Fs_out : Fs_in = 1 : 4 */ + S->FIR_Fracs = 1; + S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR2; + S->Coefs = silk_Resampler_1_4_COEFS; + } else if( silk_MUL( Fs_Hz_out, 6 ) == Fs_Hz_in ) { /* Fs_out : Fs_in = 1 : 6 */ + S->FIR_Fracs = 1; + S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR2; + S->Coefs = silk_Resampler_1_6_COEFS; + } else { + /* None available */ + silk_assert( 0 ); + return -1; + } + } else { + /* Input and output sampling rates are equal: copy */ + S->resampler_function = USE_silk_resampler_copy; + } + + /* Ratio of input/output samples */ + S->invRatio_Q16 = silk_LSHIFT32( silk_DIV32( silk_LSHIFT32( Fs_Hz_in, 14 + up2x ), Fs_Hz_out ), 2 ); + /* Make sure the ratio is rounded up */ + while( silk_SMULWW( S->invRatio_Q16, Fs_Hz_out ) < silk_LSHIFT32( Fs_Hz_in, up2x ) ) { + S->invRatio_Q16++; + } + + return 0; +} + +/* Resampler: convert from one sampling rate to another */ +/* Input and output sampling rate are at most 48000 Hz */ +opus_int silk_resampler( + silk_resampler_state_struct *S, /* I/O Resampler state */ + opus_int16 out[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + opus_int32 inLen /* I Number of input samples */ +) +{ + opus_int nSamples; + + /* Need at least 1 ms of input data */ + silk_assert( inLen >= S->Fs_in_kHz ); + /* Delay can't exceed the 1 ms of buffering */ + silk_assert( S->inputDelay <= S->Fs_in_kHz ); + + nSamples = S->Fs_in_kHz - S->inputDelay; + + /* Copy to delay buffer */ + silk_memcpy( &S->delayBuf[ S->inputDelay ], in, nSamples * sizeof( opus_int16 ) ); + + switch( S->resampler_function ) { + case USE_silk_resampler_private_up2_HQ_wrapper: + silk_resampler_private_up2_HQ_wrapper( S, out, S->delayBuf, S->Fs_in_kHz ); + silk_resampler_private_up2_HQ_wrapper( S, &out[ S->Fs_out_kHz ], &in[ nSamples ], inLen - S->Fs_in_kHz ); + break; + case USE_silk_resampler_private_IIR_FIR: + silk_resampler_private_IIR_FIR( S, out, S->delayBuf, S->Fs_in_kHz ); + silk_resampler_private_IIR_FIR( S, &out[ S->Fs_out_kHz ], &in[ nSamples ], inLen - S->Fs_in_kHz ); + break; + case USE_silk_resampler_private_down_FIR: + silk_resampler_private_down_FIR( S, out, S->delayBuf, S->Fs_in_kHz ); + silk_resampler_private_down_FIR( S, &out[ S->Fs_out_kHz ], &in[ nSamples ], inLen - S->Fs_in_kHz ); + break; + default: + silk_memcpy( out, S->delayBuf, S->Fs_in_kHz * sizeof( opus_int16 ) ); + silk_memcpy( &out[ S->Fs_out_kHz ], &in[ nSamples ], ( inLen - S->Fs_in_kHz ) * sizeof( opus_int16 ) ); + } + + /* Copy to delay buffer */ + silk_memcpy( S->delayBuf, &in[ inLen - S->inputDelay ], S->inputDelay * sizeof( opus_int16 ) ); + + return 0; +} diff --git a/code/opus-1.0.2/silk/resampler_down2.c b/code/opus-1.0.2/silk/resampler_down2.c new file mode 100644 index 00000000..21d11992 --- /dev/null +++ b/code/opus-1.0.2/silk/resampler_down2.c @@ -0,0 +1,74 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "resampler_rom.h" + +/* Downsample by a factor 2 */ +void silk_resampler_down2( + opus_int32 *S, /* I/O State vector [ 2 ] */ + opus_int16 *out, /* O Output signal [ len ] */ + const opus_int16 *in, /* I Input signal [ floor(len/2) ] */ + opus_int32 inLen /* I Number of input samples */ +) +{ + opus_int32 k, len2 = silk_RSHIFT32( inLen, 1 ); + opus_int32 in32, out32, Y, X; + + silk_assert( silk_resampler_down2_0 > 0 ); + silk_assert( silk_resampler_down2_1 < 0 ); + + /* Internal variables and state are in Q10 format */ + for( k = 0; k < len2; k++ ) { + /* Convert to Q10 */ + in32 = silk_LSHIFT( (opus_int32)in[ 2 * k ], 10 ); + + /* All-pass section for even input sample */ + Y = silk_SUB32( in32, S[ 0 ] ); + X = silk_SMLAWB( Y, Y, silk_resampler_down2_1 ); + out32 = silk_ADD32( S[ 0 ], X ); + S[ 0 ] = silk_ADD32( in32, X ); + + /* Convert to Q10 */ + in32 = silk_LSHIFT( (opus_int32)in[ 2 * k + 1 ], 10 ); + + /* All-pass section for odd input sample, and add to output of previous section */ + Y = silk_SUB32( in32, S[ 1 ] ); + X = silk_SMULWB( Y, silk_resampler_down2_0 ); + out32 = silk_ADD32( out32, S[ 1 ] ); + out32 = silk_ADD32( out32, X ); + S[ 1 ] = silk_ADD32( in32, X ); + + /* Add, convert back to int16 and store to output */ + out[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( out32, 11 ) ); + } +} + diff --git a/code/opus-1.0.2/silk/resampler_down2_3.c b/code/opus-1.0.2/silk/resampler_down2_3.c new file mode 100644 index 00000000..fe5b671d --- /dev/null +++ b/code/opus-1.0.2/silk/resampler_down2_3.c @@ -0,0 +1,98 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "resampler_private.h" + +#define ORDER_FIR 4 + +/* Downsample by a factor 2/3, low quality */ +void silk_resampler_down2_3( + opus_int32 *S, /* I/O State vector [ 6 ] */ + opus_int16 *out, /* O Output signal [ floor(2*inLen/3) ] */ + const opus_int16 *in, /* I Input signal [ inLen ] */ + opus_int32 inLen /* I Number of input samples */ +) +{ + opus_int32 nSamplesIn, counter, res_Q6; + opus_int32 buf[ RESAMPLER_MAX_BATCH_SIZE_IN + ORDER_FIR ]; + opus_int32 *buf_ptr; + + /* Copy buffered samples to start of buffer */ + silk_memcpy( buf, S, ORDER_FIR * sizeof( opus_int32 ) ); + + /* Iterate over blocks of frameSizeIn input samples */ + while( 1 ) { + nSamplesIn = silk_min( inLen, RESAMPLER_MAX_BATCH_SIZE_IN ); + + /* Second-order AR filter (output in Q8) */ + silk_resampler_private_AR2( &S[ ORDER_FIR ], &buf[ ORDER_FIR ], in, + silk_Resampler_2_3_COEFS_LQ, nSamplesIn ); + + /* Interpolate filtered signal */ + buf_ptr = buf; + counter = nSamplesIn; + while( counter > 2 ) { + /* Inner product */ + res_Q6 = silk_SMULWB( buf_ptr[ 0 ], silk_Resampler_2_3_COEFS_LQ[ 2 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 1 ], silk_Resampler_2_3_COEFS_LQ[ 3 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 2 ], silk_Resampler_2_3_COEFS_LQ[ 5 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 3 ], silk_Resampler_2_3_COEFS_LQ[ 4 ] ); + + /* Scale down, saturate and store in output array */ + *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) ); + + res_Q6 = silk_SMULWB( buf_ptr[ 1 ], silk_Resampler_2_3_COEFS_LQ[ 4 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 2 ], silk_Resampler_2_3_COEFS_LQ[ 5 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 3 ], silk_Resampler_2_3_COEFS_LQ[ 3 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 4 ], silk_Resampler_2_3_COEFS_LQ[ 2 ] ); + + /* Scale down, saturate and store in output array */ + *out++ = (opus_int16)silk_SAT16( silk_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 */ + silk_memcpy( buf, &buf[ nSamplesIn ], ORDER_FIR * sizeof( opus_int32 ) ); + } else { + break; + } + } + + /* Copy last part of filtered signal to the state for the next call */ + silk_memcpy( S, &buf[ nSamplesIn ], ORDER_FIR * sizeof( opus_int32 ) ); +} diff --git a/code/opus-1.0.2/silk/resampler_private.h b/code/opus-1.0.2/silk/resampler_private.h new file mode 100644 index 00000000..45d342c7 --- /dev/null +++ b/code/opus-1.0.2/silk/resampler_private.h @@ -0,0 +1,88 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (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 SILK_RESAMPLER_PRIVATE_H +#define SILK_RESAMPLER_PRIVATE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "SigProc_FIX.h" +#include "resampler_structs.h" +#include "resampler_rom.h" + +/* Number of input samples to process in the inner loop */ +#define RESAMPLER_MAX_BATCH_SIZE_MS 10 +#define RESAMPLER_MAX_FS_KHZ 48 +#define RESAMPLER_MAX_BATCH_SIZE_IN ( RESAMPLER_MAX_BATCH_SIZE_MS * RESAMPLER_MAX_FS_KHZ ) + +/* Description: Hybrid IIR/FIR polyphase implementation of resampling */ +void silk_resampler_private_IIR_FIR( + void *SS, /* I/O Resampler state */ + opus_int16 out[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + opus_int32 inLen /* I Number of input samples */ +); + +/* Description: Hybrid IIR/FIR polyphase implementation of resampling */ +void silk_resampler_private_down_FIR( + void *SS, /* I/O Resampler state */ + opus_int16 out[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + opus_int32 inLen /* I Number of input samples */ +); + +/* Upsample by a factor 2, high quality */ +void silk_resampler_private_up2_HQ_wrapper( + void *SS, /* I/O Resampler state (unused) */ + opus_int16 *out, /* O Output signal [ 2 * len ] */ + const opus_int16 *in, /* I Input signal [ len ] */ + opus_int32 len /* I Number of input samples */ +); + +/* Upsample by a factor 2, high quality */ +void silk_resampler_private_up2_HQ( + opus_int32 *S, /* I/O Resampler state [ 6 ] */ + opus_int16 *out, /* O Output signal [ 2 * len ] */ + const opus_int16 *in, /* I Input signal [ len ] */ + opus_int32 len /* I Number of input samples */ +); + +/* Second order AR filter */ +void silk_resampler_private_AR2( + opus_int32 S[], /* I/O State vector [ 2 ] */ + opus_int32 out_Q8[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + const opus_int16 A_Q14[], /* I AR coefficients, Q14 */ + opus_int32 len /* I Signal length */ +); + +#ifdef __cplusplus +} +#endif +#endif /* SILK_RESAMPLER_PRIVATE_H */ diff --git a/code/opus-1.0.2/silk/resampler_private_AR2.c b/code/opus-1.0.2/silk/resampler_private_AR2.c new file mode 100644 index 00000000..d069f2d8 --- /dev/null +++ b/code/opus-1.0.2/silk/resampler_private_AR2.c @@ -0,0 +1,55 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "resampler_private.h" + +/* Second order AR filter with single delay elements */ +void silk_resampler_private_AR2( + opus_int32 S[], /* I/O State vector [ 2 ] */ + opus_int32 out_Q8[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + const opus_int16 A_Q14[], /* I AR coefficients, Q14 */ + opus_int32 len /* I Signal length */ +) +{ + opus_int32 k; + opus_int32 out32; + + for( k = 0; k < len; k++ ) { + out32 = silk_ADD_LSHIFT32( S[ 0 ], (opus_int32)in[ k ], 8 ); + out_Q8[ k ] = out32; + out32 = silk_LSHIFT( out32, 2 ); + S[ 0 ] = silk_SMLAWB( S[ 1 ], out32, A_Q14[ 0 ] ); + S[ 1 ] = silk_SMULWB( out32, A_Q14[ 1 ] ); + } +} + diff --git a/code/opus-1.0.2/silk/resampler_private_IIR_FIR.c b/code/opus-1.0.2/silk/resampler_private_IIR_FIR.c new file mode 100644 index 00000000..d9e42ca0 --- /dev/null +++ b/code/opus-1.0.2/silk/resampler_private_IIR_FIR.c @@ -0,0 +1,103 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "resampler_private.h" + +static inline opus_int16 *silk_resampler_private_IIR_FIR_INTERPOL( + opus_int16 *out, + opus_int16 *buf, + opus_int32 max_index_Q16, + opus_int32 index_increment_Q16 +) +{ + opus_int32 index_Q16, res_Q15; + opus_int16 *buf_ptr; + opus_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 = silk_SMULWB( index_Q16 & 0xFFFF, 12 ); + buf_ptr = &buf[ index_Q16 >> 16 ]; + + res_Q15 = silk_SMULBB( buf_ptr[ 0 ], silk_resampler_frac_FIR_12[ table_index ][ 0 ] ); + res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 1 ], silk_resampler_frac_FIR_12[ table_index ][ 1 ] ); + res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 2 ], silk_resampler_frac_FIR_12[ table_index ][ 2 ] ); + res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 3 ], silk_resampler_frac_FIR_12[ table_index ][ 3 ] ); + res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 4 ], silk_resampler_frac_FIR_12[ 11 - table_index ][ 3 ] ); + res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 5 ], silk_resampler_frac_FIR_12[ 11 - table_index ][ 2 ] ); + res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 6 ], silk_resampler_frac_FIR_12[ 11 - table_index ][ 1 ] ); + res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 7 ], silk_resampler_frac_FIR_12[ 11 - table_index ][ 0 ] ); + *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q15, 15 ) ); + } + return out; +} +/* Upsample using a combination of allpass-based 2x upsampling and FIR interpolation */ +void silk_resampler_private_IIR_FIR( + void *SS, /* I/O Resampler state */ + opus_int16 out[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + opus_int32 inLen /* I Number of input samples */ +) +{ + silk_resampler_state_struct *S = (silk_resampler_state_struct *)SS; + opus_int32 nSamplesIn; + opus_int32 max_index_Q16, index_increment_Q16; + opus_int16 buf[ RESAMPLER_MAX_BATCH_SIZE_IN + RESAMPLER_ORDER_FIR_12 ]; + + /* Copy buffered samples to start of buffer */ + silk_memcpy( buf, S->sFIR, RESAMPLER_ORDER_FIR_12 * sizeof( opus_int32 ) ); + + /* Iterate over blocks of frameSizeIn input samples */ + index_increment_Q16 = S->invRatio_Q16; + while( 1 ) { + nSamplesIn = silk_min( inLen, S->batchSize ); + + /* Upsample 2x */ + silk_resampler_private_up2_HQ( S->sIIR, &buf[ RESAMPLER_ORDER_FIR_12 ], in, nSamplesIn ); + + max_index_Q16 = silk_LSHIFT32( nSamplesIn, 16 + 1 ); /* + 1 because 2x upsampling */ + out = 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 */ + silk_memcpy( buf, &buf[ nSamplesIn << 1 ], RESAMPLER_ORDER_FIR_12 * sizeof( opus_int32 ) ); + } else { + break; + } + } + + /* Copy last part of filtered signal to the state for the next call */ + silk_memcpy( S->sFIR, &buf[ nSamplesIn << 1 ], RESAMPLER_ORDER_FIR_12 * sizeof( opus_int32 ) ); +} + diff --git a/code/opus-1.0.2/silk/resampler_private_down_FIR.c b/code/opus-1.0.2/silk/resampler_private_down_FIR.c new file mode 100644 index 00000000..5d24564c --- /dev/null +++ b/code/opus-1.0.2/silk/resampler_private_down_FIR.c @@ -0,0 +1,189 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "resampler_private.h" + +static inline opus_int16 *silk_resampler_private_down_FIR_INTERPOL( + opus_int16 *out, + opus_int32 *buf, + const opus_int16 *FIR_Coefs, + opus_int FIR_Order, + opus_int FIR_Fracs, + opus_int32 max_index_Q16, + opus_int32 index_increment_Q16 +) +{ + opus_int32 index_Q16, res_Q6; + opus_int32 *buf_ptr; + opus_int32 interpol_ind; + const opus_int16 *interpol_ptr; + + switch( FIR_Order ) { + case RESAMPLER_DOWN_ORDER_FIR0: + for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) { + /* Integer part gives pointer to buffered input */ + buf_ptr = buf + silk_RSHIFT( index_Q16, 16 ); + + /* Fractional part gives interpolation coefficients */ + interpol_ind = silk_SMULWB( index_Q16 & 0xFFFF, FIR_Fracs ); + + /* Inner product */ + interpol_ptr = &FIR_Coefs[ RESAMPLER_DOWN_ORDER_FIR0 / 2 * interpol_ind ]; + res_Q6 = silk_SMULWB( buf_ptr[ 0 ], interpol_ptr[ 0 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 1 ], interpol_ptr[ 1 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 2 ], interpol_ptr[ 2 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 3 ], interpol_ptr[ 3 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 4 ], interpol_ptr[ 4 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 5 ], interpol_ptr[ 5 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 6 ], interpol_ptr[ 6 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 7 ], interpol_ptr[ 7 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 8 ], interpol_ptr[ 8 ] ); + interpol_ptr = &FIR_Coefs[ RESAMPLER_DOWN_ORDER_FIR0 / 2 * ( FIR_Fracs - 1 - interpol_ind ) ]; + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 17 ], interpol_ptr[ 0 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 16 ], interpol_ptr[ 1 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 15 ], interpol_ptr[ 2 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 14 ], interpol_ptr[ 3 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 13 ], interpol_ptr[ 4 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 12 ], interpol_ptr[ 5 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 11 ], interpol_ptr[ 6 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 10 ], interpol_ptr[ 7 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 9 ], interpol_ptr[ 8 ] ); + + /* Scale down, saturate and store in output array */ + *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) ); + } + break; + case RESAMPLER_DOWN_ORDER_FIR1: + for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) { + /* Integer part gives pointer to buffered input */ + buf_ptr = buf + silk_RSHIFT( index_Q16, 16 ); + + /* Inner product */ + res_Q6 = silk_SMULWB( silk_ADD32( buf_ptr[ 0 ], buf_ptr[ 23 ] ), FIR_Coefs[ 0 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 1 ], buf_ptr[ 22 ] ), FIR_Coefs[ 1 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 2 ], buf_ptr[ 21 ] ), FIR_Coefs[ 2 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 3 ], buf_ptr[ 20 ] ), FIR_Coefs[ 3 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 4 ], buf_ptr[ 19 ] ), FIR_Coefs[ 4 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 5 ], buf_ptr[ 18 ] ), FIR_Coefs[ 5 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 6 ], buf_ptr[ 17 ] ), FIR_Coefs[ 6 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 7 ], buf_ptr[ 16 ] ), FIR_Coefs[ 7 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 8 ], buf_ptr[ 15 ] ), FIR_Coefs[ 8 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 9 ], buf_ptr[ 14 ] ), FIR_Coefs[ 9 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 10 ], buf_ptr[ 13 ] ), FIR_Coefs[ 10 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 11 ], buf_ptr[ 12 ] ), FIR_Coefs[ 11 ] ); + + /* Scale down, saturate and store in output array */ + *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) ); + } + break; + case RESAMPLER_DOWN_ORDER_FIR2: + for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) { + /* Integer part gives pointer to buffered input */ + buf_ptr = buf + silk_RSHIFT( index_Q16, 16 ); + + /* Inner product */ + res_Q6 = silk_SMULWB( silk_ADD32( buf_ptr[ 0 ], buf_ptr[ 35 ] ), FIR_Coefs[ 0 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 1 ], buf_ptr[ 34 ] ), FIR_Coefs[ 1 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 2 ], buf_ptr[ 33 ] ), FIR_Coefs[ 2 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 3 ], buf_ptr[ 32 ] ), FIR_Coefs[ 3 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 4 ], buf_ptr[ 31 ] ), FIR_Coefs[ 4 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 5 ], buf_ptr[ 30 ] ), FIR_Coefs[ 5 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 6 ], buf_ptr[ 29 ] ), FIR_Coefs[ 6 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 7 ], buf_ptr[ 28 ] ), FIR_Coefs[ 7 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 8 ], buf_ptr[ 27 ] ), FIR_Coefs[ 8 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 9 ], buf_ptr[ 26 ] ), FIR_Coefs[ 9 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 10 ], buf_ptr[ 25 ] ), FIR_Coefs[ 10 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 11 ], buf_ptr[ 24 ] ), FIR_Coefs[ 11 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 12 ], buf_ptr[ 23 ] ), FIR_Coefs[ 12 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 13 ], buf_ptr[ 22 ] ), FIR_Coefs[ 13 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 14 ], buf_ptr[ 21 ] ), FIR_Coefs[ 14 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 15 ], buf_ptr[ 20 ] ), FIR_Coefs[ 15 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 16 ], buf_ptr[ 19 ] ), FIR_Coefs[ 16 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 17 ], buf_ptr[ 18 ] ), FIR_Coefs[ 17 ] ); + + /* Scale down, saturate and store in output array */ + *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) ); + } + break; + default: + silk_assert( 0 ); + } + return out; +} + +/* Resample with a 2nd order AR filter followed by FIR interpolation */ +void silk_resampler_private_down_FIR( + void *SS, /* I/O Resampler state */ + opus_int16 out[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + opus_int32 inLen /* I Number of input samples */ +) +{ + silk_resampler_state_struct *S = (silk_resampler_state_struct *)SS; + opus_int32 nSamplesIn; + opus_int32 max_index_Q16, index_increment_Q16; + opus_int32 buf[ RESAMPLER_MAX_BATCH_SIZE_IN + SILK_RESAMPLER_MAX_FIR_ORDER ]; + const opus_int16 *FIR_Coefs; + + /* Copy buffered samples to start of buffer */ + silk_memcpy( buf, S->sFIR, S->FIR_Order * sizeof( opus_int32 ) ); + + FIR_Coefs = &S->Coefs[ 2 ]; + + /* Iterate over blocks of frameSizeIn input samples */ + index_increment_Q16 = S->invRatio_Q16; + while( 1 ) { + nSamplesIn = silk_min( inLen, S->batchSize ); + + /* Second-order AR filter (output in Q8) */ + silk_resampler_private_AR2( S->sIIR, &buf[ S->FIR_Order ], in, S->Coefs, nSamplesIn ); + + max_index_Q16 = silk_LSHIFT32( nSamplesIn, 16 ); + + /* Interpolate filtered signal */ + out = silk_resampler_private_down_FIR_INTERPOL( out, buf, FIR_Coefs, S->FIR_Order, + S->FIR_Fracs, max_index_Q16, index_increment_Q16 ); + + in += nSamplesIn; + inLen -= nSamplesIn; + + if( inLen > 1 ) { + /* More iterations to do; copy last part of filtered signal to beginning of buffer */ + silk_memcpy( buf, &buf[ nSamplesIn ], S->FIR_Order * sizeof( opus_int32 ) ); + } else { + break; + } + } + + /* Copy last part of filtered signal to the state for the next call */ + silk_memcpy( S->sFIR, &buf[ nSamplesIn ], S->FIR_Order * sizeof( opus_int32 ) ); +} diff --git a/code/opus-1.0.2/silk/resampler_private_up2_HQ.c b/code/opus-1.0.2/silk/resampler_private_up2_HQ.c new file mode 100644 index 00000000..9e6dfc9e --- /dev/null +++ b/code/opus-1.0.2/silk/resampler_private_up2_HQ.c @@ -0,0 +1,113 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" +#include "resampler_private.h" + +/* Upsample by a factor 2, high quality */ +/* Uses 2nd order allpass filters for the 2x upsampling, followed by a */ +/* notch filter just above Nyquist. */ +void silk_resampler_private_up2_HQ( + opus_int32 *S, /* I/O Resampler state [ 6 ] */ + opus_int16 *out, /* O Output signal [ 2 * len ] */ + const opus_int16 *in, /* I Input signal [ len ] */ + opus_int32 len /* I Number of input samples */ +) +{ + opus_int32 k; + opus_int32 in32, out32_1, out32_2, Y, X; + + silk_assert( silk_resampler_up2_hq_0[ 0 ] > 0 ); + silk_assert( silk_resampler_up2_hq_0[ 1 ] > 0 ); + silk_assert( silk_resampler_up2_hq_0[ 2 ] < 0 ); + silk_assert( silk_resampler_up2_hq_1[ 0 ] > 0 ); + silk_assert( silk_resampler_up2_hq_1[ 1 ] > 0 ); + silk_assert( silk_resampler_up2_hq_1[ 2 ] < 0 ); + + /* Internal variables and state are in Q10 format */ + for( k = 0; k < len; k++ ) { + /* Convert to Q10 */ + in32 = silk_LSHIFT( (opus_int32)in[ k ], 10 ); + + /* First all-pass section for even output sample */ + Y = silk_SUB32( in32, S[ 0 ] ); + X = silk_SMULWB( Y, silk_resampler_up2_hq_0[ 0 ] ); + out32_1 = silk_ADD32( S[ 0 ], X ); + S[ 0 ] = silk_ADD32( in32, X ); + + /* Second all-pass section for even output sample */ + Y = silk_SUB32( out32_1, S[ 1 ] ); + X = silk_SMULWB( Y, silk_resampler_up2_hq_0[ 1 ] ); + out32_2 = silk_ADD32( S[ 1 ], X ); + S[ 1 ] = silk_ADD32( out32_1, X ); + + /* Third all-pass section for even output sample */ + Y = silk_SUB32( out32_2, S[ 2 ] ); + X = silk_SMLAWB( Y, Y, silk_resampler_up2_hq_0[ 2 ] ); + out32_1 = silk_ADD32( S[ 2 ], X ); + S[ 2 ] = silk_ADD32( out32_2, X ); + + /* Apply gain in Q15, convert back to int16 and store to output */ + out[ 2 * k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( out32_1, 10 ) ); + + /* First all-pass section for odd output sample */ + Y = silk_SUB32( in32, S[ 3 ] ); + X = silk_SMULWB( Y, silk_resampler_up2_hq_1[ 0 ] ); + out32_1 = silk_ADD32( S[ 3 ], X ); + S[ 3 ] = silk_ADD32( in32, X ); + + /* Second all-pass section for odd output sample */ + Y = silk_SUB32( out32_1, S[ 4 ] ); + X = silk_SMULWB( Y, silk_resampler_up2_hq_1[ 1 ] ); + out32_2 = silk_ADD32( S[ 4 ], X ); + S[ 4 ] = silk_ADD32( out32_1, X ); + + /* Third all-pass section for odd output sample */ + Y = silk_SUB32( out32_2, S[ 5 ] ); + X = silk_SMLAWB( Y, Y, silk_resampler_up2_hq_1[ 2 ] ); + out32_1 = silk_ADD32( S[ 5 ], X ); + S[ 5 ] = silk_ADD32( out32_2, X ); + + /* Apply gain in Q15, convert back to int16 and store to output */ + out[ 2 * k + 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( out32_1, 10 ) ); + } +} + +void silk_resampler_private_up2_HQ_wrapper( + void *SS, /* I/O Resampler state (unused) */ + opus_int16 *out, /* O Output signal [ 2 * len ] */ + const opus_int16 *in, /* I Input signal [ len ] */ + opus_int32 len /* I Number of input samples */ +) +{ + silk_resampler_state_struct *S = (silk_resampler_state_struct *)SS; + silk_resampler_private_up2_HQ( S->sIIR, out, in, len ); +} diff --git a/code/opus-1.0.2/silk/resampler_rom.c b/code/opus-1.0.2/silk/resampler_rom.c new file mode 100644 index 00000000..b50af2e2 --- /dev/null +++ b/code/opus-1.0.2/silk/resampler_rom.c @@ -0,0 +1,96 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* Filter coefficients for IIR/FIR polyphase resampling * + * Total size: 179 Words (358 Bytes) */ + +#include "resampler_private.h" + +/* Matlab code for the notch filter coefficients: */ +/* B = [1, 0.147, 1]; A = [1, 0.107, 0.89]; G = 0.93; 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 opus_int16 silk_resampler_up2_hq_notch[ 4 ] = { 9634, -7012, 7209, 30474 }; */ + +/* Tables with IIR and FIR coefficients for fractional downsamplers (123 Words) */ +silk_DWORD_ALIGN const opus_int16 silk_Resampler_3_4_COEFS[ 2 + 3 * RESAMPLER_DOWN_ORDER_FIR0 / 2 ] = { + -20694, -13867, + -49, 64, 17, -157, 353, -496, 163, 11047, 22205, + -39, 6, 91, -170, 186, 23, -896, 6336, 19928, + -19, -36, 102, -89, -24, 328, -951, 2568, 15909, +}; + +silk_DWORD_ALIGN const opus_int16 silk_Resampler_2_3_COEFS[ 2 + 2 * RESAMPLER_DOWN_ORDER_FIR0 / 2 ] = { + -14457, -14019, + 64, 128, -122, 36, 310, -768, 584, 9267, 17733, + 12, 128, 18, -142, 288, -117, -865, 4123, 14459, +}; + +silk_DWORD_ALIGN const opus_int16 silk_Resampler_1_2_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR1 / 2 ] = { + 616, -14323, + -10, 39, 58, -46, -84, 120, 184, -315, -541, 1284, 5380, 9024, +}; + +silk_DWORD_ALIGN const opus_int16 silk_Resampler_1_3_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ] = { + 16102, -15162, + -13, 0, 20, 26, 5, -31, -43, -4, 65, 90, 7, -157, -248, -44, 593, 1583, 2612, 3271, +}; + +silk_DWORD_ALIGN const opus_int16 silk_Resampler_1_4_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ] = { + 22500, -15099, + 3, -14, -20, -15, 2, 25, 37, 25, -16, -71, -107, -79, 50, 292, 623, 982, 1288, 1464, +}; + +silk_DWORD_ALIGN const opus_int16 silk_Resampler_1_6_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ] = { + 27540, -15257, + 17, 12, 8, 1, -10, -22, -30, -32, -22, 3, 44, 100, 168, 243, 317, 381, 429, 455, +}; + +silk_DWORD_ALIGN const opus_int16 silk_Resampler_2_3_COEFS_LQ[ 2 + 2 * 2 ] = { + -2797, -6507, + 4697, 10739, + 1567, 8276, +}; + +/* Table with interplation fractions of 1/24, 3/24, 5/24, ... , 23/24 : 23/24 (46 Words) */ +silk_DWORD_ALIGN const opus_int16 silk_resampler_frac_FIR_12[ 12 ][ RESAMPLER_ORDER_FIR_12 / 2 ] = { + { 189, -600, 617, 30567 }, + { 117, -159, -1070, 29704 }, + { 52, 221, -2392, 28276 }, + { -4, 529, -3350, 26341 }, + { -48, 758, -3956, 23973 }, + { -80, 905, -4235, 21254 }, + { -99, 972, -4222, 18278 }, + { -107, 967, -3957, 15143 }, + { -103, 896, -3487, 11950 }, + { -91, 773, -2865, 8798 }, + { -71, 611, -2143, 5784 }, + { -46, 425, -1375, 2996 }, +}; diff --git a/code/opus-1.0.2/silk/resampler_rom.h b/code/opus-1.0.2/silk/resampler_rom.h new file mode 100644 index 00000000..473b24a2 --- /dev/null +++ b/code/opus-1.0.2/silk/resampler_rom.h @@ -0,0 +1,68 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (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 SILK_FIX_RESAMPLER_ROM_H +#define SILK_FIX_RESAMPLER_ROM_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "typedef.h" +#include "resampler_structs.h" + +#define RESAMPLER_DOWN_ORDER_FIR0 18 +#define RESAMPLER_DOWN_ORDER_FIR1 24 +#define RESAMPLER_DOWN_ORDER_FIR2 36 +#define RESAMPLER_ORDER_FIR_12 8 + +/* Tables for 2x downsampler */ +static const opus_int16 silk_resampler_down2_0 = 9872; +static const opus_int16 silk_resampler_down2_1 = 39809 - 65536; + +/* Tables for 2x upsampler, high quality */ +static const opus_int16 silk_resampler_up2_hq_0[ 3 ] = { 1746, 14986, 39083 - 65536 }; +static const opus_int16 silk_resampler_up2_hq_1[ 3 ] = { 6854, 25769, 55542 - 65536 }; + +/* Tables with IIR and FIR coefficients for fractional downsamplers */ +extern const opus_int16 silk_Resampler_3_4_COEFS[ 2 + 3 * RESAMPLER_DOWN_ORDER_FIR0 / 2 ]; +extern const opus_int16 silk_Resampler_2_3_COEFS[ 2 + 2 * RESAMPLER_DOWN_ORDER_FIR0 / 2 ]; +extern const opus_int16 silk_Resampler_1_2_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR1 / 2 ]; +extern const opus_int16 silk_Resampler_1_3_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ]; +extern const opus_int16 silk_Resampler_1_4_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ]; +extern const opus_int16 silk_Resampler_1_6_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ]; +extern const opus_int16 silk_Resampler_2_3_COEFS_LQ[ 2 + 2 * 2 ]; + +/* Table with interplation fractions of 1/24, 3/24, ..., 23/24 */ +extern const opus_int16 silk_resampler_frac_FIR_12[ 12 ][ RESAMPLER_ORDER_FIR_12 / 2 ]; + +#ifdef __cplusplus +} +#endif + +#endif /* SILK_FIX_RESAMPLER_ROM_H */ diff --git a/code/opus-1.0.2/silk/resampler_structs.h b/code/opus-1.0.2/silk/resampler_structs.h new file mode 100644 index 00000000..4c28bd0a --- /dev/null +++ b/code/opus-1.0.2/silk/resampler_structs.h @@ -0,0 +1,57 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (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 SILK_RESAMPLER_STRUCTS_H +#define SILK_RESAMPLER_STRUCTS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define SILK_RESAMPLER_MAX_FIR_ORDER 36 +#define SILK_RESAMPLER_MAX_IIR_ORDER 6 + +typedef struct _silk_resampler_state_struct{ + opus_int32 sIIR[ SILK_RESAMPLER_MAX_IIR_ORDER ]; /* this must be the first element of this struct */ + opus_int32 sFIR[ SILK_RESAMPLER_MAX_FIR_ORDER ]; + opus_int16 delayBuf[ 48 ]; + opus_int resampler_function; + opus_int batchSize; + opus_int32 invRatio_Q16; + opus_int FIR_Order; + opus_int FIR_Fracs; + opus_int Fs_in_kHz; + opus_int Fs_out_kHz; + opus_int inputDelay; + const opus_int16 *Coefs; +} silk_resampler_state_struct; + +#ifdef __cplusplus +} +#endif +#endif /* SILK_RESAMPLER_STRUCTS_H */ + diff --git a/code/opus-1.0.2/silk/shell_coder.c b/code/opus-1.0.2/silk/shell_coder.c new file mode 100644 index 00000000..32d00129 --- /dev/null +++ b/code/opus-1.0.2/silk/shell_coder.c @@ -0,0 +1,151 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* shell coder; pulse-subframe length is hardcoded */ + +static inline void combine_pulses( + opus_int *out, /* O combined pulses vector [len] */ + const opus_int *in, /* I input vector [2 * len] */ + const opus_int len /* I number of OUTPUT samples */ +) +{ + opus_int k; + for( k = 0; k < len; k++ ) { + out[ k ] = in[ 2 * k ] + in[ 2 * k + 1 ]; + } +} + +static inline void encode_split( + ec_enc *psRangeEnc, /* I/O compressor data structure */ + const opus_int p_child1, /* I pulse amplitude of first child subframe */ + const opus_int p, /* I pulse amplitude of current subframe */ + const opus_uint8 *shell_table /* I table of shell cdfs */ +) +{ + if( p > 0 ) { + ec_enc_icdf( psRangeEnc, p_child1, &shell_table[ silk_shell_code_table_offsets[ p ] ], 8 ); + } +} + +static inline void decode_split( + opus_int *p_child1, /* O pulse amplitude of first child subframe */ + opus_int *p_child2, /* O pulse amplitude of second child subframe */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + const opus_int p, /* I pulse amplitude of current subframe */ + const opus_uint8 *shell_table /* I table of shell cdfs */ +) +{ + if( p > 0 ) { + p_child1[ 0 ] = ec_dec_icdf( psRangeDec, &shell_table[ silk_shell_code_table_offsets[ p ] ], 8 ); + 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 silk_shell_encoder( + ec_enc *psRangeEnc, /* I/O compressor data structure */ + const opus_int *pulses0 /* I data: nonnegative pulse amplitudes */ +) +{ + opus_int pulses1[ 8 ], pulses2[ 4 ], pulses3[ 2 ], pulses4[ 1 ]; + + /* this function operates on one shell code frame of 16 pulses */ + silk_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( psRangeEnc, pulses3[ 0 ], pulses4[ 0 ], silk_shell_code_table3 ); + + encode_split( psRangeEnc, pulses2[ 0 ], pulses3[ 0 ], silk_shell_code_table2 ); + + encode_split( psRangeEnc, pulses1[ 0 ], pulses2[ 0 ], silk_shell_code_table1 ); + encode_split( psRangeEnc, pulses0[ 0 ], pulses1[ 0 ], silk_shell_code_table0 ); + encode_split( psRangeEnc, pulses0[ 2 ], pulses1[ 1 ], silk_shell_code_table0 ); + + encode_split( psRangeEnc, pulses1[ 2 ], pulses2[ 1 ], silk_shell_code_table1 ); + encode_split( psRangeEnc, pulses0[ 4 ], pulses1[ 2 ], silk_shell_code_table0 ); + encode_split( psRangeEnc, pulses0[ 6 ], pulses1[ 3 ], silk_shell_code_table0 ); + + encode_split( psRangeEnc, pulses2[ 2 ], pulses3[ 1 ], silk_shell_code_table2 ); + + encode_split( psRangeEnc, pulses1[ 4 ], pulses2[ 2 ], silk_shell_code_table1 ); + encode_split( psRangeEnc, pulses0[ 8 ], pulses1[ 4 ], silk_shell_code_table0 ); + encode_split( psRangeEnc, pulses0[ 10 ], pulses1[ 5 ], silk_shell_code_table0 ); + + encode_split( psRangeEnc, pulses1[ 6 ], pulses2[ 3 ], silk_shell_code_table1 ); + encode_split( psRangeEnc, pulses0[ 12 ], pulses1[ 6 ], silk_shell_code_table0 ); + encode_split( psRangeEnc, pulses0[ 14 ], pulses1[ 7 ], silk_shell_code_table0 ); +} + + +/* Shell decoder, operates on one shell code frame of 16 pulses */ +void silk_shell_decoder( + opus_int *pulses0, /* O data: nonnegative pulse amplitudes */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + const opus_int pulses4 /* I number of pulses per pulse-subframe */ +) +{ + opus_int pulses3[ 2 ], pulses2[ 4 ], pulses1[ 8 ]; + + /* this function operates on one shell code frame of 16 pulses */ + silk_assert( SHELL_CODEC_FRAME_LENGTH == 16 ); + + decode_split( &pulses3[ 0 ], &pulses3[ 1 ], psRangeDec, pulses4, silk_shell_code_table3 ); + + decode_split( &pulses2[ 0 ], &pulses2[ 1 ], psRangeDec, pulses3[ 0 ], silk_shell_code_table2 ); + + decode_split( &pulses1[ 0 ], &pulses1[ 1 ], psRangeDec, pulses2[ 0 ], silk_shell_code_table1 ); + decode_split( &pulses0[ 0 ], &pulses0[ 1 ], psRangeDec, pulses1[ 0 ], silk_shell_code_table0 ); + decode_split( &pulses0[ 2 ], &pulses0[ 3 ], psRangeDec, pulses1[ 1 ], silk_shell_code_table0 ); + + decode_split( &pulses1[ 2 ], &pulses1[ 3 ], psRangeDec, pulses2[ 1 ], silk_shell_code_table1 ); + decode_split( &pulses0[ 4 ], &pulses0[ 5 ], psRangeDec, pulses1[ 2 ], silk_shell_code_table0 ); + decode_split( &pulses0[ 6 ], &pulses0[ 7 ], psRangeDec, pulses1[ 3 ], silk_shell_code_table0 ); + + decode_split( &pulses2[ 2 ], &pulses2[ 3 ], psRangeDec, pulses3[ 1 ], silk_shell_code_table2 ); + + decode_split( &pulses1[ 4 ], &pulses1[ 5 ], psRangeDec, pulses2[ 2 ], silk_shell_code_table1 ); + decode_split( &pulses0[ 8 ], &pulses0[ 9 ], psRangeDec, pulses1[ 4 ], silk_shell_code_table0 ); + decode_split( &pulses0[ 10 ], &pulses0[ 11 ], psRangeDec, pulses1[ 5 ], silk_shell_code_table0 ); + + decode_split( &pulses1[ 6 ], &pulses1[ 7 ], psRangeDec, pulses2[ 3 ], silk_shell_code_table1 ); + decode_split( &pulses0[ 12 ], &pulses0[ 13 ], psRangeDec, pulses1[ 6 ], silk_shell_code_table0 ); + decode_split( &pulses0[ 14 ], &pulses0[ 15 ], psRangeDec, pulses1[ 7 ], silk_shell_code_table0 ); +} diff --git a/code/opus-1.0.2/silk/sigm_Q15.c b/code/opus-1.0.2/silk/sigm_Q15.c new file mode 100644 index 00000000..cf5af6bc --- /dev/null +++ b/code/opus-1.0.2/silk/sigm_Q15.c @@ -0,0 +1,76 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* Approximate sigmoid function */ + +#include "SigProc_FIX.h" + +/* fprintf(1, '%d, ', round(1024 * ([1 ./ (1 + exp(-(1:5))), 1] - 1 ./ (1 + exp(-(0:5)))))); */ +static const opus_int32 sigm_LUT_slope_Q10[ 6 ] = { + 237, 153, 73, 30, 12, 7 +}; +/* fprintf(1, '%d, ', round(32767 * 1 ./ (1 + exp(-(0:5))))); */ +static const opus_int32 sigm_LUT_pos_Q15[ 6 ] = { + 16384, 23955, 28861, 31213, 32178, 32548 +}; +/* fprintf(1, '%d, ', round(32767 * 1 ./ (1 + exp((0:5))))); */ +static const opus_int32 sigm_LUT_neg_Q15[ 6 ] = { + 16384, 8812, 3906, 1554, 589, 219 +}; + +opus_int silk_sigm_Q15( + opus_int in_Q5 /* I */ +) +{ + opus_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 = silk_RSHIFT( in_Q5, 5 ); + return( sigm_LUT_neg_Q15[ ind ] - silk_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 = silk_RSHIFT( in_Q5, 5 ); + return( sigm_LUT_pos_Q15[ ind ] + silk_SMULBB( sigm_LUT_slope_Q10[ ind ], in_Q5 & 0x1F ) ); + } + } +} + diff --git a/code/opus-1.0.2/silk/sort.c b/code/opus-1.0.2/silk/sort.c new file mode 100644 index 00000000..a4072ec4 --- /dev/null +++ b/code/opus-1.0.2/silk/sort.c @@ -0,0 +1,154 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* 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 */ +/* */ +/* Shell short: http://en.wikipedia.org/wiki/Shell_sort */ + +#include "SigProc_FIX.h" + +void silk_insertion_sort_increasing( + opus_int32 *a, /* I/O Unsorted / Sorted vector */ + opus_int *idx, /* O Index vector for the sorted elements */ + const opus_int L, /* I Vector length */ + const opus_int K /* I Number of correctly sorted positions */ +) +{ + opus_int32 value; + opus_int i, j; + + /* Safety checks */ + silk_assert( K > 0 ); + silk_assert( L > 0 ); + silk_assert( L >= K ); + + /* Write start indices in index vector */ + for( i = 0; i < K; i++ ) { + idx[ 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 */ + idx[ j + 1 ] = idx[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + idx[ 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 */ + idx[ j + 1 ] = idx[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + idx[ j + 1 ] = i; /* Write index */ + } + } +} + +#ifdef FIXED_POINT +/* This function is only used by the fixed-point build */ +void silk_insertion_sort_decreasing_int16( + opus_int16 *a, /* I/O Unsorted / Sorted vector */ + opus_int *idx, /* O Index vector for the sorted elements */ + const opus_int L, /* I Vector length */ + const opus_int K /* I Number of correctly sorted positions */ +) +{ + opus_int i, j; + opus_int value; + + /* Safety checks */ + silk_assert( K > 0 ); + silk_assert( L > 0 ); + silk_assert( L >= K ); + + /* Write start indices in index vector */ + for( i = 0; i < K; i++ ) { + idx[ 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 */ + idx[ j + 1 ] = idx[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + idx[ 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 */ + idx[ j + 1 ] = idx[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + idx[ j + 1 ] = i; /* Write index */ + } + } +} +#endif + +void silk_insertion_sort_increasing_all_values_int16( + opus_int16 *a, /* I/O Unsorted / Sorted vector */ + const opus_int L /* I Vector length */ +) +{ + opus_int value; + opus_int i, j; + + /* Safety checks */ + silk_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/code/opus-1.0.2/silk/stereo_LR_to_MS.c b/code/opus-1.0.2/silk/stereo_LR_to_MS.c new file mode 100644 index 00000000..6a680e09 --- /dev/null +++ b/code/opus-1.0.2/silk/stereo_LR_to_MS.c @@ -0,0 +1,219 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Convert Left/Right stereo signal to adaptive Mid/Side representation */ +void silk_stereo_LR_to_MS( + stereo_enc_state *state, /* I/O State */ + opus_int16 x1[], /* I/O Left input signal, becomes mid signal */ + opus_int16 x2[], /* I/O Right input signal, becomes side signal */ + opus_int8 ix[ 2 ][ 3 ], /* O Quantization indices */ + opus_int8 *mid_only_flag, /* O Flag: only mid signal coded */ + opus_int32 mid_side_rates_bps[], /* O Bitrates for mid and side signals */ + opus_int32 total_rate_bps, /* I Total bitrate */ + opus_int prev_speech_act_Q8, /* I Speech activity level in previous frame */ + opus_int toMono, /* I Last frame before a stereo->mono transition */ + opus_int fs_kHz, /* I Sample rate (kHz) */ + opus_int frame_length /* I Number of samples */ +) +{ + opus_int n, is10msFrame, denom_Q16, delta0_Q13, delta1_Q13; + opus_int32 sum, diff, smooth_coef_Q16, pred_Q13[ 2 ], pred0_Q13, pred1_Q13; + opus_int32 LP_ratio_Q14, HP_ratio_Q14, frac_Q16, frac_3_Q16, min_mid_rate_bps, width_Q14, w_Q24, deltaw_Q24; + opus_int16 side[ MAX_FRAME_LENGTH + 2 ]; + opus_int16 LP_mid[ MAX_FRAME_LENGTH ], HP_mid[ MAX_FRAME_LENGTH ]; + opus_int16 LP_side[ MAX_FRAME_LENGTH ], HP_side[ MAX_FRAME_LENGTH ]; + opus_int16 *mid = &x1[ -2 ]; + + /* Convert to basic mid/side signals */ + for( n = 0; n < frame_length + 2; n++ ) { + sum = x1[ n - 2 ] + (opus_int32)x2[ n - 2 ]; + diff = x1[ n - 2 ] - (opus_int32)x2[ n - 2 ]; + mid[ n ] = (opus_int16)silk_RSHIFT_ROUND( sum, 1 ); + side[ n ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( diff, 1 ) ); + } + + /* Buffering */ + silk_memcpy( mid, state->sMid, 2 * sizeof( opus_int16 ) ); + silk_memcpy( side, state->sSide, 2 * sizeof( opus_int16 ) ); + silk_memcpy( state->sMid, &mid[ frame_length ], 2 * sizeof( opus_int16 ) ); + silk_memcpy( state->sSide, &side[ frame_length ], 2 * sizeof( opus_int16 ) ); + + /* LP and HP filter mid signal */ + for( n = 0; n < frame_length; n++ ) { + sum = silk_RSHIFT_ROUND( silk_ADD_LSHIFT( mid[ n ] + mid[ n + 2 ], mid[ n + 1 ], 1 ), 2 ); + LP_mid[ n ] = sum; + HP_mid[ n ] = mid[ n + 1 ] - sum; + } + + /* LP and HP filter side signal */ + for( n = 0; n < frame_length; n++ ) { + sum = silk_RSHIFT_ROUND( silk_ADD_LSHIFT( side[ n ] + side[ n + 2 ], side[ n + 1 ], 1 ), 2 ); + LP_side[ n ] = sum; + HP_side[ n ] = side[ n + 1 ] - sum; + } + + /* Find energies and predictors */ + is10msFrame = frame_length == 10 * fs_kHz; + smooth_coef_Q16 = is10msFrame ? + SILK_FIX_CONST( STEREO_RATIO_SMOOTH_COEF / 2, 16 ) : + SILK_FIX_CONST( STEREO_RATIO_SMOOTH_COEF, 16 ); + smooth_coef_Q16 = silk_SMULWB( silk_SMULBB( prev_speech_act_Q8, prev_speech_act_Q8 ), smooth_coef_Q16 ); + + pred_Q13[ 0 ] = silk_stereo_find_predictor( &LP_ratio_Q14, LP_mid, LP_side, &state->mid_side_amp_Q0[ 0 ], frame_length, smooth_coef_Q16 ); + pred_Q13[ 1 ] = silk_stereo_find_predictor( &HP_ratio_Q14, HP_mid, HP_side, &state->mid_side_amp_Q0[ 2 ], frame_length, smooth_coef_Q16 ); + /* Ratio of the norms of residual and mid signals */ + frac_Q16 = silk_SMLABB( HP_ratio_Q14, LP_ratio_Q14, 3 ); + frac_Q16 = silk_min( frac_Q16, SILK_FIX_CONST( 1, 16 ) ); + + /* Determine bitrate distribution between mid and side, and possibly reduce stereo width */ + total_rate_bps -= is10msFrame ? 1200 : 600; /* Subtract approximate bitrate for coding stereo parameters */ + if( total_rate_bps < 1 ) { + total_rate_bps = 1; + } + min_mid_rate_bps = silk_SMLABB( 2000, fs_kHz, 900 ); + silk_assert( min_mid_rate_bps < 32767 ); + /* Default bitrate distribution: 8 parts for Mid and (5+3*frac) parts for Side. so: mid_rate = ( 8 / ( 13 + 3 * frac ) ) * total_ rate */ + frac_3_Q16 = silk_MUL( 3, frac_Q16 ); + mid_side_rates_bps[ 0 ] = silk_DIV32_varQ( total_rate_bps, SILK_FIX_CONST( 8 + 5, 16 ) + frac_3_Q16, 16+3 ); + /* If Mid bitrate below minimum, reduce stereo width */ + if( mid_side_rates_bps[ 0 ] < min_mid_rate_bps ) { + mid_side_rates_bps[ 0 ] = min_mid_rate_bps; + mid_side_rates_bps[ 1 ] = total_rate_bps - mid_side_rates_bps[ 0 ]; + /* width = 4 * ( 2 * side_rate - min_rate ) / ( ( 1 + 3 * frac ) * min_rate ) */ + width_Q14 = silk_DIV32_varQ( silk_LSHIFT( mid_side_rates_bps[ 1 ], 1 ) - min_mid_rate_bps, + silk_SMULWB( SILK_FIX_CONST( 1, 16 ) + frac_3_Q16, min_mid_rate_bps ), 14+2 ); + width_Q14 = silk_LIMIT( width_Q14, 0, SILK_FIX_CONST( 1, 14 ) ); + } else { + mid_side_rates_bps[ 1 ] = total_rate_bps - mid_side_rates_bps[ 0 ]; + width_Q14 = SILK_FIX_CONST( 1, 14 ); + } + + /* Smoother */ + state->smth_width_Q14 = (opus_int16)silk_SMLAWB( state->smth_width_Q14, width_Q14 - state->smth_width_Q14, smooth_coef_Q16 ); + + /* At very low bitrates or for inputs that are nearly amplitude panned, switch to panned-mono coding */ + *mid_only_flag = 0; + if( toMono ) { + /* Last frame before stereo->mono transition; collapse stereo width */ + width_Q14 = 0; + pred_Q13[ 0 ] = 0; + pred_Q13[ 1 ] = 0; + silk_stereo_quant_pred( pred_Q13, ix ); + } else if( state->width_prev_Q14 == 0 && + ( 8 * total_rate_bps < 13 * min_mid_rate_bps || silk_SMULWB( frac_Q16, state->smth_width_Q14 ) < SILK_FIX_CONST( 0.05, 14 ) ) ) + { + /* Code as panned-mono; previous frame already had zero width */ + /* Scale down and quantize predictors */ + pred_Q13[ 0 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 0 ] ), 14 ); + pred_Q13[ 1 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 1 ] ), 14 ); + silk_stereo_quant_pred( pred_Q13, ix ); + /* Collapse stereo width */ + width_Q14 = 0; + pred_Q13[ 0 ] = 0; + pred_Q13[ 1 ] = 0; + mid_side_rates_bps[ 0 ] = total_rate_bps; + mid_side_rates_bps[ 1 ] = 0; + *mid_only_flag = 1; + } else if( state->width_prev_Q14 != 0 && + ( 8 * total_rate_bps < 11 * min_mid_rate_bps || silk_SMULWB( frac_Q16, state->smth_width_Q14 ) < SILK_FIX_CONST( 0.02, 14 ) ) ) + { + /* Transition to zero-width stereo */ + /* Scale down and quantize predictors */ + pred_Q13[ 0 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 0 ] ), 14 ); + pred_Q13[ 1 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 1 ] ), 14 ); + silk_stereo_quant_pred( pred_Q13, ix ); + /* Collapse stereo width */ + width_Q14 = 0; + pred_Q13[ 0 ] = 0; + pred_Q13[ 1 ] = 0; + } else if( state->smth_width_Q14 > SILK_FIX_CONST( 0.95, 14 ) ) { + /* Full-width stereo coding */ + silk_stereo_quant_pred( pred_Q13, ix ); + width_Q14 = SILK_FIX_CONST( 1, 14 ); + } else { + /* Reduced-width stereo coding; scale down and quantize predictors */ + pred_Q13[ 0 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 0 ] ), 14 ); + pred_Q13[ 1 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 1 ] ), 14 ); + silk_stereo_quant_pred( pred_Q13, ix ); + width_Q14 = state->smth_width_Q14; + } + + /* Make sure to keep on encoding until the tapered output has been transmitted */ + if( *mid_only_flag == 1 ) { + state->silent_side_len += frame_length - STEREO_INTERP_LEN_MS * fs_kHz; + if( state->silent_side_len < LA_SHAPE_MS * fs_kHz ) { + *mid_only_flag = 0; + } else { + /* Limit to avoid wrapping around */ + state->silent_side_len = 10000; + } + } else { + state->silent_side_len = 0; + } + + if( *mid_only_flag == 0 && mid_side_rates_bps[ 1 ] < 1 ) { + mid_side_rates_bps[ 1 ] = 1; + mid_side_rates_bps[ 0 ] = silk_max_int( 1, total_rate_bps - mid_side_rates_bps[ 1 ]); + } + + /* Interpolate predictors and subtract prediction from side channel */ + pred0_Q13 = -state->pred_prev_Q13[ 0 ]; + pred1_Q13 = -state->pred_prev_Q13[ 1 ]; + w_Q24 = silk_LSHIFT( state->width_prev_Q14, 10 ); + denom_Q16 = silk_DIV32_16( (opus_int32)1 << 16, STEREO_INTERP_LEN_MS * fs_kHz ); + delta0_Q13 = -silk_RSHIFT_ROUND( silk_SMULBB( pred_Q13[ 0 ] - state->pred_prev_Q13[ 0 ], denom_Q16 ), 16 ); + delta1_Q13 = -silk_RSHIFT_ROUND( silk_SMULBB( pred_Q13[ 1 ] - state->pred_prev_Q13[ 1 ], denom_Q16 ), 16 ); + deltaw_Q24 = silk_LSHIFT( silk_SMULWB( width_Q14 - state->width_prev_Q14, denom_Q16 ), 10 ); + for( n = 0; n < STEREO_INTERP_LEN_MS * fs_kHz; n++ ) { + pred0_Q13 += delta0_Q13; + pred1_Q13 += delta1_Q13; + w_Q24 += deltaw_Q24; + sum = silk_LSHIFT( silk_ADD_LSHIFT( mid[ n ] + mid[ n + 2 ], mid[ n + 1 ], 1 ), 9 ); /* Q11 */ + sum = silk_SMLAWB( silk_SMULWB( w_Q24, side[ n + 1 ] ), sum, pred0_Q13 ); /* Q8 */ + sum = silk_SMLAWB( sum, silk_LSHIFT( (opus_int32)mid[ n + 1 ], 11 ), pred1_Q13 ); /* Q8 */ + x2[ n - 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sum, 8 ) ); + } + + pred0_Q13 = -pred_Q13[ 0 ]; + pred1_Q13 = -pred_Q13[ 1 ]; + w_Q24 = silk_LSHIFT( width_Q14, 10 ); + for( n = STEREO_INTERP_LEN_MS * fs_kHz; n < frame_length; n++ ) { + sum = silk_LSHIFT( silk_ADD_LSHIFT( mid[ n ] + mid[ n + 2 ], mid[ n + 1 ], 1 ), 9 ); /* Q11 */ + sum = silk_SMLAWB( silk_SMULWB( w_Q24, side[ n + 1 ] ), sum, pred0_Q13 ); /* Q8 */ + sum = silk_SMLAWB( sum, silk_LSHIFT( (opus_int32)mid[ n + 1 ], 11 ), pred1_Q13 ); /* Q8 */ + x2[ n - 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sum, 8 ) ); + } + state->pred_prev_Q13[ 0 ] = (opus_int16)pred_Q13[ 0 ]; + state->pred_prev_Q13[ 1 ] = (opus_int16)pred_Q13[ 1 ]; + state->width_prev_Q14 = (opus_int16)width_Q14; +} diff --git a/code/opus-1.0.2/silk/stereo_MS_to_LR.c b/code/opus-1.0.2/silk/stereo_MS_to_LR.c new file mode 100644 index 00000000..23515870 --- /dev/null +++ b/code/opus-1.0.2/silk/stereo_MS_to_LR.c @@ -0,0 +1,85 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Convert adaptive Mid/Side representation to Left/Right stereo signal */ +void silk_stereo_MS_to_LR( + stereo_dec_state *state, /* I/O State */ + opus_int16 x1[], /* I/O Left input signal, becomes mid signal */ + opus_int16 x2[], /* I/O Right input signal, becomes side signal */ + const opus_int32 pred_Q13[], /* I Predictors */ + opus_int fs_kHz, /* I Samples rate (kHz) */ + opus_int frame_length /* I Number of samples */ +) +{ + opus_int n, denom_Q16, delta0_Q13, delta1_Q13; + opus_int32 sum, diff, pred0_Q13, pred1_Q13; + + /* Buffering */ + silk_memcpy( x1, state->sMid, 2 * sizeof( opus_int16 ) ); + silk_memcpy( x2, state->sSide, 2 * sizeof( opus_int16 ) ); + silk_memcpy( state->sMid, &x1[ frame_length ], 2 * sizeof( opus_int16 ) ); + silk_memcpy( state->sSide, &x2[ frame_length ], 2 * sizeof( opus_int16 ) ); + + /* Interpolate predictors and add prediction to side channel */ + pred0_Q13 = state->pred_prev_Q13[ 0 ]; + pred1_Q13 = state->pred_prev_Q13[ 1 ]; + denom_Q16 = silk_DIV32_16( (opus_int32)1 << 16, STEREO_INTERP_LEN_MS * fs_kHz ); + delta0_Q13 = silk_RSHIFT_ROUND( silk_SMULBB( pred_Q13[ 0 ] - state->pred_prev_Q13[ 0 ], denom_Q16 ), 16 ); + delta1_Q13 = silk_RSHIFT_ROUND( silk_SMULBB( pred_Q13[ 1 ] - state->pred_prev_Q13[ 1 ], denom_Q16 ), 16 ); + for( n = 0; n < STEREO_INTERP_LEN_MS * fs_kHz; n++ ) { + pred0_Q13 += delta0_Q13; + pred1_Q13 += delta1_Q13; + sum = silk_LSHIFT( silk_ADD_LSHIFT( x1[ n ] + x1[ n + 2 ], x1[ n + 1 ], 1 ), 9 ); /* Q11 */ + sum = silk_SMLAWB( silk_LSHIFT( (opus_int32)x2[ n + 1 ], 8 ), sum, pred0_Q13 ); /* Q8 */ + sum = silk_SMLAWB( sum, silk_LSHIFT( (opus_int32)x1[ n + 1 ], 11 ), pred1_Q13 ); /* Q8 */ + x2[ n + 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sum, 8 ) ); + } + pred0_Q13 = pred_Q13[ 0 ]; + pred1_Q13 = pred_Q13[ 1 ]; + for( n = STEREO_INTERP_LEN_MS * fs_kHz; n < frame_length; n++ ) { + sum = silk_LSHIFT( silk_ADD_LSHIFT( x1[ n ] + x1[ n + 2 ], x1[ n + 1 ], 1 ), 9 ); /* Q11 */ + sum = silk_SMLAWB( silk_LSHIFT( (opus_int32)x2[ n + 1 ], 8 ), sum, pred0_Q13 ); /* Q8 */ + sum = silk_SMLAWB( sum, silk_LSHIFT( (opus_int32)x1[ n + 1 ], 11 ), pred1_Q13 ); /* Q8 */ + x2[ n + 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sum, 8 ) ); + } + state->pred_prev_Q13[ 0 ] = pred_Q13[ 0 ]; + state->pred_prev_Q13[ 1 ] = pred_Q13[ 1 ]; + + /* Convert to left/right signals */ + for( n = 0; n < frame_length; n++ ) { + sum = x1[ n + 1 ] + (opus_int32)x2[ n + 1 ]; + diff = x1[ n + 1 ] - (opus_int32)x2[ n + 1 ]; + x1[ n + 1 ] = (opus_int16)silk_SAT16( sum ); + x2[ n + 1 ] = (opus_int16)silk_SAT16( diff ); + } +} diff --git a/code/opus-1.0.2/silk/stereo_decode_pred.c b/code/opus-1.0.2/silk/stereo_decode_pred.c new file mode 100644 index 00000000..026aa7a0 --- /dev/null +++ b/code/opus-1.0.2/silk/stereo_decode_pred.c @@ -0,0 +1,73 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Decode mid/side predictors */ +void silk_stereo_decode_pred( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int32 pred_Q13[] /* O Predictors */ +) +{ + opus_int n, ix[ 2 ][ 3 ]; + opus_int32 low_Q13, step_Q13; + + /* Entropy decoding */ + n = ec_dec_icdf( psRangeDec, silk_stereo_pred_joint_iCDF, 8 ); + ix[ 0 ][ 2 ] = silk_DIV32_16( n, 5 ); + ix[ 1 ][ 2 ] = n - 5 * ix[ 0 ][ 2 ]; + for( n = 0; n < 2; n++ ) { + ix[ n ][ 0 ] = ec_dec_icdf( psRangeDec, silk_uniform3_iCDF, 8 ); + ix[ n ][ 1 ] = ec_dec_icdf( psRangeDec, silk_uniform5_iCDF, 8 ); + } + + /* Dequantize */ + for( n = 0; n < 2; n++ ) { + ix[ n ][ 0 ] += 3 * ix[ n ][ 2 ]; + low_Q13 = silk_stereo_pred_quant_Q13[ ix[ n ][ 0 ] ]; + step_Q13 = silk_SMULWB( silk_stereo_pred_quant_Q13[ ix[ n ][ 0 ] + 1 ] - low_Q13, + SILK_FIX_CONST( 0.5 / STEREO_QUANT_SUB_STEPS, 16 ) ); + pred_Q13[ n ] = silk_SMLABB( low_Q13, step_Q13, 2 * ix[ n ][ 1 ] + 1 ); + } + + /* Subtract second from first predictor (helps when actually applying these) */ + pred_Q13[ 0 ] -= pred_Q13[ 1 ]; +} + +/* Decode mid-only flag */ +void silk_stereo_decode_mid_only( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int *decode_only_mid /* O Flag that only mid channel has been coded */ +) +{ + /* Decode flag that only mid channel is coded */ + *decode_only_mid = ec_dec_icdf( psRangeDec, silk_stereo_only_code_mid_iCDF, 8 ); +} diff --git a/code/opus-1.0.2/silk/stereo_encode_pred.c b/code/opus-1.0.2/silk/stereo_encode_pred.c new file mode 100644 index 00000000..3cffd367 --- /dev/null +++ b/code/opus-1.0.2/silk/stereo_encode_pred.c @@ -0,0 +1,62 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Entropy code the mid/side quantization indices */ +void silk_stereo_encode_pred( + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int8 ix[ 2 ][ 3 ] /* I Quantization indices */ +) +{ + opus_int n; + + /* Entropy coding */ + n = 5 * ix[ 0 ][ 2 ] + ix[ 1 ][ 2 ]; + silk_assert( n < 25 ); + ec_enc_icdf( psRangeEnc, n, silk_stereo_pred_joint_iCDF, 8 ); + for( n = 0; n < 2; n++ ) { + silk_assert( ix[ n ][ 0 ] < 3 ); + silk_assert( ix[ n ][ 1 ] < STEREO_QUANT_SUB_STEPS ); + ec_enc_icdf( psRangeEnc, ix[ n ][ 0 ], silk_uniform3_iCDF, 8 ); + ec_enc_icdf( psRangeEnc, ix[ n ][ 1 ], silk_uniform5_iCDF, 8 ); + } +} + +/* Entropy code the mid-only flag */ +void silk_stereo_encode_mid_only( + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int8 mid_only_flag +) +{ + /* Encode flag that only mid channel is coded */ + ec_enc_icdf( psRangeEnc, mid_only_flag, silk_stereo_only_code_mid_iCDF, 8 ); +} diff --git a/code/opus-1.0.2/silk/stereo_find_predictor.c b/code/opus-1.0.2/silk/stereo_find_predictor.c new file mode 100644 index 00000000..aec58dab --- /dev/null +++ b/code/opus-1.0.2/silk/stereo_find_predictor.c @@ -0,0 +1,79 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Find least-squares prediction gain for one signal based on another and quantize it */ +opus_int32 silk_stereo_find_predictor( /* O Returns predictor in Q13 */ + opus_int32 *ratio_Q14, /* O Ratio of residual and mid energies */ + const opus_int16 x[], /* I Basis signal */ + const opus_int16 y[], /* I Target signal */ + opus_int32 mid_res_amp_Q0[], /* I/O Smoothed mid, residual norms */ + opus_int length, /* I Number of samples */ + opus_int smooth_coef_Q16 /* I Smoothing coefficient */ +) +{ + opus_int scale, scale1, scale2; + opus_int32 nrgx, nrgy, corr, pred_Q13, pred2_Q10; + + /* Find predictor */ + silk_sum_sqr_shift( &nrgx, &scale1, x, length ); + silk_sum_sqr_shift( &nrgy, &scale2, y, length ); + scale = silk_max_int( scale1, scale2 ); + scale = scale + ( scale & 1 ); /* make even */ + nrgy = silk_RSHIFT32( nrgy, scale - scale2 ); + nrgx = silk_RSHIFT32( nrgx, scale - scale1 ); + nrgx = silk_max_int( nrgx, 1 ); + corr = silk_inner_prod_aligned_scale( x, y, scale, length ); + pred_Q13 = silk_DIV32_varQ( corr, nrgx, 13 ); + pred_Q13 = silk_LIMIT( pred_Q13, -(1 << 14), 1 << 14 ); + pred2_Q10 = silk_SMULWB( pred_Q13, pred_Q13 ); + + /* Faster update for signals with large prediction parameters */ + smooth_coef_Q16 = (opus_int)silk_max_int( smooth_coef_Q16, silk_abs( pred2_Q10 ) ); + + /* Smoothed mid and residual norms */ + silk_assert( smooth_coef_Q16 < 32768 ); + scale = silk_RSHIFT( scale, 1 ); + mid_res_amp_Q0[ 0 ] = silk_SMLAWB( mid_res_amp_Q0[ 0 ], silk_LSHIFT( silk_SQRT_APPROX( nrgx ), scale ) - mid_res_amp_Q0[ 0 ], + smooth_coef_Q16 ); + /* Residual energy = nrgy - 2 * pred * corr + pred^2 * nrgx */ + nrgy = silk_SUB_LSHIFT32( nrgy, silk_SMULWB( corr, pred_Q13 ), 3 + 1 ); + nrgy = silk_ADD_LSHIFT32( nrgy, silk_SMULWB( nrgx, pred2_Q10 ), 6 ); + mid_res_amp_Q0[ 1 ] = silk_SMLAWB( mid_res_amp_Q0[ 1 ], silk_LSHIFT( silk_SQRT_APPROX( nrgy ), scale ) - mid_res_amp_Q0[ 1 ], + smooth_coef_Q16 ); + + /* Ratio of smoothed residual and mid norms */ + *ratio_Q14 = silk_DIV32_varQ( mid_res_amp_Q0[ 1 ], silk_max( mid_res_amp_Q0[ 0 ], 1 ), 14 ); + *ratio_Q14 = silk_LIMIT( *ratio_Q14, 0, 32767 ); + + return pred_Q13; +} diff --git a/code/opus-1.0.2/silk/stereo_quant_pred.c b/code/opus-1.0.2/silk/stereo_quant_pred.c new file mode 100644 index 00000000..df97c9f6 --- /dev/null +++ b/code/opus-1.0.2/silk/stereo_quant_pred.c @@ -0,0 +1,73 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "main.h" + +/* Quantize mid/side predictors */ +void silk_stereo_quant_pred( + opus_int32 pred_Q13[], /* I/O Predictors (out: quantized) */ + opus_int8 ix[ 2 ][ 3 ] /* O Quantization indices */ +) +{ + opus_int i, j, n; + opus_int32 low_Q13, step_Q13, lvl_Q13, err_min_Q13, err_Q13, quant_pred_Q13 = 0; + + /* Quantize */ + for( n = 0; n < 2; n++ ) { + /* Brute-force search over quantization levels */ + err_min_Q13 = silk_int32_MAX; + for( i = 0; i < STEREO_QUANT_TAB_SIZE - 1; i++ ) { + low_Q13 = silk_stereo_pred_quant_Q13[ i ]; + step_Q13 = silk_SMULWB( silk_stereo_pred_quant_Q13[ i + 1 ] - low_Q13, + SILK_FIX_CONST( 0.5 / STEREO_QUANT_SUB_STEPS, 16 ) ); + for( j = 0; j < STEREO_QUANT_SUB_STEPS; j++ ) { + lvl_Q13 = silk_SMLABB( low_Q13, step_Q13, 2 * j + 1 ); + err_Q13 = silk_abs( pred_Q13[ n ] - lvl_Q13 ); + if( err_Q13 < err_min_Q13 ) { + err_min_Q13 = err_Q13; + quant_pred_Q13 = lvl_Q13; + ix[ n ][ 0 ] = i; + ix[ n ][ 1 ] = j; + } else { + /* Error increasing, so we're past the optimum */ + goto done; + } + } + } + done: + ix[ n ][ 2 ] = silk_DIV32_16( ix[ n ][ 0 ], 3 ); + ix[ n ][ 0 ] -= ix[ n ][ 2 ] * 3; + pred_Q13[ n ] = quant_pred_Q13; + } + + /* Subtract second from first predictor (helps when actually applying these) */ + pred_Q13[ 0 ] -= pred_Q13[ 1 ]; +} diff --git a/code/opus-1.0.2/silk/structs.h b/code/opus-1.0.2/silk/structs.h new file mode 100644 index 00000000..5d37f660 --- /dev/null +++ b/code/opus-1.0.2/silk/structs.h @@ -0,0 +1,324 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (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 SILK_STRUCTS_H +#define SILK_STRUCTS_H + +#include "typedef.h" +#include "SigProc_FIX.h" +#include "define.h" +#include "entenc.h" +#include "entdec.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/************************************/ +/* Noise shaping quantization state */ +/************************************/ +typedef struct { + opus_int16 xq[ 2 * MAX_FRAME_LENGTH ]; /* Buffer for quantized output signal */ + opus_int32 sLTP_shp_Q14[ 2 * MAX_FRAME_LENGTH ]; + opus_int32 sLPC_Q14[ MAX_SUB_FRAME_LENGTH + NSQ_LPC_BUF_LENGTH ]; + opus_int32 sAR2_Q14[ MAX_SHAPE_LPC_ORDER ]; + opus_int32 sLF_AR_shp_Q14; + opus_int lagPrev; + opus_int sLTP_buf_idx; + opus_int sLTP_shp_buf_idx; + opus_int32 rand_seed; + opus_int32 prev_gain_Q16; + opus_int rewhite_flag; +} silk_nsq_state; + +/********************************/ +/* VAD state */ +/********************************/ +typedef struct { + opus_int32 AnaState[ 2 ]; /* Analysis filterbank state: 0-8 kHz */ + opus_int32 AnaState1[ 2 ]; /* Analysis filterbank state: 0-4 kHz */ + opus_int32 AnaState2[ 2 ]; /* Analysis filterbank state: 0-2 kHz */ + opus_int32 XnrgSubfr[ VAD_N_BANDS ]; /* Subframe energies */ + opus_int32 NrgRatioSmth_Q8[ VAD_N_BANDS ]; /* Smoothed energy level in each band */ + opus_int16 HPstate; /* State of differentiator in the lowest band */ + opus_int32 NL[ VAD_N_BANDS ]; /* Noise energy level in each band */ + opus_int32 inv_NL[ VAD_N_BANDS ]; /* Inverse noise energy level in each band */ + opus_int32 NoiseLevelBias[ VAD_N_BANDS ]; /* Noise level estimator bias/offset */ + opus_int32 counter; /* Frame counter used in the initial phase */ +} silk_VAD_state; + +/* Variable cut-off low-pass filter state */ +typedef struct { + opus_int32 In_LP_State[ 2 ]; /* Low pass filter state */ + opus_int32 transition_frame_no; /* Counter which is mapped to a cut-off frequency */ + opus_int mode; /* Operating mode, <0: switch down, >0: switch up; 0: do nothing */ +} silk_LP_state; + +/* Structure containing NLSF codebook */ +typedef struct { + const opus_int16 nVectors; + const opus_int16 order; + const opus_int16 quantStepSize_Q16; + const opus_int16 invQuantStepSize_Q6; + const opus_uint8 *CB1_NLSF_Q8; + const opus_uint8 *CB1_iCDF; + const opus_uint8 *pred_Q8; + const opus_uint8 *ec_sel; + const opus_uint8 *ec_iCDF; + const opus_uint8 *ec_Rates_Q5; + const opus_int16 *deltaMin_Q15; +} silk_NLSF_CB_struct; + +typedef struct { + opus_int16 pred_prev_Q13[ 2 ]; + opus_int16 sMid[ 2 ]; + opus_int16 sSide[ 2 ]; + opus_int32 mid_side_amp_Q0[ 4 ]; + opus_int16 smth_width_Q14; + opus_int16 width_prev_Q14; + opus_int16 silent_side_len; + opus_int8 predIx[ MAX_FRAMES_PER_PACKET ][ 2 ][ 3 ]; + opus_int8 mid_only_flags[ MAX_FRAMES_PER_PACKET ]; +} stereo_enc_state; + +typedef struct { + opus_int16 pred_prev_Q13[ 2 ]; + opus_int16 sMid[ 2 ]; + opus_int16 sSide[ 2 ]; +} stereo_dec_state; + +typedef struct { + opus_int8 GainsIndices[ MAX_NB_SUBFR ]; + opus_int8 LTPIndex[ MAX_NB_SUBFR ]; + opus_int8 NLSFIndices[ MAX_LPC_ORDER + 1 ]; + opus_int16 lagIndex; + opus_int8 contourIndex; + opus_int8 signalType; + opus_int8 quantOffsetType; + opus_int8 NLSFInterpCoef_Q2; + opus_int8 PERIndex; + opus_int8 LTP_scaleIndex; + opus_int8 Seed; +} SideInfoIndices; + +/********************************/ +/* Encoder state */ +/********************************/ +typedef struct { + opus_int32 In_HP_State[ 2 ]; /* High pass filter state */ + opus_int32 variable_HP_smth1_Q15; /* State of first smoother */ + opus_int32 variable_HP_smth2_Q15; /* State of second smoother */ + silk_LP_state sLP; /* Low pass filter state */ + silk_VAD_state sVAD; /* Voice activity detector state */ + silk_nsq_state sNSQ; /* Noise Shape Quantizer State */ + opus_int16 prev_NLSFq_Q15[ MAX_LPC_ORDER ]; /* Previously quantized NLSF vector */ + opus_int speech_activity_Q8; /* Speech activity */ + opus_int allow_bandwidth_switch; /* Flag indicating that switching of internal bandwidth is allowed */ + opus_int8 LBRRprevLastGainIndex; + opus_int8 prevSignalType; + opus_int prevLag; + opus_int pitch_LPC_win_length; + opus_int max_pitch_lag; /* Highest possible pitch lag (samples) */ + opus_int32 API_fs_Hz; /* API sampling frequency (Hz) */ + opus_int32 prev_API_fs_Hz; /* Previous API sampling frequency (Hz) */ + opus_int maxInternal_fs_Hz; /* Maximum internal sampling frequency (Hz) */ + opus_int minInternal_fs_Hz; /* Minimum internal sampling frequency (Hz) */ + opus_int desiredInternal_fs_Hz; /* Soft request for internal sampling frequency (Hz) */ + opus_int fs_kHz; /* Internal sampling frequency (kHz) */ + opus_int nb_subfr; /* Number of 5 ms subframes in a frame */ + opus_int frame_length; /* Frame length (samples) */ + opus_int subfr_length; /* Subframe length (samples) */ + opus_int ltp_mem_length; /* Length of LTP memory */ + opus_int la_pitch; /* Look-ahead for pitch analysis (samples) */ + opus_int la_shape; /* Look-ahead for noise shape analysis (samples) */ + opus_int shapeWinLength; /* Window length for noise shape analysis (samples) */ + opus_int32 TargetRate_bps; /* Target bitrate (bps) */ + opus_int PacketSize_ms; /* Number of milliseconds to put in each packet */ + opus_int PacketLoss_perc; /* Packet loss rate measured by farend */ + opus_int32 frameCounter; + opus_int Complexity; /* Complexity setting */ + opus_int nStatesDelayedDecision; /* Number of states in delayed decision quantization */ + opus_int useInterpolatedNLSFs; /* Flag for using NLSF interpolation */ + opus_int shapingLPCOrder; /* Filter order for noise shaping filters */ + opus_int predictLPCOrder; /* Filter order for prediction filters */ + opus_int pitchEstimationComplexity; /* Complexity level for pitch estimator */ + opus_int pitchEstimationLPCOrder; /* Whitening filter order for pitch estimator */ + opus_int32 pitchEstimationThreshold_Q16; /* Threshold for pitch estimator */ + opus_int LTPQuantLowComplexity; /* Flag for low complexity LTP quantization */ + opus_int mu_LTP_Q9; /* Rate-distortion tradeoff in LTP quantization */ + opus_int NLSF_MSVQ_Survivors; /* Number of survivors in NLSF MSVQ */ + opus_int first_frame_after_reset; /* Flag for deactivating NLSF interpolation, pitch prediction */ + opus_int controlled_since_last_payload; /* Flag for ensuring codec_control only runs once per packet */ + opus_int warping_Q16; /* Warping parameter for warped noise shaping */ + opus_int useCBR; /* Flag to enable constant bitrate */ + opus_int prefillFlag; /* Flag to indicate that only buffers are prefilled, no coding */ + const opus_uint8 *pitch_lag_low_bits_iCDF; /* Pointer to iCDF table for low bits of pitch lag index */ + const opus_uint8 *pitch_contour_iCDF; /* Pointer to iCDF table for pitch contour index */ + const silk_NLSF_CB_struct *psNLSF_CB; /* Pointer to NLSF codebook */ + opus_int input_quality_bands_Q15[ VAD_N_BANDS ]; + opus_int input_tilt_Q15; + opus_int SNR_dB_Q7; /* Quality setting */ + + opus_int8 VAD_flags[ MAX_FRAMES_PER_PACKET ]; + opus_int8 LBRR_flag; + opus_int LBRR_flags[ MAX_FRAMES_PER_PACKET ]; + + SideInfoIndices indices; + opus_int8 pulses[ MAX_FRAME_LENGTH ]; + + /* Input/output buffering */ + opus_int16 inputBuf[ MAX_FRAME_LENGTH + 2 ]; /* Buffer containing input signal */ + opus_int inputBufIx; + opus_int nFramesPerPacket; + opus_int nFramesEncoded; /* Number of frames analyzed in current packet */ + + opus_int nChannelsAPI; + opus_int nChannelsInternal; + opus_int channelNb; + + /* Parameters For LTP scaling Control */ + opus_int frames_since_onset; + + /* Specifically for entropy coding */ + opus_int ec_prevSignalType; + opus_int16 ec_prevLagIndex; + + silk_resampler_state_struct resampler_state; + + /* DTX */ + opus_int useDTX; /* Flag to enable DTX */ + opus_int inDTX; /* Flag to signal DTX period */ + opus_int noSpeechCounter; /* Counts concecutive nonactive frames, used by DTX */ + + /* Inband Low Bitrate Redundancy (LBRR) data */ + opus_int useInBandFEC; /* Saves the API setting for query */ + opus_int LBRR_enabled; /* Depends on useInBandFRC, bitrate and packet loss rate */ + opus_int LBRR_GainIncreases; /* Gains increment for coding LBRR frames */ + SideInfoIndices indices_LBRR[ MAX_FRAMES_PER_PACKET ]; + opus_int8 pulses_LBRR[ MAX_FRAMES_PER_PACKET ][ MAX_FRAME_LENGTH ]; +} silk_encoder_state; + + +/* Struct for Packet Loss Concealment */ +typedef struct { + opus_int32 pitchL_Q8; /* Pitch lag to use for voiced concealment */ + opus_int16 LTPCoef_Q14[ LTP_ORDER ]; /* LTP coeficients to use for voiced concealment */ + opus_int16 prevLPC_Q12[ MAX_LPC_ORDER ]; + opus_int last_frame_lost; /* Was previous frame lost */ + opus_int32 rand_seed; /* Seed for unvoiced signal generation */ + opus_int16 randScale_Q14; /* Scaling of unvoiced random signal */ + opus_int32 conc_energy; + opus_int conc_energy_shift; + opus_int16 prevLTP_scale_Q14; + opus_int32 prevGain_Q16[ 2 ]; + opus_int fs_kHz; + opus_int nb_subfr; + opus_int subfr_length; +} silk_PLC_struct; + +/* Struct for CNG */ +typedef struct { + opus_int32 CNG_exc_buf_Q14[ MAX_FRAME_LENGTH ]; + opus_int16 CNG_smth_NLSF_Q15[ MAX_LPC_ORDER ]; + opus_int32 CNG_synth_state[ MAX_LPC_ORDER ]; + opus_int32 CNG_smth_Gain_Q16; + opus_int32 rand_seed; + opus_int fs_kHz; +} silk_CNG_struct; + +/********************************/ +/* Decoder state */ +/********************************/ +typedef struct { + opus_int32 prev_gain_Q16; + opus_int32 exc_Q14[ MAX_FRAME_LENGTH ]; + opus_int32 sLPC_Q14_buf[ MAX_LPC_ORDER ]; + opus_int16 outBuf[ MAX_FRAME_LENGTH + 2 * MAX_SUB_FRAME_LENGTH ]; /* Buffer for output signal */ + opus_int lagPrev; /* Previous Lag */ + opus_int8 LastGainIndex; /* Previous gain index */ + opus_int fs_kHz; /* Sampling frequency in kHz */ + opus_int32 fs_API_hz; /* API sample frequency (Hz) */ + opus_int nb_subfr; /* Number of 5 ms subframes in a frame */ + opus_int frame_length; /* Frame length (samples) */ + opus_int subfr_length; /* Subframe length (samples) */ + opus_int ltp_mem_length; /* Length of LTP memory */ + opus_int LPC_order; /* LPC order */ + opus_int16 prevNLSF_Q15[ MAX_LPC_ORDER ]; /* Used to interpolate LSFs */ + opus_int first_frame_after_reset; /* Flag for deactivating NLSF interpolation */ + const opus_uint8 *pitch_lag_low_bits_iCDF; /* Pointer to iCDF table for low bits of pitch lag index */ + const opus_uint8 *pitch_contour_iCDF; /* Pointer to iCDF table for pitch contour index */ + + /* For buffering payload in case of more frames per packet */ + opus_int nFramesDecoded; + opus_int nFramesPerPacket; + + /* Specifically for entropy coding */ + opus_int ec_prevSignalType; + opus_int16 ec_prevLagIndex; + + opus_int VAD_flags[ MAX_FRAMES_PER_PACKET ]; + opus_int LBRR_flag; + opus_int LBRR_flags[ MAX_FRAMES_PER_PACKET ]; + + silk_resampler_state_struct resampler_state; + + const silk_NLSF_CB_struct *psNLSF_CB; /* Pointer to NLSF codebook */ + + /* Quantization indices */ + SideInfoIndices indices; + + /* CNG state */ + silk_CNG_struct sCNG; + + /* Stuff used for PLC */ + opus_int lossCnt; + opus_int prevSignalType; + + silk_PLC_struct sPLC; + +} silk_decoder_state; + +/************************/ +/* Decoder control */ +/************************/ +typedef struct { + /* Prediction and coding parameters */ + opus_int pitchL[ MAX_NB_SUBFR ]; + opus_int32 Gains_Q16[ MAX_NB_SUBFR ]; + /* Holds interpolated and final coefficients, 4-byte aligned */ + silk_DWORD_ALIGN opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ]; + opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ]; + opus_int LTP_scale_Q14; +} silk_decoder_control; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/code/opus-1.0.2/silk/sum_sqr_shift.c b/code/opus-1.0.2/silk/sum_sqr_shift.c new file mode 100644 index 00000000..2eaf77b6 --- /dev/null +++ b/code/opus-1.0.2/silk/sum_sqr_shift.c @@ -0,0 +1,85 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "SigProc_FIX.h" + +/* Compute number of bits to right shift the sum of squares of a vector */ +/* of int16s to make it fit in an int32 */ +void silk_sum_sqr_shift( + opus_int32 *energy, /* O Energy of x, after shifting to the right */ + opus_int *shift, /* O Number of bits right shift applied to energy */ + const opus_int16 *x, /* I Input vector */ + opus_int len /* I Length of input vector */ +) +{ + opus_int i, shft; + opus_int32 nrg_tmp, nrg; + + nrg = 0; + shft = 0; + len--; + for( i = 0; i < len; i += 2 ) { + nrg = silk_SMLABB_ovflw( nrg, x[ i ], x[ i ] ); + nrg = silk_SMLABB_ovflw( nrg, x[ i + 1 ], x[ i + 1 ] ); + if( nrg < 0 ) { + /* Scale down */ + nrg = (opus_int32)silk_RSHIFT_uint( (opus_uint32)nrg, 2 ); + shft = 2; + break; + } + } + for( ; i < len; i += 2 ) { + nrg_tmp = silk_SMULBB( x[ i ], x[ i ] ); + nrg_tmp = silk_SMLABB_ovflw( nrg_tmp, x[ i + 1 ], x[ i + 1 ] ); + nrg = (opus_int32)silk_ADD_RSHIFT_uint( nrg, (opus_uint32)nrg_tmp, shft ); + if( nrg < 0 ) { + /* Scale down */ + nrg = (opus_int32)silk_RSHIFT_uint( (opus_uint32)nrg, 2 ); + shft += 2; + } + } + if( i == len ) { + /* One sample left to process */ + nrg_tmp = silk_SMULBB( x[ i ], x[ i ] ); + nrg = (opus_int32)silk_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 = silk_RSHIFT_uint( (opus_uint32)nrg, 2 ); + shft += 2; + } + + /* Output arguments */ + *shift = shft; + *energy = nrg; +} + diff --git a/code/opus-1.0.2/silk/table_LSF_cos.c b/code/opus-1.0.2/silk/table_LSF_cos.c new file mode 100644 index 00000000..710537fb --- /dev/null +++ b/code/opus-1.0.2/silk/table_LSF_cos.c @@ -0,0 +1,70 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tables.h" + +/* Cosine approximation table for LSF conversion */ +/* Q12 values (even) */ +const opus_int16 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/code/opus-1.0.2/silk/tables.h b/code/opus-1.0.2/silk/tables.h new file mode 100644 index 00000000..072b7929 --- /dev/null +++ b/code/opus-1.0.2/silk/tables.h @@ -0,0 +1,120 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (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 SILK_TABLES_H +#define SILK_TABLES_H + +#include "define.h" +#include "structs.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Entropy coding tables (with size in bytes indicated) */ +extern const opus_uint8 silk_gain_iCDF[ 3 ][ N_LEVELS_QGAIN / 8 ]; /* 24 */ +extern const opus_uint8 silk_delta_gain_iCDF[ MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 1 ]; /* 41 */ + +extern const opus_uint8 silk_pitch_lag_iCDF[ 2 * ( PITCH_EST_MAX_LAG_MS - PITCH_EST_MIN_LAG_MS ) ];/* 32 */ +extern const opus_uint8 silk_pitch_delta_iCDF[ 21 ]; /* 21 */ +extern const opus_uint8 silk_pitch_contour_iCDF[ 34 ]; /* 34 */ +extern const opus_uint8 silk_pitch_contour_NB_iCDF[ 11 ]; /* 11 */ +extern const opus_uint8 silk_pitch_contour_10_ms_iCDF[ 12 ]; /* 12 */ +extern const opus_uint8 silk_pitch_contour_10_ms_NB_iCDF[ 3 ]; /* 3 */ + +extern const opus_uint8 silk_pulses_per_block_iCDF[ N_RATE_LEVELS ][ MAX_PULSES + 2 ]; /* 180 */ +extern const opus_uint8 silk_pulses_per_block_BITS_Q5[ N_RATE_LEVELS - 1 ][ MAX_PULSES + 2 ]; /* 162 */ + +extern const opus_uint8 silk_rate_levels_iCDF[ 2 ][ N_RATE_LEVELS - 1 ]; /* 18 */ +extern const opus_uint8 silk_rate_levels_BITS_Q5[ 2 ][ N_RATE_LEVELS - 1 ]; /* 18 */ + +extern const opus_uint8 silk_max_pulses_table[ 4 ]; /* 4 */ + +extern const opus_uint8 silk_shell_code_table0[ 152 ]; /* 152 */ +extern const opus_uint8 silk_shell_code_table1[ 152 ]; /* 152 */ +extern const opus_uint8 silk_shell_code_table2[ 152 ]; /* 152 */ +extern const opus_uint8 silk_shell_code_table3[ 152 ]; /* 152 */ +extern const opus_uint8 silk_shell_code_table_offsets[ MAX_PULSES + 1 ]; /* 17 */ + +extern const opus_uint8 silk_lsb_iCDF[ 2 ]; /* 2 */ + +extern const opus_uint8 silk_sign_iCDF[ 42 ]; /* 42 */ + +extern const opus_uint8 silk_uniform3_iCDF[ 3 ]; /* 3 */ +extern const opus_uint8 silk_uniform4_iCDF[ 4 ]; /* 4 */ +extern const opus_uint8 silk_uniform5_iCDF[ 5 ]; /* 5 */ +extern const opus_uint8 silk_uniform6_iCDF[ 6 ]; /* 6 */ +extern const opus_uint8 silk_uniform8_iCDF[ 8 ]; /* 8 */ + +extern const opus_uint8 silk_NLSF_EXT_iCDF[ 7 ]; /* 7 */ + +extern const opus_uint8 silk_LTP_per_index_iCDF[ 3 ]; /* 3 */ +extern const opus_uint8 * const silk_LTP_gain_iCDF_ptrs[ NB_LTP_CBKS ]; /* 3 */ +extern const opus_uint8 * const silk_LTP_gain_BITS_Q5_ptrs[ NB_LTP_CBKS ]; /* 3 */ +extern const opus_int16 silk_LTP_gain_middle_avg_RD_Q14; +extern const opus_int8 * const silk_LTP_vq_ptrs_Q7[ NB_LTP_CBKS ]; /* 168 */ +extern const opus_int8 silk_LTP_vq_sizes[ NB_LTP_CBKS ]; /* 3 */ + +extern const opus_uint8 silk_LTPscale_iCDF[ 3 ]; /* 4 */ +extern const opus_int16 silk_LTPScales_table_Q14[ 3 ]; /* 6 */ + +extern const opus_uint8 silk_type_offset_VAD_iCDF[ 4 ]; /* 4 */ +extern const opus_uint8 silk_type_offset_no_VAD_iCDF[ 2 ]; /* 2 */ + +extern const opus_int16 silk_stereo_pred_quant_Q13[ STEREO_QUANT_TAB_SIZE ]; /* 32 */ +extern const opus_uint8 silk_stereo_pred_joint_iCDF[ 25 ]; /* 25 */ +extern const opus_uint8 silk_stereo_only_code_mid_iCDF[ 2 ]; /* 2 */ + +extern const opus_uint8 * const silk_LBRR_flags_iCDF_ptr[ 2 ]; /* 10 */ + +extern const opus_uint8 silk_NLSF_interpolation_factor_iCDF[ 5 ]; /* 5 */ + +extern const silk_NLSF_CB_struct silk_NLSF_CB_WB; /* 1040 */ +extern const silk_NLSF_CB_struct silk_NLSF_CB_NB_MB; /* 728 */ + +/* Piece-wise linear mapping from bitrate in kbps to coding quality in dB SNR */ +extern const opus_int32 silk_TargetRate_table_NB[ TARGET_RATE_TAB_SZ ]; /* 32 */ +extern const opus_int32 silk_TargetRate_table_MB[ TARGET_RATE_TAB_SZ ]; /* 32 */ +extern const opus_int32 silk_TargetRate_table_WB[ TARGET_RATE_TAB_SZ ]; /* 32 */ +extern const opus_int16 silk_SNR_table_Q1[ TARGET_RATE_TAB_SZ ]; /* 32 */ + +/* Quantization offsets */ +extern const opus_int16 silk_Quantization_Offsets_Q10[ 2 ][ 2 ]; /* 8 */ + +/* Interpolation points for filter coefficients used in the bandwidth transition smoother */ +extern const opus_int32 silk_Transition_LP_B_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NB ]; /* 60 */ +extern const opus_int32 silk_Transition_LP_A_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NA ]; /* 60 */ + +/* Rom table with cosine values */ +extern const opus_int16 silk_LSFCosTab_FIX_Q12[ LSF_COS_TAB_SZ_FIX + 1 ]; /* 258 */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/code/opus-1.0.2/silk/tables_LTP.c b/code/opus-1.0.2/silk/tables_LTP.c new file mode 100644 index 00000000..dd1fb556 --- /dev/null +++ b/code/opus-1.0.2/silk/tables_LTP.c @@ -0,0 +1,272 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tables.h" + +const opus_uint8 silk_LTP_per_index_iCDF[3] = { + 179, 99, 0 +}; + +static const opus_uint8 silk_LTP_gain_iCDF_0[8] = { + 71, 56, 43, 30, 21, 12, 6, 0 +}; + +static const opus_uint8 silk_LTP_gain_iCDF_1[16] = { + 199, 165, 144, 124, 109, 96, 84, 71, + 61, 51, 42, 32, 23, 15, 8, 0 +}; + +static const opus_uint8 silk_LTP_gain_iCDF_2[32] = { + 241, 225, 211, 199, 187, 175, 164, 153, + 142, 132, 123, 114, 105, 96, 88, 80, + 72, 64, 57, 50, 44, 38, 33, 29, + 24, 20, 16, 12, 9, 5, 2, 0 +}; + +const opus_int16 silk_LTP_gain_middle_avg_RD_Q14 = 12304; + +static const opus_uint8 silk_LTP_gain_BITS_Q5_0[8] = { + 15, 131, 138, 138, 155, 155, 173, 173 +}; + +static const opus_uint8 silk_LTP_gain_BITS_Q5_1[16] = { + 69, 93, 115, 118, 131, 138, 141, 138, + 150, 150, 155, 150, 155, 160, 166, 160 +}; + +static const opus_uint8 silk_LTP_gain_BITS_Q5_2[32] = { + 131, 128, 134, 141, 141, 141, 145, 145, + 145, 150, 155, 155, 155, 155, 160, 160, + 160, 160, 166, 166, 173, 173, 182, 192, + 182, 192, 192, 192, 205, 192, 205, 224 +}; + +const opus_uint8 * const silk_LTP_gain_iCDF_ptrs[NB_LTP_CBKS] = { + silk_LTP_gain_iCDF_0, + silk_LTP_gain_iCDF_1, + silk_LTP_gain_iCDF_2 +}; + +const opus_uint8 * const silk_LTP_gain_BITS_Q5_ptrs[NB_LTP_CBKS] = { + silk_LTP_gain_BITS_Q5_0, + silk_LTP_gain_BITS_Q5_1, + silk_LTP_gain_BITS_Q5_2 +}; + +static const opus_int8 silk_LTP_gain_vq_0[8][5] = +{ +{ + 4, 6, 24, 7, 5 +}, +{ + 0, 0, 2, 0, 0 +}, +{ + 12, 28, 41, 13, -4 +}, +{ + -9, 15, 42, 25, 14 +}, +{ + 1, -2, 62, 41, -9 +}, +{ + -10, 37, 65, -4, 3 +}, +{ + -6, 4, 66, 7, -8 +}, +{ + 16, 14, 38, -3, 33 +} +}; + +static const opus_int8 silk_LTP_gain_vq_1[16][5] = +{ +{ + 13, 22, 39, 23, 12 +}, +{ + -1, 36, 64, 27, -6 +}, +{ + -7, 10, 55, 43, 17 +}, +{ + 1, 1, 8, 1, 1 +}, +{ + 6, -11, 74, 53, -9 +}, +{ + -12, 55, 76, -12, 8 +}, +{ + -3, 3, 93, 27, -4 +}, +{ + 26, 39, 59, 3, -8 +}, +{ + 2, 0, 77, 11, 9 +}, +{ + -8, 22, 44, -6, 7 +}, +{ + 40, 9, 26, 3, 9 +}, +{ + -7, 20, 101, -7, 4 +}, +{ + 3, -8, 42, 26, 0 +}, +{ + -15, 33, 68, 2, 23 +}, +{ + -2, 55, 46, -2, 15 +}, +{ + 3, -1, 21, 16, 41 +} +}; + +static const opus_int8 silk_LTP_gain_vq_2[32][5] = +{ +{ + -6, 27, 61, 39, 5 +}, +{ + -11, 42, 88, 4, 1 +}, +{ + -2, 60, 65, 6, -4 +}, +{ + -1, -5, 73, 56, 1 +}, +{ + -9, 19, 94, 29, -9 +}, +{ + 0, 12, 99, 6, 4 +}, +{ + 8, -19, 102, 46, -13 +}, +{ + 3, 2, 13, 3, 2 +}, +{ + 9, -21, 84, 72, -18 +}, +{ + -11, 46, 104, -22, 8 +}, +{ + 18, 38, 48, 23, 0 +}, +{ + -16, 70, 83, -21, 11 +}, +{ + 5, -11, 117, 22, -8 +}, +{ + -6, 23, 117, -12, 3 +}, +{ + 3, -8, 95, 28, 4 +}, +{ + -10, 15, 77, 60, -15 +}, +{ + -1, 4, 124, 2, -4 +}, +{ + 3, 38, 84, 24, -25 +}, +{ + 2, 13, 42, 13, 31 +}, +{ + 21, -4, 56, 46, -1 +}, +{ + -1, 35, 79, -13, 19 +}, +{ + -7, 65, 88, -9, -14 +}, +{ + 20, 4, 81, 49, -29 +}, +{ + 20, 0, 75, 3, -17 +}, +{ + 5, -9, 44, 92, -8 +}, +{ + 1, -3, 22, 69, 31 +}, +{ + -6, 95, 41, -12, 5 +}, +{ + 39, 67, 16, -4, 1 +}, +{ + 0, -6, 120, 55, -36 +}, +{ + -13, 44, 122, 4, -24 +}, +{ + 81, 5, 11, 3, 7 +}, +{ + 2, 0, 9, 10, 88 +} +}; + +const opus_int8 * const silk_LTP_vq_ptrs_Q7[NB_LTP_CBKS] = { + (opus_int8 *)&silk_LTP_gain_vq_0[0][0], + (opus_int8 *)&silk_LTP_gain_vq_1[0][0], + (opus_int8 *)&silk_LTP_gain_vq_2[0][0] +}; + +const opus_int8 silk_LTP_vq_sizes[NB_LTP_CBKS] = { + 8, 16, 32 +}; diff --git a/code/opus-1.0.2/silk/tables_NLSF_CB_NB_MB.c b/code/opus-1.0.2/silk/tables_NLSF_CB_NB_MB.c new file mode 100644 index 00000000..75480526 --- /dev/null +++ b/code/opus-1.0.2/silk/tables_NLSF_CB_NB_MB.c @@ -0,0 +1,159 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tables.h" + +static const opus_uint8 silk_NLSF_CB1_NB_MB_Q8[ 320 ] = { + 12, 35, 60, 83, 108, 132, 157, 180, + 206, 228, 15, 32, 55, 77, 101, 125, + 151, 175, 201, 225, 19, 42, 66, 89, + 114, 137, 162, 184, 209, 230, 12, 25, + 50, 72, 97, 120, 147, 172, 200, 223, + 26, 44, 69, 90, 114, 135, 159, 180, + 205, 225, 13, 22, 53, 80, 106, 130, + 156, 180, 205, 228, 15, 25, 44, 64, + 90, 115, 142, 168, 196, 222, 19, 24, + 62, 82, 100, 120, 145, 168, 190, 214, + 22, 31, 50, 79, 103, 120, 151, 170, + 203, 227, 21, 29, 45, 65, 106, 124, + 150, 171, 196, 224, 30, 49, 75, 97, + 121, 142, 165, 186, 209, 229, 19, 25, + 52, 70, 93, 116, 143, 166, 192, 219, + 26, 34, 62, 75, 97, 118, 145, 167, + 194, 217, 25, 33, 56, 70, 91, 113, + 143, 165, 196, 223, 21, 34, 51, 72, + 97, 117, 145, 171, 196, 222, 20, 29, + 50, 67, 90, 117, 144, 168, 197, 221, + 22, 31, 48, 66, 95, 117, 146, 168, + 196, 222, 24, 33, 51, 77, 116, 134, + 158, 180, 200, 224, 21, 28, 70, 87, + 106, 124, 149, 170, 194, 217, 26, 33, + 53, 64, 83, 117, 152, 173, 204, 225, + 27, 34, 65, 95, 108, 129, 155, 174, + 210, 225, 20, 26, 72, 99, 113, 131, + 154, 176, 200, 219, 34, 43, 61, 78, + 93, 114, 155, 177, 205, 229, 23, 29, + 54, 97, 124, 138, 163, 179, 209, 229, + 30, 38, 56, 89, 118, 129, 158, 178, + 200, 231, 21, 29, 49, 63, 85, 111, + 142, 163, 193, 222, 27, 48, 77, 103, + 133, 158, 179, 196, 215, 232, 29, 47, + 74, 99, 124, 151, 176, 198, 220, 237, + 33, 42, 61, 76, 93, 121, 155, 174, + 207, 225, 29, 53, 87, 112, 136, 154, + 170, 188, 208, 227, 24, 30, 52, 84, + 131, 150, 166, 186, 203, 229, 37, 48, + 64, 84, 104, 118, 156, 177, 201, 230 +}; + +static const opus_uint8 silk_NLSF_CB1_iCDF_NB_MB[ 64 ] = { + 212, 178, 148, 129, 108, 96, 85, 82, + 79, 77, 61, 59, 57, 56, 51, 49, + 48, 45, 42, 41, 40, 38, 36, 34, + 31, 30, 21, 12, 10, 3, 1, 0, + 255, 245, 244, 236, 233, 225, 217, 203, + 190, 176, 175, 161, 149, 136, 125, 114, + 102, 91, 81, 71, 60, 52, 43, 35, + 28, 20, 19, 18, 12, 11, 5, 0 +}; + +static const opus_uint8 silk_NLSF_CB2_SELECT_NB_MB[ 160 ] = { + 16, 0, 0, 0, 0, 99, 66, 36, + 36, 34, 36, 34, 34, 34, 34, 83, + 69, 36, 52, 34, 116, 102, 70, 68, + 68, 176, 102, 68, 68, 34, 65, 85, + 68, 84, 36, 116, 141, 152, 139, 170, + 132, 187, 184, 216, 137, 132, 249, 168, + 185, 139, 104, 102, 100, 68, 68, 178, + 218, 185, 185, 170, 244, 216, 187, 187, + 170, 244, 187, 187, 219, 138, 103, 155, + 184, 185, 137, 116, 183, 155, 152, 136, + 132, 217, 184, 184, 170, 164, 217, 171, + 155, 139, 244, 169, 184, 185, 170, 164, + 216, 223, 218, 138, 214, 143, 188, 218, + 168, 244, 141, 136, 155, 170, 168, 138, + 220, 219, 139, 164, 219, 202, 216, 137, + 168, 186, 246, 185, 139, 116, 185, 219, + 185, 138, 100, 100, 134, 100, 102, 34, + 68, 68, 100, 68, 168, 203, 221, 218, + 168, 167, 154, 136, 104, 70, 164, 246, + 171, 137, 139, 137, 155, 218, 219, 139 +}; + +static const opus_uint8 silk_NLSF_CB2_iCDF_NB_MB[ 72 ] = { + 255, 254, 253, 238, 14, 3, 2, 1, + 0, 255, 254, 252, 218, 35, 3, 2, + 1, 0, 255, 254, 250, 208, 59, 4, + 2, 1, 0, 255, 254, 246, 194, 71, + 10, 2, 1, 0, 255, 252, 236, 183, + 82, 8, 2, 1, 0, 255, 252, 235, + 180, 90, 17, 2, 1, 0, 255, 248, + 224, 171, 97, 30, 4, 1, 0, 255, + 254, 236, 173, 95, 37, 7, 1, 0 +}; + +static const opus_uint8 silk_NLSF_CB2_BITS_NB_MB_Q5[ 72 ] = { + 255, 255, 255, 131, 6, 145, 255, 255, + 255, 255, 255, 236, 93, 15, 96, 255, + 255, 255, 255, 255, 194, 83, 25, 71, + 221, 255, 255, 255, 255, 162, 73, 34, + 66, 162, 255, 255, 255, 210, 126, 73, + 43, 57, 173, 255, 255, 255, 201, 125, + 71, 48, 58, 130, 255, 255, 255, 166, + 110, 73, 57, 62, 104, 210, 255, 255, + 251, 123, 65, 55, 68, 100, 171, 255 +}; + +static const opus_uint8 silk_NLSF_PRED_NB_MB_Q8[ 18 ] = { + 179, 138, 140, 148, 151, 149, 153, 151, + 163, 116, 67, 82, 59, 92, 72, 100, + 89, 92 +}; + +static const opus_int16 silk_NLSF_DELTA_MIN_NB_MB_Q15[ 11 ] = { + 250, 3, 6, 3, 3, 3, 4, 3, + 3, 3, 461 +}; + +const silk_NLSF_CB_struct silk_NLSF_CB_NB_MB = +{ + 32, + 10, + SILK_FIX_CONST( 0.18, 16 ), + SILK_FIX_CONST( 1.0 / 0.18, 6 ), + silk_NLSF_CB1_NB_MB_Q8, + silk_NLSF_CB1_iCDF_NB_MB, + silk_NLSF_PRED_NB_MB_Q8, + silk_NLSF_CB2_SELECT_NB_MB, + silk_NLSF_CB2_iCDF_NB_MB, + silk_NLSF_CB2_BITS_NB_MB_Q5, + silk_NLSF_DELTA_MIN_NB_MB_Q15, +}; diff --git a/code/opus-1.0.2/silk/tables_NLSF_CB_WB.c b/code/opus-1.0.2/silk/tables_NLSF_CB_WB.c new file mode 100644 index 00000000..3d6052e4 --- /dev/null +++ b/code/opus-1.0.2/silk/tables_NLSF_CB_WB.c @@ -0,0 +1,198 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tables.h" + +static const opus_uint8 silk_NLSF_CB1_WB_Q8[ 512 ] = { + 7, 23, 38, 54, 69, 85, 100, 116, + 131, 147, 162, 178, 193, 208, 223, 239, + 13, 25, 41, 55, 69, 83, 98, 112, + 127, 142, 157, 171, 187, 203, 220, 236, + 15, 21, 34, 51, 61, 78, 92, 106, + 126, 136, 152, 167, 185, 205, 225, 240, + 10, 21, 36, 50, 63, 79, 95, 110, + 126, 141, 157, 173, 189, 205, 221, 237, + 17, 20, 37, 51, 59, 78, 89, 107, + 123, 134, 150, 164, 184, 205, 224, 240, + 10, 15, 32, 51, 67, 81, 96, 112, + 129, 142, 158, 173, 189, 204, 220, 236, + 8, 21, 37, 51, 65, 79, 98, 113, + 126, 138, 155, 168, 179, 192, 209, 218, + 12, 15, 34, 55, 63, 78, 87, 108, + 118, 131, 148, 167, 185, 203, 219, 236, + 16, 19, 32, 36, 56, 79, 91, 108, + 118, 136, 154, 171, 186, 204, 220, 237, + 11, 28, 43, 58, 74, 89, 105, 120, + 135, 150, 165, 180, 196, 211, 226, 241, + 6, 16, 33, 46, 60, 75, 92, 107, + 123, 137, 156, 169, 185, 199, 214, 225, + 11, 19, 30, 44, 57, 74, 89, 105, + 121, 135, 152, 169, 186, 202, 218, 234, + 12, 19, 29, 46, 57, 71, 88, 100, + 120, 132, 148, 165, 182, 199, 216, 233, + 17, 23, 35, 46, 56, 77, 92, 106, + 123, 134, 152, 167, 185, 204, 222, 237, + 14, 17, 45, 53, 63, 75, 89, 107, + 115, 132, 151, 171, 188, 206, 221, 240, + 9, 16, 29, 40, 56, 71, 88, 103, + 119, 137, 154, 171, 189, 205, 222, 237, + 16, 19, 36, 48, 57, 76, 87, 105, + 118, 132, 150, 167, 185, 202, 218, 236, + 12, 17, 29, 54, 71, 81, 94, 104, + 126, 136, 149, 164, 182, 201, 221, 237, + 15, 28, 47, 62, 79, 97, 115, 129, + 142, 155, 168, 180, 194, 208, 223, 238, + 8, 14, 30, 45, 62, 78, 94, 111, + 127, 143, 159, 175, 192, 207, 223, 239, + 17, 30, 49, 62, 79, 92, 107, 119, + 132, 145, 160, 174, 190, 204, 220, 235, + 14, 19, 36, 45, 61, 76, 91, 108, + 121, 138, 154, 172, 189, 205, 222, 238, + 12, 18, 31, 45, 60, 76, 91, 107, + 123, 138, 154, 171, 187, 204, 221, 236, + 13, 17, 31, 43, 53, 70, 83, 103, + 114, 131, 149, 167, 185, 203, 220, 237, + 17, 22, 35, 42, 58, 78, 93, 110, + 125, 139, 155, 170, 188, 206, 224, 240, + 8, 15, 34, 50, 67, 83, 99, 115, + 131, 146, 162, 178, 193, 209, 224, 239, + 13, 16, 41, 66, 73, 86, 95, 111, + 128, 137, 150, 163, 183, 206, 225, 241, + 17, 25, 37, 52, 63, 75, 92, 102, + 119, 132, 144, 160, 175, 191, 212, 231, + 19, 31, 49, 65, 83, 100, 117, 133, + 147, 161, 174, 187, 200, 213, 227, 242, + 18, 31, 52, 68, 88, 103, 117, 126, + 138, 149, 163, 177, 192, 207, 223, 239, + 16, 29, 47, 61, 76, 90, 106, 119, + 133, 147, 161, 176, 193, 209, 224, 240, + 15, 21, 35, 50, 61, 73, 86, 97, + 110, 119, 129, 141, 175, 198, 218, 237 +}; + +static const opus_uint8 silk_NLSF_CB1_iCDF_WB[ 64 ] = { + 225, 204, 201, 184, 183, 175, 158, 154, + 153, 135, 119, 115, 113, 110, 109, 99, + 98, 95, 79, 68, 52, 50, 48, 45, + 43, 32, 31, 27, 18, 10, 3, 0, + 255, 251, 235, 230, 212, 201, 196, 182, + 167, 166, 163, 151, 138, 124, 110, 104, + 90, 78, 76, 70, 69, 57, 45, 34, + 24, 21, 11, 6, 5, 4, 3, 0 +}; + +static const opus_uint8 silk_NLSF_CB2_SELECT_WB[ 256 ] = { + 0, 0, 0, 0, 0, 0, 0, 1, + 100, 102, 102, 68, 68, 36, 34, 96, + 164, 107, 158, 185, 180, 185, 139, 102, + 64, 66, 36, 34, 34, 0, 1, 32, + 208, 139, 141, 191, 152, 185, 155, 104, + 96, 171, 104, 166, 102, 102, 102, 132, + 1, 0, 0, 0, 0, 16, 16, 0, + 80, 109, 78, 107, 185, 139, 103, 101, + 208, 212, 141, 139, 173, 153, 123, 103, + 36, 0, 0, 0, 0, 0, 0, 1, + 48, 0, 0, 0, 0, 0, 0, 32, + 68, 135, 123, 119, 119, 103, 69, 98, + 68, 103, 120, 118, 118, 102, 71, 98, + 134, 136, 157, 184, 182, 153, 139, 134, + 208, 168, 248, 75, 189, 143, 121, 107, + 32, 49, 34, 34, 34, 0, 17, 2, + 210, 235, 139, 123, 185, 137, 105, 134, + 98, 135, 104, 182, 100, 183, 171, 134, + 100, 70, 68, 70, 66, 66, 34, 131, + 64, 166, 102, 68, 36, 2, 1, 0, + 134, 166, 102, 68, 34, 34, 66, 132, + 212, 246, 158, 139, 107, 107, 87, 102, + 100, 219, 125, 122, 137, 118, 103, 132, + 114, 135, 137, 105, 171, 106, 50, 34, + 164, 214, 141, 143, 185, 151, 121, 103, + 192, 34, 0, 0, 0, 0, 0, 1, + 208, 109, 74, 187, 134, 249, 159, 137, + 102, 110, 154, 118, 87, 101, 119, 101, + 0, 2, 0, 36, 36, 66, 68, 35, + 96, 164, 102, 100, 36, 0, 2, 33, + 167, 138, 174, 102, 100, 84, 2, 2, + 100, 107, 120, 119, 36, 197, 24, 0 +}; + +static const opus_uint8 silk_NLSF_CB2_iCDF_WB[ 72 ] = { + 255, 254, 253, 244, 12, 3, 2, 1, + 0, 255, 254, 252, 224, 38, 3, 2, + 1, 0, 255, 254, 251, 209, 57, 4, + 2, 1, 0, 255, 254, 244, 195, 69, + 4, 2, 1, 0, 255, 251, 232, 184, + 84, 7, 2, 1, 0, 255, 254, 240, + 186, 86, 14, 2, 1, 0, 255, 254, + 239, 178, 91, 30, 5, 1, 0, 255, + 248, 227, 177, 100, 19, 2, 1, 0 +}; + +static const opus_uint8 silk_NLSF_CB2_BITS_WB_Q5[ 72 ] = { + 255, 255, 255, 156, 4, 154, 255, 255, + 255, 255, 255, 227, 102, 15, 92, 255, + 255, 255, 255, 255, 213, 83, 24, 72, + 236, 255, 255, 255, 255, 150, 76, 33, + 63, 214, 255, 255, 255, 190, 121, 77, + 43, 55, 185, 255, 255, 255, 245, 137, + 71, 43, 59, 139, 255, 255, 255, 255, + 131, 66, 50, 66, 107, 194, 255, 255, + 166, 116, 76, 55, 53, 125, 255, 255 +}; + +static const opus_uint8 silk_NLSF_PRED_WB_Q8[ 30 ] = { + 175, 148, 160, 176, 178, 173, 174, 164, + 177, 174, 196, 182, 198, 192, 182, 68, + 62, 66, 60, 72, 117, 85, 90, 118, + 136, 151, 142, 160, 142, 155 +}; + +static const opus_int16 silk_NLSF_DELTA_MIN_WB_Q15[ 17 ] = { + 100, 3, 40, 3, 3, 3, 5, 14, + 14, 10, 11, 3, 8, 9, 7, 3, + 347 +}; + +const silk_NLSF_CB_struct silk_NLSF_CB_WB = +{ + 32, + 16, + SILK_FIX_CONST( 0.15, 16 ), + SILK_FIX_CONST( 1.0 / 0.15, 6 ), + silk_NLSF_CB1_WB_Q8, + silk_NLSF_CB1_iCDF_WB, + silk_NLSF_PRED_WB_Q8, + silk_NLSF_CB2_SELECT_WB, + silk_NLSF_CB2_iCDF_WB, + silk_NLSF_CB2_BITS_WB_Q5, + silk_NLSF_DELTA_MIN_WB_Q15, +}; + diff --git a/code/opus-1.0.2/silk/tables_gain.c b/code/opus-1.0.2/silk/tables_gain.c new file mode 100644 index 00000000..fccef821 --- /dev/null +++ b/code/opus-1.0.2/silk/tables_gain.c @@ -0,0 +1,63 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tables.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +const opus_uint8 silk_gain_iCDF[ 3 ][ N_LEVELS_QGAIN / 8 ] = +{ +{ + 224, 112, 44, 15, 3, 2, 1, 0 +}, +{ + 254, 237, 192, 132, 70, 23, 4, 0 +}, +{ + 255, 252, 226, 155, 61, 11, 2, 0 +} +}; + +const opus_uint8 silk_delta_gain_iCDF[ MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 1 ] = { + 250, 245, 234, 203, 71, 50, 42, 38, + 35, 33, 31, 29, 28, 27, 26, 25, + 24, 23, 22, 21, 20, 19, 18, 17, + 16, 15, 14, 13, 12, 11, 10, 9, + 8, 7, 6, 5, 4, 3, 2, 1, + 0 +}; + +#ifdef __cplusplus +} +#endif diff --git a/code/opus-1.0.2/silk/tables_other.c b/code/opus-1.0.2/silk/tables_other.c new file mode 100644 index 00000000..3dc68d47 --- /dev/null +++ b/code/opus-1.0.2/silk/tables_other.c @@ -0,0 +1,138 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "structs.h" +#include "define.h" +#include "tables.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Piece-wise linear mapping from bitrate in kbps to coding quality in dB SNR */ +const opus_int32 silk_TargetRate_table_NB[ TARGET_RATE_TAB_SZ ] = { + 0, 8000, 9400, 11500, 13500, 17500, 25000, MAX_TARGET_RATE_BPS +}; +const opus_int32 silk_TargetRate_table_MB[ TARGET_RATE_TAB_SZ ] = { + 0, 9000, 12000, 14500, 18500, 24500, 35500, MAX_TARGET_RATE_BPS +}; +const opus_int32 silk_TargetRate_table_WB[ TARGET_RATE_TAB_SZ ] = { + 0, 10500, 14000, 17000, 21500, 28500, 42000, MAX_TARGET_RATE_BPS +}; +const opus_int16 silk_SNR_table_Q1[ TARGET_RATE_TAB_SZ ] = { + 18, 29, 38, 40, 46, 52, 62, 84 +}; + +/* Tables for stereo predictor coding */ +const opus_int16 silk_stereo_pred_quant_Q13[ STEREO_QUANT_TAB_SIZE ] = { + -13732, -10050, -8266, -7526, -6500, -5000, -2950, -820, + 820, 2950, 5000, 6500, 7526, 8266, 10050, 13732 +}; +const opus_uint8 silk_stereo_pred_joint_iCDF[ 25 ] = { + 249, 247, 246, 245, 244, + 234, 210, 202, 201, 200, + 197, 174, 82, 59, 56, + 55, 54, 46, 22, 12, + 11, 10, 9, 7, 0 +}; +const opus_uint8 silk_stereo_only_code_mid_iCDF[ 2 ] = { 64, 0 }; + +/* Tables for LBRR flags */ +static const opus_uint8 silk_LBRR_flags_2_iCDF[ 3 ] = { 203, 150, 0 }; +static const opus_uint8 silk_LBRR_flags_3_iCDF[ 7 ] = { 215, 195, 166, 125, 110, 82, 0 }; +const opus_uint8 * const silk_LBRR_flags_iCDF_ptr[ 2 ] = { + silk_LBRR_flags_2_iCDF, + silk_LBRR_flags_3_iCDF +}; + +/* Table for LSB coding */ +const opus_uint8 silk_lsb_iCDF[ 2 ] = { 120, 0 }; + +/* Tables for LTPScale */ +const opus_uint8 silk_LTPscale_iCDF[ 3 ] = { 128, 64, 0 }; + +/* Tables for signal type and offset coding */ +const opus_uint8 silk_type_offset_VAD_iCDF[ 4 ] = { + 232, 158, 10, 0 +}; +const opus_uint8 silk_type_offset_no_VAD_iCDF[ 2 ] = { + 230, 0 +}; + +/* Tables for NLSF interpolation factor */ +const opus_uint8 silk_NLSF_interpolation_factor_iCDF[ 5 ] = { 243, 221, 192, 181, 0 }; + +/* Quantization offsets */ +const opus_int16 silk_Quantization_Offsets_Q10[ 2 ][ 2 ] = { + { OFFSET_UVL_Q10, OFFSET_UVH_Q10 }, { OFFSET_VL_Q10, OFFSET_VH_Q10 } +}; + +/* Table for LTPScale */ +const opus_int16 silk_LTPScales_table_Q14[ 3 ] = { 15565, 12288, 8192 }; + +/* Uniform entropy tables */ +const opus_uint8 silk_uniform3_iCDF[ 3 ] = { 171, 85, 0 }; +const opus_uint8 silk_uniform4_iCDF[ 4 ] = { 192, 128, 64, 0 }; +const opus_uint8 silk_uniform5_iCDF[ 5 ] = { 205, 154, 102, 51, 0 }; +const opus_uint8 silk_uniform6_iCDF[ 6 ] = { 213, 171, 128, 85, 43, 0 }; +const opus_uint8 silk_uniform8_iCDF[ 8 ] = { 224, 192, 160, 128, 96, 64, 32, 0 }; + +const opus_uint8 silk_NLSF_EXT_iCDF[ 7 ] = { 100, 40, 16, 7, 3, 1, 0 }; + +/* 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 opus_int32 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 opus_int32 silk_Transition_LP_A_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NA ] = +{ +{ 506393414, 239854379 }, +{ 411067935, 169683996 }, +{ 306733530, 116694253 }, +{ 185807084, 77959395 }, +{ 35497197, 57401098 } +}; + +#ifdef __cplusplus +} +#endif + diff --git a/code/opus-1.0.2/silk/tables_pitch_lag.c b/code/opus-1.0.2/silk/tables_pitch_lag.c new file mode 100644 index 00000000..819b0ab3 --- /dev/null +++ b/code/opus-1.0.2/silk/tables_pitch_lag.c @@ -0,0 +1,69 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tables.h" + +const opus_uint8 silk_pitch_lag_iCDF[ 2 * ( PITCH_EST_MAX_LAG_MS - PITCH_EST_MIN_LAG_MS ) ] = { + 253, 250, 244, 233, 212, 182, 150, 131, + 120, 110, 98, 85, 72, 60, 49, 40, + 32, 25, 19, 15, 13, 11, 9, 8, + 7, 6, 5, 4, 3, 2, 1, 0 +}; + +const opus_uint8 silk_pitch_delta_iCDF[21] = { + 210, 208, 206, 203, 199, 193, 183, 168, + 142, 104, 74, 52, 37, 27, 20, 14, + 10, 6, 4, 2, 0 +}; + +const opus_uint8 silk_pitch_contour_iCDF[34] = { + 223, 201, 183, 167, 152, 138, 124, 111, + 98, 88, 79, 70, 62, 56, 50, 44, + 39, 35, 31, 27, 24, 21, 18, 16, + 14, 12, 10, 8, 6, 4, 3, 2, + 1, 0 +}; + +const opus_uint8 silk_pitch_contour_NB_iCDF[11] = { + 188, 176, 155, 138, 119, 97, 67, 43, + 26, 10, 0 +}; + +const opus_uint8 silk_pitch_contour_10_ms_iCDF[12] = { + 165, 119, 80, 61, 47, 35, 27, 20, + 14, 9, 4, 0 +}; + +const opus_uint8 silk_pitch_contour_10_ms_NB_iCDF[3] = { + 113, 63, 0 +}; + + diff --git a/code/opus-1.0.2/silk/tables_pulses_per_block.c b/code/opus-1.0.2/silk/tables_pulses_per_block.c new file mode 100644 index 00000000..521e6ff6 --- /dev/null +++ b/code/opus-1.0.2/silk/tables_pulses_per_block.c @@ -0,0 +1,264 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tables.h" + +const opus_uint8 silk_max_pulses_table[ 4 ] = { + 8, 10, 12, 16 +}; + +const opus_uint8 silk_pulses_per_block_iCDF[ 10 ][ 18 ] = { +{ + 125, 51, 26, 18, 15, 12, 11, 10, + 9, 8, 7, 6, 5, 4, 3, 2, + 1, 0 +}, +{ + 198, 105, 45, 22, 15, 12, 11, 10, + 9, 8, 7, 6, 5, 4, 3, 2, + 1, 0 +}, +{ + 213, 162, 116, 83, 59, 43, 32, 24, + 18, 15, 12, 9, 7, 6, 5, 3, + 2, 0 +}, +{ + 239, 187, 116, 59, 28, 16, 11, 10, + 9, 8, 7, 6, 5, 4, 3, 2, + 1, 0 +}, +{ + 250, 229, 188, 135, 86, 51, 30, 19, + 13, 10, 8, 6, 5, 4, 3, 2, + 1, 0 +}, +{ + 249, 235, 213, 185, 156, 128, 103, 83, + 66, 53, 42, 33, 26, 21, 17, 13, + 10, 0 +}, +{ + 254, 249, 235, 206, 164, 118, 77, 46, + 27, 16, 10, 7, 5, 4, 3, 2, + 1, 0 +}, +{ + 255, 253, 249, 239, 220, 191, 156, 119, + 85, 57, 37, 23, 15, 10, 6, 4, + 2, 0 +}, +{ + 255, 253, 251, 246, 237, 223, 203, 179, + 152, 124, 98, 75, 55, 40, 29, 21, + 15, 0 +}, +{ + 255, 254, 253, 247, 220, 162, 106, 67, + 42, 28, 18, 12, 9, 6, 4, 3, + 2, 0 +} +}; + +const opus_uint8 silk_pulses_per_block_BITS_Q5[ 9 ][ 18 ] = { +{ + 31, 57, 107, 160, 205, 205, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255 +}, +{ + 69, 47, 67, 111, 166, 205, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255 +}, +{ + 82, 74, 79, 95, 109, 128, 145, 160, + 173, 205, 205, 205, 224, 255, 255, 224, + 255, 224 +}, +{ + 125, 74, 59, 69, 97, 141, 182, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255 +}, +{ + 173, 115, 85, 73, 76, 92, 115, 145, + 173, 205, 224, 224, 255, 255, 255, 255, + 255, 255 +}, +{ + 166, 134, 113, 102, 101, 102, 107, 118, + 125, 138, 145, 155, 166, 182, 192, 192, + 205, 150 +}, +{ + 224, 182, 134, 101, 83, 79, 85, 97, + 120, 145, 173, 205, 224, 255, 255, 255, + 255, 255 +}, +{ + 255, 224, 192, 150, 120, 101, 92, 89, + 93, 102, 118, 134, 160, 182, 192, 224, + 224, 224 +}, +{ + 255, 224, 224, 182, 155, 134, 118, 109, + 104, 102, 106, 111, 118, 131, 145, 160, + 173, 131 +} +}; + +const opus_uint8 silk_rate_levels_iCDF[ 2 ][ 9 ] = +{ +{ + 241, 190, 178, 132, 87, 74, 41, 14, + 0 +}, +{ + 223, 193, 157, 140, 106, 57, 39, 18, + 0 +} +}; + +const opus_uint8 silk_rate_levels_BITS_Q5[ 2 ][ 9 ] = +{ +{ + 131, 74, 141, 79, 80, 138, 95, 104, + 134 +}, +{ + 95, 99, 91, 125, 93, 76, 123, 115, + 123 +} +}; + +const opus_uint8 silk_shell_code_table0[ 152 ] = { + 128, 0, 214, 42, 0, 235, 128, 21, + 0, 244, 184, 72, 11, 0, 248, 214, + 128, 42, 7, 0, 248, 225, 170, 80, + 25, 5, 0, 251, 236, 198, 126, 54, + 18, 3, 0, 250, 238, 211, 159, 82, + 35, 15, 5, 0, 250, 231, 203, 168, + 128, 88, 53, 25, 6, 0, 252, 238, + 216, 185, 148, 108, 71, 40, 18, 4, + 0, 253, 243, 225, 199, 166, 128, 90, + 57, 31, 13, 3, 0, 254, 246, 233, + 212, 183, 147, 109, 73, 44, 23, 10, + 2, 0, 255, 250, 240, 223, 198, 166, + 128, 90, 58, 33, 16, 6, 1, 0, + 255, 251, 244, 231, 210, 181, 146, 110, + 75, 46, 25, 12, 5, 1, 0, 255, + 253, 248, 238, 221, 196, 164, 128, 92, + 60, 35, 18, 8, 3, 1, 0, 255, + 253, 249, 242, 229, 208, 180, 146, 110, + 76, 48, 27, 14, 7, 3, 1, 0 +}; + +const opus_uint8 silk_shell_code_table1[ 152 ] = { + 129, 0, 207, 50, 0, 236, 129, 20, + 0, 245, 185, 72, 10, 0, 249, 213, + 129, 42, 6, 0, 250, 226, 169, 87, + 27, 4, 0, 251, 233, 194, 130, 62, + 20, 4, 0, 250, 236, 207, 160, 99, + 47, 17, 3, 0, 255, 240, 217, 182, + 131, 81, 41, 11, 1, 0, 255, 254, + 233, 201, 159, 107, 61, 20, 2, 1, + 0, 255, 249, 233, 206, 170, 128, 86, + 50, 23, 7, 1, 0, 255, 250, 238, + 217, 186, 148, 108, 70, 39, 18, 6, + 1, 0, 255, 252, 243, 226, 200, 166, + 128, 90, 56, 30, 13, 4, 1, 0, + 255, 252, 245, 231, 209, 180, 146, 110, + 76, 47, 25, 11, 4, 1, 0, 255, + 253, 248, 237, 219, 194, 163, 128, 93, + 62, 37, 19, 8, 3, 1, 0, 255, + 254, 250, 241, 226, 205, 177, 145, 111, + 79, 51, 30, 15, 6, 2, 1, 0 +}; + +const opus_uint8 silk_shell_code_table2[ 152 ] = { + 129, 0, 203, 54, 0, 234, 129, 23, + 0, 245, 184, 73, 10, 0, 250, 215, + 129, 41, 5, 0, 252, 232, 173, 86, + 24, 3, 0, 253, 240, 200, 129, 56, + 15, 2, 0, 253, 244, 217, 164, 94, + 38, 10, 1, 0, 253, 245, 226, 189, + 132, 71, 27, 7, 1, 0, 253, 246, + 231, 203, 159, 105, 56, 23, 6, 1, + 0, 255, 248, 235, 213, 179, 133, 85, + 47, 19, 5, 1, 0, 255, 254, 243, + 221, 194, 159, 117, 70, 37, 12, 2, + 1, 0, 255, 254, 248, 234, 208, 171, + 128, 85, 48, 22, 8, 2, 1, 0, + 255, 254, 250, 240, 220, 189, 149, 107, + 67, 36, 16, 6, 2, 1, 0, 255, + 254, 251, 243, 227, 201, 166, 128, 90, + 55, 29, 13, 5, 2, 1, 0, 255, + 254, 252, 246, 234, 213, 183, 147, 109, + 73, 43, 22, 10, 4, 2, 1, 0 +}; + +const opus_uint8 silk_shell_code_table3[ 152 ] = { + 130, 0, 200, 58, 0, 231, 130, 26, + 0, 244, 184, 76, 12, 0, 249, 214, + 130, 43, 6, 0, 252, 232, 173, 87, + 24, 3, 0, 253, 241, 203, 131, 56, + 14, 2, 0, 254, 246, 221, 167, 94, + 35, 8, 1, 0, 254, 249, 232, 193, + 130, 65, 23, 5, 1, 0, 255, 251, + 239, 211, 162, 99, 45, 15, 4, 1, + 0, 255, 251, 243, 223, 186, 131, 74, + 33, 11, 3, 1, 0, 255, 252, 245, + 230, 202, 158, 105, 57, 24, 8, 2, + 1, 0, 255, 253, 247, 235, 214, 179, + 132, 84, 44, 19, 7, 2, 1, 0, + 255, 254, 250, 240, 223, 196, 159, 112, + 69, 36, 15, 6, 2, 1, 0, 255, + 254, 253, 245, 231, 209, 176, 136, 93, + 55, 27, 11, 3, 2, 1, 0, 255, + 254, 253, 252, 239, 221, 194, 158, 117, + 76, 42, 18, 4, 3, 2, 1, 0 +}; + +const opus_uint8 silk_shell_code_table_offsets[ 17 ] = { + 0, 0, 2, 5, 9, 14, 20, 27, + 35, 44, 54, 65, 77, 90, 104, 119, + 135 +}; + +const opus_uint8 silk_sign_iCDF[ 42 ] = { + 254, 49, 67, 77, 82, 93, 99, + 198, 11, 18, 24, 31, 36, 45, + 255, 46, 66, 78, 87, 94, 104, + 208, 14, 21, 32, 42, 51, 66, + 255, 94, 104, 109, 112, 115, 118, + 248, 53, 69, 80, 88, 95, 102 +}; diff --git a/code/opus-1.0.2/silk/tuning_parameters.h b/code/opus-1.0.2/silk/tuning_parameters.h new file mode 100644 index 00000000..a26de4d2 --- /dev/null +++ b/code/opus-1.0.2/silk/tuning_parameters.h @@ -0,0 +1,168 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (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 SILK_TUNING_PARAMETERS_H +#define SILK_TUNING_PARAMETERS_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Decay time for bitreservoir */ +#define BITRESERVOIR_DECAY_TIME_MS 500 + +/*******************/ +/* 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_BANDWIDTH_EXPANSION 0.99f + +/*********************/ +/* Linear prediction */ +/*********************/ + +/* LPC analysis defines: regularization and bandwidth expansion */ +#define FIND_LPC_COND_FAC 1e-5f + +/* LTP analysis defines */ +#define FIND_LTP_COND_FAC 1e-5f +#define LTP_DAMPING 0.05f +#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 + +/***********************/ +/* 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 +#define VARIABLE_HP_MAX_DELTA_FREQ 0.4f + +/* Min and max cut-off frequency values (-3 dB points) */ +#define VARIABLE_HP_MIN_CUTOFF_HZ 60 +#define VARIABLE_HP_MAX_CUTOFF_HZ 100 + +/***********/ +/* Various */ +/***********/ + +/* VAD threshold */ +#define SPEECH_ACTIVITY_DTX_THRES 0.05f + +/* Speech Activity LBRR enable threshold */ +#define LBRR_SPEECH_ACTIVITY_THRES 0.3f + +/*************************/ +/* Perceptual parameters */ +/*************************/ + +/* reduction in coding SNR during low speech activity */ +#define BG_SNR_DECR_dB 2.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 5e-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 + +/* 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.25f + +/* 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 4.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 + +/* 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.2f +#define LAMBDA_DELAYED_DECISIONS -0.05f +#define LAMBDA_INPUT_QUALITY -0.1f +#define LAMBDA_CODING_QUALITY -0.2f +#define LAMBDA_QUANT_OFFSET 0.8f + +/* Compensation in bitrate calculations for 10 ms modes */ +#define REDUCE_BITRATE_10_MS_BPS 2200 + +/* Maximum time before allowing a bandwidth transition */ +#define MAX_BANDWIDTH_SWITCH_DELAY_MS 5000 + +#ifdef __cplusplus +} +#endif + +#endif /* SILK_TUNING_PARAMETERS_H */ diff --git a/code/opus-1.0.2/silk/typedef.h b/code/opus-1.0.2/silk/typedef.h new file mode 100644 index 00000000..da981237 --- /dev/null +++ b/code/opus-1.0.2/silk/typedef.h @@ -0,0 +1,77 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (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 SILK_TYPEDEF_H +#define SILK_TYPEDEF_H + +#include "opus_types.h" + +#ifndef FIXED_POINT +# include +# define silk_float float +# define silk_float_MAX FLT_MAX +#endif + +#define silk_int64_MAX ((opus_int64)0x7FFFFFFFFFFFFFFFLL) /* 2^63 - 1 */ +#define silk_int64_MIN ((opus_int64)0x8000000000000000LL) /* -2^63 */ +#define silk_int32_MAX 0x7FFFFFFF /* 2^31 - 1 = 2147483647 */ +#define silk_int32_MIN ((opus_int32)0x80000000) /* -2^31 = -2147483648 */ +#define silk_int16_MAX 0x7FFF /* 2^15 - 1 = 32767 */ +#define silk_int16_MIN ((opus_int16)0x8000) /* -2^15 = -32768 */ +#define silk_int8_MAX 0x7F /* 2^7 - 1 = 127 */ +#define silk_int8_MIN ((opus_int8)0x80) /* -2^7 = -128 */ +#define silk_uint8_MAX 0xFF /* 2^8 - 1 = 255 */ + +#define silk_TRUE 1 +#define silk_FALSE 0 + +/* assertions */ +#if (defined _WIN32 && !defined _WINCE && !defined(__GNUC__) && !defined(NO_ASSERTS)) +# ifndef silk_assert +# include /* ASSERTE() */ +# define silk_assert(COND) _ASSERTE(COND) +# endif +#else +# ifdef ENABLE_ASSERTIONS +# include +# include +#define silk_fatal(str) _silk_fatal(str, __FILE__, __LINE__); +#ifdef __GNUC__ +__attribute__((noreturn)) +#endif +static inline void _silk_fatal(const char *str, const char *file, int line) +{ + fprintf (stderr, "Fatal (internal) error in %s, line %d: %s\n", file, line, str); + abort(); +} +# define silk_assert(COND) {if (!(COND)) {silk_fatal("assertion failed: " #COND);}} +# else +# define silk_assert(COND) +# endif +#endif + +#endif /* SILK_TYPEDEF_H */ diff --git a/code/opus-1.0.2/src/opus.c b/code/opus-1.0.2/src/opus.c new file mode 100644 index 00000000..d6ae7bab --- /dev/null +++ b/code/opus-1.0.2/src/opus.c @@ -0,0 +1,47 @@ +/* Copyright (c) 2011 Xiph.Org Foundation, Skype Limited + Written by Jean-Marc Valin and Koen Vos */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "opus.h" +#include "opus_private.h" + +int encode_size(int size, unsigned char *data) +{ + if (size < 252) + { + data[0] = size; + return 1; + } else { + data[0] = 252+(size&0x3); + data[1] = (size-(int)data[0])>>2; + return 2; + } +} + diff --git a/code/opus-1.0.2/src/opus_decoder.c b/code/opus-1.0.2/src/opus_decoder.c new file mode 100644 index 00000000..ad5f7470 --- /dev/null +++ b/code/opus-1.0.2/src/opus_decoder.c @@ -0,0 +1,1051 @@ +/* Copyright (c) 2010 Xiph.Org Foundation, Skype Limited + Written by Jean-Marc Valin and Koen Vos */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef OPUS_BUILD +#error "OPUS_BUILD _MUST_ be defined to build Opus. This probably means you need other defines as well, as in a config.h. See the included build files for details." +#endif + +#include +#include "celt.h" +#include "opus.h" +#include "entdec.h" +#include "modes.h" +#include "API.h" +#include "stack_alloc.h" +#include "float_cast.h" +#include "opus_private.h" +#include "os_support.h" +#include "structs.h" +#include "define.h" +#include "mathops.h" + +struct OpusDecoder { + int celt_dec_offset; + int silk_dec_offset; + int channels; + opus_int32 Fs; /** Sampling rate (at the API level) */ + silk_DecControlStruct DecControl; + int decode_gain; + + /* Everything beyond this point gets cleared on a reset */ +#define OPUS_DECODER_RESET_START stream_channels + int stream_channels; + + int bandwidth; + int mode; + int prev_mode; + int frame_size; + int prev_redundancy; + int last_packet_duration; + + opus_uint32 rangeFinal; +}; + +#ifdef FIXED_POINT +static inline opus_int16 SAT16(opus_int32 x) { + return x > 32767 ? 32767 : x < -32768 ? -32768 : (opus_int16)x; +} +#endif + + +int opus_decoder_get_size(int channels) +{ + int silkDecSizeBytes, celtDecSizeBytes; + int ret; + if (channels<1 || channels > 2) + return 0; + ret = silk_Get_Decoder_Size( &silkDecSizeBytes ); + if(ret) + return 0; + silkDecSizeBytes = align(silkDecSizeBytes); + celtDecSizeBytes = celt_decoder_get_size(channels); + return align(sizeof(OpusDecoder))+silkDecSizeBytes+celtDecSizeBytes; +} + +int opus_decoder_init(OpusDecoder *st, opus_int32 Fs, int channels) +{ + void *silk_dec; + CELTDecoder *celt_dec; + int ret, silkDecSizeBytes; + + if ((Fs!=48000&&Fs!=24000&&Fs!=16000&&Fs!=12000&&Fs!=8000) + || (channels!=1&&channels!=2)) + return OPUS_BAD_ARG; + + OPUS_CLEAR((char*)st, opus_decoder_get_size(channels)); + /* Initialize SILK encoder */ + ret = silk_Get_Decoder_Size(&silkDecSizeBytes); + if (ret) + return OPUS_INTERNAL_ERROR; + + silkDecSizeBytes = align(silkDecSizeBytes); + st->silk_dec_offset = align(sizeof(OpusDecoder)); + st->celt_dec_offset = st->silk_dec_offset+silkDecSizeBytes; + silk_dec = (char*)st+st->silk_dec_offset; + celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset); + st->stream_channels = st->channels = channels; + + st->Fs = Fs; + st->DecControl.API_sampleRate = st->Fs; + st->DecControl.nChannelsAPI = st->channels; + + /* Reset decoder */ + ret = silk_InitDecoder( silk_dec ); + if(ret)return OPUS_INTERNAL_ERROR; + + /* Initialize CELT decoder */ + ret = celt_decoder_init(celt_dec, Fs, channels); + if(ret!=OPUS_OK)return OPUS_INTERNAL_ERROR; + + celt_decoder_ctl(celt_dec, CELT_SET_SIGNALLING(0)); + + st->prev_mode = 0; + st->frame_size = Fs/400; + return OPUS_OK; +} + +OpusDecoder *opus_decoder_create(opus_int32 Fs, int channels, int *error) +{ + int ret; + OpusDecoder *st; + if ((Fs!=48000&&Fs!=24000&&Fs!=16000&&Fs!=12000&&Fs!=8000) + || (channels!=1&&channels!=2)) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + st = (OpusDecoder *)opus_alloc(opus_decoder_get_size(channels)); + if (st == NULL) + { + if (error) + *error = OPUS_ALLOC_FAIL; + return NULL; + } + ret = opus_decoder_init(st, Fs, channels); + if (error) + *error = ret; + if (ret != OPUS_OK) + { + opus_free(st); + st = NULL; + } + return st; +} + +static void smooth_fade(const opus_val16 *in1, const opus_val16 *in2, + opus_val16 *out, int overlap, int channels, + const opus_val16 *window, opus_int32 Fs) +{ + int i, c; + int inc = 48000/Fs; + for (c=0;csilk_dec_offset; + celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset); + F20 = st->Fs/50; + F10 = F20>>1; + F5 = F10>>1; + F2_5 = F5>>1; + if (frame_size < F2_5) + { + RESTORE_STACK; + return OPUS_BUFFER_TOO_SMALL; + } + /* Limit frame_size to avoid excessive stack allocations. */ + frame_size = IMIN(frame_size, st->Fs/25*3); + /* Payloads of 1 (2 including ToC) or 0 trigger the PLC/DTX */ + if (len<=1) + { + data = NULL; + /* In that case, don't conceal more than what the ToC says */ + frame_size = IMIN(frame_size, st->frame_size); + } + if (data != NULL) + { + audiosize = st->frame_size; + mode = st->mode; + ec_dec_init(&dec,(unsigned char*)data,len); + } else { + audiosize = frame_size; + + if (st->prev_mode == 0) + { + /* If we haven't got any packet yet, all we can do is return zeros */ + for (i=0;ichannels;i++) + pcm[i] = 0; + RESTORE_STACK; + return audiosize; + } else { + mode = st->prev_mode; + } + } + + /* For CELT/hybrid PLC of more than 20 ms, opus_decode_native() will do + multiple calls */ + if (data==NULL && mode != MODE_SILK_ONLY) + frame_size = IMIN(frame_size, F20); + ALLOC(pcm_transition, F5*st->channels, opus_val16); + + if (data!=NULL && st->prev_mode > 0 && ( + (mode == MODE_CELT_ONLY && st->prev_mode != MODE_CELT_ONLY && !st->prev_redundancy) + || (mode != MODE_CELT_ONLY && st->prev_mode == MODE_CELT_ONLY) ) + ) + { + transition = 1; + if (mode == MODE_CELT_ONLY) + opus_decode_frame(st, NULL, 0, pcm_transition, IMIN(F5, audiosize), 0); + } + if (audiosize > frame_size) + { + /*fprintf(stderr, "PCM buffer too small: %d vs %d (mode = %d)\n", audiosize, frame_size, mode);*/ + RESTORE_STACK; + return OPUS_BAD_ARG; + } else { + frame_size = audiosize; + } + + ALLOC(pcm_silk, IMAX(F10, frame_size)*st->channels, opus_int16); + ALLOC(redundant_audio, F5*st->channels, opus_val16); + + /* SILK processing */ + if (mode != MODE_CELT_ONLY) + { + int lost_flag, decoded_samples; + opus_int16 *pcm_ptr = pcm_silk; + + if (st->prev_mode==MODE_CELT_ONLY) + silk_InitDecoder( silk_dec ); + + /* The SILK PLC cannot produce frames of less than 10 ms */ + st->DecControl.payloadSize_ms = IMAX(10, 1000 * audiosize / st->Fs); + + if (data != NULL) + { + st->DecControl.nChannelsInternal = st->stream_channels; + if( mode == MODE_SILK_ONLY ) { + if( st->bandwidth == OPUS_BANDWIDTH_NARROWBAND ) { + st->DecControl.internalSampleRate = 8000; + } else if( st->bandwidth == OPUS_BANDWIDTH_MEDIUMBAND ) { + st->DecControl.internalSampleRate = 12000; + } else if( st->bandwidth == OPUS_BANDWIDTH_WIDEBAND ) { + st->DecControl.internalSampleRate = 16000; + } else { + st->DecControl.internalSampleRate = 16000; + silk_assert( 0 ); + } + } else { + /* Hybrid mode */ + st->DecControl.internalSampleRate = 16000; + } + } + + lost_flag = data == NULL ? 1 : 2 * decode_fec; + decoded_samples = 0; + do { + /* Call SILK decoder */ + int first_frame = decoded_samples == 0; + silk_ret = silk_Decode( silk_dec, &st->DecControl, + lost_flag, first_frame, &dec, pcm_ptr, &silk_frame_size ); + if( silk_ret ) { + if (lost_flag) { + /* PLC failure should not be fatal */ + silk_frame_size = frame_size; + for (i=0;ichannels;i++) + pcm_ptr[i] = 0; + } else { + RESTORE_STACK; + return OPUS_INVALID_PACKET; + } + } + pcm_ptr += silk_frame_size * st->channels; + decoded_samples += silk_frame_size; + } while( decoded_samples < frame_size ); + } + + start_band = 0; + if (!decode_fec && mode != MODE_CELT_ONLY && data != NULL + && ec_tell(&dec)+17+20*(st->mode == MODE_HYBRID) <= 8*len) + { + /* Check if we have a redundant 0-8 kHz band */ + if (mode == MODE_HYBRID) + redundancy = ec_dec_bit_logp(&dec, 12); + else + redundancy = 1; + if (redundancy) + { + celt_to_silk = ec_dec_bit_logp(&dec, 1); + /* redundancy_bytes will be at least two, in the non-hybrid + case due to the ec_tell() check above */ + redundancy_bytes = mode==MODE_HYBRID ? + (opus_int32)ec_dec_uint(&dec, 256)+2 : + len-((ec_tell(&dec)+7)>>3); + len -= redundancy_bytes; + /* This is a sanity check. It should never happen for a valid + packet, so the exact behaviour is not normative. */ + if (len*8 < ec_tell(&dec)) + { + len = 0; + redundancy_bytes = 0; + redundancy = 0; + } + /* Shrink decoder because of raw bits */ + dec.storage -= redundancy_bytes; + } + } + if (mode != MODE_CELT_ONLY) + start_band = 17; + + { + int endband=21; + + switch(st->bandwidth) + { + case OPUS_BANDWIDTH_NARROWBAND: + endband = 13; + break; + case OPUS_BANDWIDTH_MEDIUMBAND: + case OPUS_BANDWIDTH_WIDEBAND: + endband = 17; + break; + case OPUS_BANDWIDTH_SUPERWIDEBAND: + endband = 19; + break; + case OPUS_BANDWIDTH_FULLBAND: + endband = 21; + break; + } + celt_decoder_ctl(celt_dec, CELT_SET_END_BAND(endband)); + celt_decoder_ctl(celt_dec, CELT_SET_CHANNELS(st->stream_channels)); + } + + if (redundancy) + transition = 0; + + if (transition && mode != MODE_CELT_ONLY) + opus_decode_frame(st, NULL, 0, pcm_transition, IMIN(F5, audiosize), 0); + + /* 5 ms redundant frame for CELT->SILK*/ + if (redundancy && celt_to_silk) + { + celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0)); + celt_decode_with_ec(celt_dec, data+len, redundancy_bytes, + redundant_audio, F5, NULL); + celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng)); + } + + /* MUST be after PLC */ + celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(start_band)); + + if (mode != MODE_SILK_ONLY) + { + int celt_frame_size = IMIN(F20, frame_size); + /* Make sure to discard any previous CELT state */ + if (mode != st->prev_mode && st->prev_mode > 0 && !st->prev_redundancy) + celt_decoder_ctl(celt_dec, OPUS_RESET_STATE); + /* Decode CELT */ + celt_ret = celt_decode_with_ec(celt_dec, decode_fec ? NULL : data, + len, pcm, celt_frame_size, &dec); + } else { + unsigned char silence[2] = {0xFF, 0xFF}; + for (i=0;ichannels;i++) + pcm[i] = 0; + /* For hybrid -> SILK transitions, we let the CELT MDCT + do a fade-out by decoding a silence frame */ + if (st->prev_mode == MODE_HYBRID && !(redundancy && celt_to_silk && st->prev_redundancy) ) + { + celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0)); + celt_decode_with_ec(celt_dec, silence, 2, pcm, F2_5, NULL); + } + } + + if (mode != MODE_CELT_ONLY) + { +#ifdef FIXED_POINT + for (i=0;ichannels;i++) + pcm[i] = SAT16(pcm[i] + pcm_silk[i]); +#else + for (i=0;ichannels;i++) + pcm[i] = pcm[i] + (opus_val16)((1.f/32768.f)*pcm_silk[i]); +#endif + } + + { + const CELTMode *celt_mode; + celt_decoder_ctl(celt_dec, CELT_GET_MODE(&celt_mode)); + window = celt_mode->window; + } + + /* 5 ms redundant frame for SILK->CELT */ + if (redundancy && !celt_to_silk) + { + celt_decoder_ctl(celt_dec, OPUS_RESET_STATE); + celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0)); + + celt_decode_with_ec(celt_dec, data+len, redundancy_bytes, redundant_audio, F5, NULL); + celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng)); + smooth_fade(pcm+st->channels*(frame_size-F2_5), redundant_audio+st->channels*F2_5, + pcm+st->channels*(frame_size-F2_5), F2_5, st->channels, window, st->Fs); + } + if (redundancy && celt_to_silk) + { + for (c=0;cchannels;c++) + { + for (i=0;ichannels*i+c] = redundant_audio[st->channels*i+c]; + } + smooth_fade(redundant_audio+st->channels*F2_5, pcm+st->channels*F2_5, + pcm+st->channels*F2_5, F2_5, st->channels, window, st->Fs); + } + if (transition) + { + if (audiosize >= F5) + { + for (i=0;ichannels*F2_5;i++) + pcm[i] = pcm_transition[i]; + smooth_fade(pcm_transition+st->channels*F2_5, pcm+st->channels*F2_5, + pcm+st->channels*F2_5, F2_5, + st->channels, window, st->Fs); + } else { + /* Not enough time to do a clean transition, but we do it anyway + This will not preserve amplitude perfectly and may introduce + a bit of temporal aliasing, but it shouldn't be too bad and + that's pretty much the best we can do. In any case, generating this + transition it pretty silly in the first place */ + smooth_fade(pcm_transition, pcm, + pcm, F2_5, + st->channels, window, st->Fs); + } + } + + if(st->decode_gain) + { + opus_val32 gain; + gain = celt_exp2(MULT16_16_P15(QCONST16(6.48814081e-4f, 25), st->decode_gain)); + for (i=0;ichannels;i++) + { + opus_val32 x; + x = MULT16_32_P16(pcm[i],gain); + pcm[i] = SATURATE(x, 32767); + } + } + + if (len <= 1) + st->rangeFinal = 0; + else + st->rangeFinal = dec.rng ^ redundant_rng; + + st->prev_mode = mode; + st->prev_redundancy = redundancy && !celt_to_silk; + RESTORE_STACK; + return celt_ret < 0 ? celt_ret : audiosize; + +} + +static int parse_size(const unsigned char *data, opus_int32 len, short *size) +{ + if (len<1) + { + *size = -1; + return -1; + } else if (data[0]<252) + { + *size = data[0]; + return 1; + } else if (len<2) + { + *size = -1; + return -1; + } else { + *size = 4*data[1] + data[0]; + return 2; + } +} + +static int opus_packet_parse_impl(const unsigned char *data, opus_int32 len, + int self_delimited, unsigned char *out_toc, + const unsigned char *frames[48], short size[48], int *payload_offset) +{ + int i, bytes; + int count; + int cbr; + unsigned char ch, toc; + int framesize; + opus_int32 last_size; + const unsigned char *data0 = data; + + if (size==NULL) + return OPUS_BAD_ARG; + + framesize = opus_packet_get_samples_per_frame(data, 48000); + + cbr = 0; + toc = *data++; + len--; + last_size = len; + switch (toc&0x3) + { + /* One frame */ + case 0: + count=1; + break; + /* Two CBR frames */ + case 1: + count=2; + cbr = 1; + if (!self_delimited) + { + if (len&0x1) + return OPUS_INVALID_PACKET; + last_size = len/2; + /* If last_size doesn't fit in size[0], we'll catch it later */ + size[0] = (short)last_size; + } + break; + /* Two VBR frames */ + case 2: + count = 2; + bytes = parse_size(data, len, size); + len -= bytes; + if (size[0]<0 || size[0] > len) + return OPUS_INVALID_PACKET; + data += bytes; + last_size = len-size[0]; + break; + /* Multiple CBR/VBR frames (from 0 to 120 ms) */ + default: /*case 3:*/ + if (len<1) + return OPUS_INVALID_PACKET; + /* Number of frames encoded in bits 0 to 5 */ + ch = *data++; + count = ch&0x3F; + if (count <= 0 || framesize*count > 5760) + return OPUS_INVALID_PACKET; + len--; + /* Padding flag is bit 6 */ + if (ch&0x40) + { + int p; + do { + if (len<=0) + return OPUS_INVALID_PACKET; + p = *data++; + len--; + len -= p==255 ? 254: p; + } while (p==255); + } + if (len<0) + return OPUS_INVALID_PACKET; + /* VBR flag is bit 7 */ + cbr = !(ch&0x80); + if (!cbr) + { + /* VBR case */ + last_size = len; + for (i=0;i len) + return OPUS_INVALID_PACKET; + data += bytes; + last_size -= bytes+size[i]; + } + if (last_size<0) + return OPUS_INVALID_PACKET; + } else if (!self_delimited) + { + /* CBR case */ + last_size = len/count; + if (last_size*count!=len) + return OPUS_INVALID_PACKET; + for (i=0;i len) + return OPUS_INVALID_PACKET; + data += bytes; + /* For CBR packets, apply the size to all the frames. */ + if (cbr) + { + if (size[count-1]*count > len) + return OPUS_INVALID_PACKET; + for (i=0;i last_size) + return OPUS_INVALID_PACKET; + } else + { + /* Because it's not encoded explicitly, it's possible the size of the + last packet (or all the packets, for the CBR case) is larger than + 1275. Reject them here.*/ + if (last_size > 1275) + return OPUS_INVALID_PACKET; + size[count-1] = (short)last_size; + } + + if (frames) + { + for (i=0;i1) + return OPUS_BAD_ARG; + /* For FEC/PLC, frame_size has to be to have a multiple of 2.5 ms */ + if ((decode_fec || len==0 || data==NULL) && frame_size%(st->Fs/400)!=0) + return OPUS_BAD_ARG; + if (len==0 || data==NULL) + { + int pcm_count=0; + do { + int ret; + ret = opus_decode_frame(st, NULL, 0, pcm, frame_size-pcm_count, 0); + if (ret<0) + return ret; + pcm += st->channels*ret; + pcm_count += ret; + } while (pcm_count < frame_size); + st->last_packet_duration = pcm_count; + return pcm_count; + } else if (len<0) + return OPUS_BAD_ARG; + + packet_mode = opus_packet_get_mode(data); + packet_bandwidth = opus_packet_get_bandwidth(data); + packet_frame_size = opus_packet_get_samples_per_frame(data, st->Fs); + packet_stream_channels = opus_packet_get_nb_channels(data); + + count = opus_packet_parse_impl(data, len, self_delimited, &toc, NULL, size, &offset); + + data += offset; + + if (decode_fec) + { + int duration_copy; + int ret; + /* If no FEC can be present, run the PLC (recursive call) */ + if (frame_size <= packet_frame_size || packet_mode == MODE_CELT_ONLY || st->mode == MODE_CELT_ONLY) + return opus_decode_native(st, NULL, 0, pcm, frame_size, 0, 0, NULL); + /* Otherwise, run the PLC on everything except the size for which we might have FEC */ + duration_copy = st->last_packet_duration; + ret = opus_decode_native(st, NULL, 0, pcm, frame_size-packet_frame_size, 0, 0, NULL); + if (ret<0) + { + st->last_packet_duration = duration_copy; + return ret; + } + /* Complete with FEC */ + st->mode = packet_mode; + st->bandwidth = packet_bandwidth; + st->frame_size = packet_frame_size; + st->stream_channels = packet_stream_channels; + ret = opus_decode_frame(st, data, size[0], pcm+st->channels*(frame_size-packet_frame_size), + packet_frame_size, 1); + if (ret<0) + return ret; + st->last_packet_duration = frame_size; + return frame_size; + } + tot_offset = 0; + if (count < 0) + return count; + + tot_offset += offset; + + if (count*packet_frame_size > frame_size) + return OPUS_BUFFER_TOO_SMALL; + + /* Update the state as the last step to avoid updating it on an invalid packet */ + st->mode = packet_mode; + st->bandwidth = packet_bandwidth; + st->frame_size = packet_frame_size; + st->stream_channels = packet_stream_channels; + + nb_samples=0; + for (i=0;ichannels; + nb_samples += ret; + } + if (packet_offset != NULL) + *packet_offset = tot_offset; + st->last_packet_duration = nb_samples; + return nb_samples; +} + +#ifdef FIXED_POINT + +int opus_decode(OpusDecoder *st, const unsigned char *data, + opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec) +{ + return opus_decode_native(st, data, len, pcm, frame_size, decode_fec, 0, NULL); +} + +#ifndef DISABLE_FLOAT_API +int opus_decode_float(OpusDecoder *st, const unsigned char *data, + opus_int32 len, float *pcm, int frame_size, int decode_fec) +{ + VARDECL(opus_int16, out); + int ret, i; + ALLOC_STACK; + + ALLOC(out, frame_size*st->channels, opus_int16); + + ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL); + if (ret > 0) + { + for (i=0;ichannels;i++) + pcm[i] = (1.f/32768.f)*(out[i]); + } + RESTORE_STACK; + return ret; +} +#endif + + +#else +int opus_decode(OpusDecoder *st, const unsigned char *data, + opus_int32 len, opus_int16 *pcm, int frame_size, int decode_fec) +{ + VARDECL(float, out); + int ret, i; + ALLOC_STACK; + + if(frame_size<0) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + + ALLOC(out, frame_size*st->channels, float); + + ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL); + if (ret > 0) + { + for (i=0;ichannels;i++) + pcm[i] = FLOAT2INT16(out[i]); + } + RESTORE_STACK; + return ret; +} + +int opus_decode_float(OpusDecoder *st, const unsigned char *data, + opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec) +{ + return opus_decode_native(st, data, len, pcm, frame_size, decode_fec, 0, NULL); +} + +#endif + +int opus_decoder_ctl(OpusDecoder *st, int request, ...) +{ + int ret = OPUS_OK; + va_list ap; + void *silk_dec; + CELTDecoder *celt_dec; + + silk_dec = (char*)st+st->silk_dec_offset; + celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset); + + + va_start(ap, request); + + switch (request) + { + case OPUS_GET_BANDWIDTH_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + *value = st->bandwidth; + } + break; + case OPUS_GET_FINAL_RANGE_REQUEST: + { + opus_uint32 *value = va_arg(ap, opus_uint32*); + *value = st->rangeFinal; + } + break; + case OPUS_RESET_STATE: + { + OPUS_CLEAR((char*)&st->OPUS_DECODER_RESET_START, + sizeof(OpusDecoder)- + ((char*)&st->OPUS_DECODER_RESET_START - (char*)st)); + + celt_decoder_ctl(celt_dec, OPUS_RESET_STATE); + silk_InitDecoder( silk_dec ); + st->stream_channels = st->channels; + st->frame_size = st->Fs/400; + } + break; + case OPUS_GET_SAMPLE_RATE_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (value==NULL) + { + ret = OPUS_BAD_ARG; + break; + } + *value = st->Fs; + } + break; + case OPUS_GET_PITCH_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (value==NULL) + { + ret = OPUS_BAD_ARG; + break; + } + if (st->prev_mode == MODE_CELT_ONLY) + celt_decoder_ctl(celt_dec, OPUS_GET_PITCH(value)); + else + *value = st->DecControl.prevPitchLag; + } + break; + case OPUS_GET_GAIN_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (value==NULL) + { + ret = OPUS_BAD_ARG; + break; + } + *value = st->decode_gain; + } + break; + case OPUS_SET_GAIN_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<-32768 || value>32767) + { + ret = OPUS_BAD_ARG; + break; + } + st->decode_gain = value; + } + break; + case OPUS_GET_LAST_PACKET_DURATION_REQUEST: + { + opus_uint32 *value = va_arg(ap, opus_uint32*); + *value = st->last_packet_duration; + } + break; + default: + /*fprintf(stderr, "unknown opus_decoder_ctl() request: %d", request);*/ + ret = OPUS_UNIMPLEMENTED; + break; + } + + va_end(ap); + return ret; +} + +void opus_decoder_destroy(OpusDecoder *st) +{ + opus_free(st); +} + + +int opus_packet_get_bandwidth(const unsigned char *data) +{ + int bandwidth; + if (data[0]&0x80) + { + bandwidth = OPUS_BANDWIDTH_MEDIUMBAND + ((data[0]>>5)&0x3); + if (bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) + bandwidth = OPUS_BANDWIDTH_NARROWBAND; + } else if ((data[0]&0x60) == 0x60) + { + bandwidth = (data[0]&0x10) ? OPUS_BANDWIDTH_FULLBAND : + OPUS_BANDWIDTH_SUPERWIDEBAND; + } else { + bandwidth = OPUS_BANDWIDTH_NARROWBAND + ((data[0]>>5)&0x3); + } + return bandwidth; +} + +int opus_packet_get_samples_per_frame(const unsigned char *data, + opus_int32 Fs) +{ + int audiosize; + if (data[0]&0x80) + { + audiosize = ((data[0]>>3)&0x3); + audiosize = (Fs<>3)&0x3); + if (audiosize == 3) + audiosize = Fs*60/1000; + else + audiosize = (Fs< Fs*3) + return OPUS_INVALID_PACKET; + else + return samples; +} + +int opus_decoder_get_nb_samples(const OpusDecoder *dec, + const unsigned char packet[], opus_int32 len) +{ + return opus_packet_get_nb_samples(packet, len, dec->Fs); +} diff --git a/code/opus-1.0.2/src/opus_encoder.c b/code/opus-1.0.2/src/opus_encoder.c new file mode 100644 index 00000000..aae31256 --- /dev/null +++ b/code/opus-1.0.2/src/opus_encoder.c @@ -0,0 +1,1617 @@ +/* Copyright (c) 2010-2011 Xiph.Org Foundation, Skype Limited + Written by Jean-Marc Valin and Koen Vos */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "celt.h" +#include "entenc.h" +#include "modes.h" +#include "API.h" +#include "stack_alloc.h" +#include "float_cast.h" +#include "opus.h" +#include "arch.h" +#include "opus_private.h" +#include "os_support.h" + +#include "tuning_parameters.h" +#ifdef FIXED_POINT +#include "fixed/structs_FIX.h" +#else +#include "float/structs_FLP.h" +#endif + +#define MAX_ENCODER_BUFFER 480 + +struct OpusEncoder { + int celt_enc_offset; + int silk_enc_offset; + silk_EncControlStruct silk_mode; + int application; + int channels; + int delay_compensation; + int force_channels; + int signal_type; + int user_bandwidth; + int max_bandwidth; + int user_forced_mode; + int voice_ratio; + opus_int32 Fs; + int use_vbr; + int vbr_constraint; + opus_int32 bitrate_bps; + opus_int32 user_bitrate_bps; + int encoder_buffer; + +#define OPUS_ENCODER_RESET_START stream_channels + int stream_channels; + opus_int16 hybrid_stereo_width_Q14; + opus_int32 variable_HP_smth2_Q15; + opus_val32 hp_mem[4]; + int mode; + int prev_mode; + int prev_channels; + int prev_framesize; + int bandwidth; + int silk_bw_switch; + /* Sampling rate (at the API level) */ + int first; + opus_val16 delay_buffer[MAX_ENCODER_BUFFER*2]; + + opus_uint32 rangeFinal; +}; + +/* Transition tables for the voice and music. First column is the + middle (memoriless) threshold. The second column is the hysteresis + (difference with the middle) */ +static const opus_int32 mono_voice_bandwidth_thresholds[8] = { + 11000, 1000, /* NB<->MB */ + 14000, 1000, /* MB<->WB */ + 21000, 2000, /* WB<->SWB */ + 29000, 2000, /* SWB<->FB */ +}; +static const opus_int32 mono_music_bandwidth_thresholds[8] = { + 14000, 1000, /* MB not allowed */ + 18000, 2000, /* MB<->WB */ + 24000, 2000, /* WB<->SWB */ + 33000, 2000, /* SWB<->FB */ +}; +static const opus_int32 stereo_voice_bandwidth_thresholds[8] = { + 11000, 1000, /* NB<->MB */ + 14000, 1000, /* MB<->WB */ + 21000, 2000, /* WB<->SWB */ + 32000, 2000, /* SWB<->FB */ +}; +static const opus_int32 stereo_music_bandwidth_thresholds[8] = { + 14000, 1000, /* MB not allowed */ + 18000, 2000, /* MB<->WB */ + 24000, 2000, /* WB<->SWB */ + 48000, 2000, /* SWB<->FB */ +}; +/* Threshold bit-rates for switching between mono and stereo */ +static const opus_int32 stereo_voice_threshold = 26000; +static const opus_int32 stereo_music_threshold = 36000; + +/* Threshold bit-rate for switching between SILK/hybrid and CELT-only */ +static const opus_int32 mode_thresholds[2][2] = { + /* voice */ /* music */ + { 48000, 24000}, /* mono */ + { 48000, 24000}, /* stereo */ +}; + +int opus_encoder_get_size(int channels) +{ + int silkEncSizeBytes, celtEncSizeBytes; + int ret; + if (channels<1 || channels > 2) + return 0; + ret = silk_Get_Encoder_Size( &silkEncSizeBytes ); + if (ret) + return 0; + silkEncSizeBytes = align(silkEncSizeBytes); + celtEncSizeBytes = celt_encoder_get_size(channels); + return align(sizeof(OpusEncoder))+silkEncSizeBytes+celtEncSizeBytes; +} + +int opus_encoder_init(OpusEncoder* st, opus_int32 Fs, int channels, int application) +{ + void *silk_enc; + CELTEncoder *celt_enc; + int err; + int ret, silkEncSizeBytes; + + if((Fs!=48000&&Fs!=24000&&Fs!=16000&&Fs!=12000&&Fs!=8000)||(channels!=1&&channels!=2)|| + (application != OPUS_APPLICATION_VOIP && application != OPUS_APPLICATION_AUDIO + && application != OPUS_APPLICATION_RESTRICTED_LOWDELAY)) + return OPUS_BAD_ARG; + + OPUS_CLEAR((char*)st, opus_encoder_get_size(channels)); + /* Create SILK encoder */ + ret = silk_Get_Encoder_Size( &silkEncSizeBytes ); + if (ret) + return OPUS_BAD_ARG; + silkEncSizeBytes = align(silkEncSizeBytes); + st->silk_enc_offset = align(sizeof(OpusEncoder)); + st->celt_enc_offset = st->silk_enc_offset+silkEncSizeBytes; + silk_enc = (char*)st+st->silk_enc_offset; + celt_enc = (CELTEncoder*)((char*)st+st->celt_enc_offset); + + st->stream_channels = st->channels = channels; + + st->Fs = Fs; + + ret = silk_InitEncoder( silk_enc, &st->silk_mode ); + if(ret)return OPUS_INTERNAL_ERROR; + + /* default SILK parameters */ + st->silk_mode.nChannelsAPI = channels; + st->silk_mode.nChannelsInternal = channels; + st->silk_mode.API_sampleRate = st->Fs; + st->silk_mode.maxInternalSampleRate = 16000; + st->silk_mode.minInternalSampleRate = 8000; + st->silk_mode.desiredInternalSampleRate = 16000; + st->silk_mode.payloadSize_ms = 20; + st->silk_mode.bitRate = 25000; + st->silk_mode.packetLossPercentage = 0; + st->silk_mode.complexity = 10; + st->silk_mode.useInBandFEC = 0; + st->silk_mode.useDTX = 0; + st->silk_mode.useCBR = 0; + + /* Create CELT encoder */ + /* Initialize CELT encoder */ + err = celt_encoder_init(celt_enc, Fs, channels); + if(err!=OPUS_OK)return OPUS_INTERNAL_ERROR; + + celt_encoder_ctl(celt_enc, CELT_SET_SIGNALLING(0)); + celt_encoder_ctl(celt_enc, OPUS_SET_COMPLEXITY(10)); + + st->use_vbr = 1; + /* Makes constrained VBR the default (safer for real-time use) */ + st->vbr_constraint = 1; + st->user_bitrate_bps = OPUS_AUTO; + st->bitrate_bps = 3000+Fs*channels; + st->application = application; + st->signal_type = OPUS_AUTO; + st->user_bandwidth = OPUS_AUTO; + st->max_bandwidth = OPUS_BANDWIDTH_FULLBAND; + st->force_channels = OPUS_AUTO; + st->user_forced_mode = OPUS_AUTO; + st->voice_ratio = -1; + st->encoder_buffer = st->Fs/100; + + /* Delay compensation of 4 ms (2.5 ms for SILK's extra look-ahead + + 1.5 ms for SILK resamplers and stereo prediction) */ + st->delay_compensation = st->Fs/250; + + st->hybrid_stereo_width_Q14 = 1 << 14; + st->variable_HP_smth2_Q15 = silk_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 ); + st->first = 1; + st->mode = MODE_HYBRID; + st->bandwidth = OPUS_BANDWIDTH_FULLBAND; + + return OPUS_OK; +} + +static int pad_frame(unsigned char *data, opus_int32 len, opus_int32 new_len) +{ + if (len == new_len) + return 0; + if (len > new_len) + return 1; + + if ((data[0]&0x3)==0) + { + int i; + int padding, nb_255s; + + padding = new_len - len; + if (padding >= 2) + { + nb_255s = (padding-2)/255; + + for (i=len-1;i>=1;i--) + data[i+nb_255s+2] = data[i]; + data[0] |= 0x3; + data[1] = 0x41; + for (i=0;i=1;i--) + data[i+1] = data[i]; + data[0] |= 0x3; + data[1] = 1; + } + return 0; + } else { + return 1; + } +} + +static unsigned char gen_toc(int mode, int framerate, int bandwidth, int channels) +{ + int period; + unsigned char toc; + period = 0; + while (framerate < 400) + { + framerate <<= 1; + period++; + } + if (mode == MODE_SILK_ONLY) + { + toc = (bandwidth-OPUS_BANDWIDTH_NARROWBAND)<<5; + toc |= (period-2)<<3; + } else if (mode == MODE_CELT_ONLY) + { + int tmp = bandwidth-OPUS_BANDWIDTH_MEDIUMBAND; + if (tmp < 0) + tmp = 0; + toc = 0x80; + toc |= tmp << 5; + toc |= period<<3; + } else /* Hybrid */ + { + toc = 0x60; + toc |= (bandwidth-OPUS_BANDWIDTH_SUPERWIDEBAND)<<4; + toc |= (period-2)<<3; + } + toc |= (channels==2)<<2; + return toc; +} + +#ifndef FIXED_POINT +static void silk_biquad_float( + const opus_val16 *in, /* I: Input signal */ + const opus_int32 *B_Q28, /* I: MA coefficients [3] */ + const opus_int32 *A_Q28, /* I: AR coefficients [2] */ + opus_val32 *S, /* I/O: State vector [2] */ + opus_val16 *out, /* O: Output signal */ + const opus_int32 len, /* I: Signal length (must be even) */ + int stride +) +{ + /* DIRECT FORM II TRANSPOSED (uses 2 element state vector) */ + opus_int k; + opus_val32 vout; + opus_val32 inval; + opus_val32 A[2], B[3]; + + A[0] = (opus_val32)(A_Q28[0] * (1.f/((opus_int32)1<<28))); + A[1] = (opus_val32)(A_Q28[1] * (1.f/((opus_int32)1<<28))); + B[0] = (opus_val32)(B_Q28[0] * (1.f/((opus_int32)1<<28))); + B[1] = (opus_val32)(B_Q28[1] * (1.f/((opus_int32)1<<28))); + B[2] = (opus_val32)(B_Q28[2] * (1.f/((opus_int32)1<<28))); + + /* Negate A_Q28 values and split in two parts */ + + for( k = 0; k < len; k++ ) { + /* S[ 0 ], S[ 1 ]: Q12 */ + inval = in[ k*stride ]; + vout = S[ 0 ] + B[0]*inval; + + S[ 0 ] = S[1] - vout*A[0] + B[1]*inval; + + S[ 1 ] = - vout*A[1] + B[2]*inval; + + /* Scale back to Q0 and saturate */ + out[ k*stride ] = vout; + } +} +#endif + +static void hp_cutoff(const opus_val16 *in, opus_int32 cutoff_Hz, opus_val16 *out, opus_val32 *hp_mem, int len, int channels, opus_int32 Fs) +{ + opus_int32 B_Q28[ 3 ], A_Q28[ 2 ]; + opus_int32 Fc_Q19, r_Q28, r_Q22; + + silk_assert( cutoff_Hz <= silk_int32_MAX / SILK_FIX_CONST( 1.5 * 3.14159 / 1000, 19 ) ); + Fc_Q19 = silk_DIV32_16( silk_SMULBB( SILK_FIX_CONST( 1.5 * 3.14159 / 1000, 19 ), cutoff_Hz ), Fs/1000 ); + silk_assert( Fc_Q19 > 0 && Fc_Q19 < 32768 ); + + r_Q28 = SILK_FIX_CONST( 1.0, 28 ) - silk_MUL( SILK_FIX_CONST( 0.92, 9 ), Fc_Q19 ); + + /* b = r * [ 1; -2; 1 ]; */ + /* a = [ 1; -2 * r * ( 1 - 0.5 * Fc^2 ); r^2 ]; */ + B_Q28[ 0 ] = r_Q28; + B_Q28[ 1 ] = silk_LSHIFT( -r_Q28, 1 ); + B_Q28[ 2 ] = r_Q28; + + /* -r * ( 2 - Fc * Fc ); */ + r_Q22 = silk_RSHIFT( r_Q28, 6 ); + A_Q28[ 0 ] = silk_SMULWW( r_Q22, silk_SMULWW( Fc_Q19, Fc_Q19 ) - SILK_FIX_CONST( 2.0, 22 ) ); + A_Q28[ 1 ] = silk_SMULWW( r_Q22, r_Q22 ); + +#ifdef FIXED_POINT + silk_biquad_alt( in, B_Q28, A_Q28, hp_mem, out, len, channels ); + if( channels == 2 ) { + silk_biquad_alt( in+1, B_Q28, A_Q28, hp_mem+2, out+1, len, channels ); + } +#else + silk_biquad_float( in, B_Q28, A_Q28, hp_mem, out, len, channels ); + if( channels == 2 ) { + silk_biquad_float( in+1, B_Q28, A_Q28, hp_mem+2, out+1, len, channels ); + } +#endif +} + +static void stereo_fade(const opus_val16 *in, opus_val16 *out, opus_val16 g1, opus_val16 g2, + int overlap48, int frame_size, int channels, const opus_val16 *window, opus_int32 Fs) +{ + int i; + int overlap; + int inc; + inc = 48000/Fs; + overlap=overlap48/inc; + g1 = Q15ONE-g1; + g2 = Q15ONE-g2; + for (i=0;iFs/400; + if (st->user_bitrate_bps==OPUS_AUTO) + return 60*st->Fs/frame_size + st->Fs*st->channels; + else if (st->user_bitrate_bps==OPUS_BITRATE_MAX) + return max_data_bytes*8*st->Fs/frame_size; + else + return st->user_bitrate_bps; +} + +#ifdef FIXED_POINT +#define opus_encode_native opus_encode +opus_int32 opus_encode(OpusEncoder *st, const opus_val16 *pcm, int frame_size, + unsigned char *data, opus_int32 out_data_bytes) +#else +#define opus_encode_native opus_encode_float +opus_int32 opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size, + unsigned char *data, opus_int32 out_data_bytes) +#endif +{ + void *silk_enc; + CELTEncoder *celt_enc; + int i; + int ret=0; + opus_int32 nBytes; + ec_enc enc; + int bytes_target; + int prefill=0; + int start_band = 0; + int redundancy = 0; + int redundancy_bytes = 0; /* Number of bytes to use for redundancy frame */ + int celt_to_silk = 0; + VARDECL(opus_val16, pcm_buf); + int nb_compr_bytes; + int to_celt = 0; + opus_uint32 redundant_rng = 0; + int cutoff_Hz, hp_freq_smth1; + int voice_est; /* Probability of voice in Q7 */ + opus_int32 equiv_rate; + int delay_compensation; + int frame_rate; + opus_int32 max_rate; /* Max bitrate we're allowed to use */ + int curr_bandwidth; + opus_int32 max_data_bytes; /* Max number of bytes we're allowed to use */ + VARDECL(opus_val16, tmp_prefill); + + ALLOC_STACK; + + max_data_bytes = IMIN(1276, out_data_bytes); + + st->rangeFinal = 0; + if (400*frame_size != st->Fs && 200*frame_size != st->Fs && 100*frame_size != st->Fs && + 50*frame_size != st->Fs && 25*frame_size != st->Fs && 50*frame_size != 3*st->Fs) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + if (max_data_bytes<=0) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + silk_enc = (char*)st+st->silk_enc_offset; + celt_enc = (CELTEncoder*)((char*)st+st->celt_enc_offset); + + if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY) + delay_compensation = 0; + else + delay_compensation = st->delay_compensation; + + st->bitrate_bps = user_bitrate_to_bitrate(st, frame_size, max_data_bytes); + + frame_rate = st->Fs/frame_size; + if (max_data_bytes<3 || st->bitrate_bps < 3*frame_rate*8 + || (frame_rate<50 && (max_data_bytes*frame_rate<300 || st->bitrate_bps < 2400))) + { + /*If the space is too low to do something useful, emit 'PLC' frames.*/ + int tocmode = st->mode; + int bw = st->bandwidth == 0 ? OPUS_BANDWIDTH_NARROWBAND : st->bandwidth; + if (tocmode==0) + tocmode = MODE_SILK_ONLY; + if (frame_rate>100) + tocmode = MODE_CELT_ONLY; + if (frame_rate < 50) + tocmode = MODE_SILK_ONLY; + if(tocmode==MODE_SILK_ONLY&&bw>OPUS_BANDWIDTH_WIDEBAND) + bw=OPUS_BANDWIDTH_WIDEBAND; + else if (tocmode==MODE_CELT_ONLY&&bw==OPUS_BANDWIDTH_MEDIUMBAND) + bw=OPUS_BANDWIDTH_NARROWBAND; + else if (bw<=OPUS_BANDWIDTH_SUPERWIDEBAND) + bw=OPUS_BANDWIDTH_SUPERWIDEBAND; + data[0] = gen_toc(tocmode, frame_rate, bw, st->stream_channels); + RESTORE_STACK; + return 1; + } + if (!st->use_vbr) + { + int cbrBytes; + cbrBytes = IMIN( (st->bitrate_bps + 4*frame_rate)/(8*frame_rate) , max_data_bytes); + st->bitrate_bps = cbrBytes * (8*frame_rate); + max_data_bytes = cbrBytes; + } + max_rate = frame_rate*max_data_bytes*8; + + /* Equivalent 20-ms rate for mode/channel/bandwidth decisions */ + equiv_rate = st->bitrate_bps - 60*(st->Fs/frame_size - 50); + + if (st->signal_type == OPUS_SIGNAL_VOICE) + voice_est = 127; + else if (st->signal_type == OPUS_SIGNAL_MUSIC) + voice_est = 0; + else if (st->voice_ratio >= 0) + voice_est = st->voice_ratio*327>>8; + else if (st->application == OPUS_APPLICATION_VOIP) + voice_est = 115; + else + voice_est = 48; + + if (st->force_channels!=OPUS_AUTO && st->channels == 2) + { + st->stream_channels = st->force_channels; + } else { +#ifdef FUZZING + /* Random mono/stereo decision */ + if (st->channels == 2 && (rand()&0x1F)==0) + st->stream_channels = 3-st->stream_channels; +#else + /* Rate-dependent mono-stereo decision */ + if (st->channels == 2) + { + opus_int32 stereo_threshold; + stereo_threshold = stereo_music_threshold + ((voice_est*voice_est*(stereo_voice_threshold-stereo_music_threshold))>>14); + if (st->stream_channels == 2) + stereo_threshold -= 4000; + else + stereo_threshold += 4000; + st->stream_channels = (equiv_rate > stereo_threshold) ? 2 : 1; + } else { + st->stream_channels = st->channels; + } +#endif + } + + /* Mode selection depending on application and signal type */ + if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY) + { + st->mode = MODE_CELT_ONLY; + } else if (st->user_forced_mode == OPUS_AUTO) + { +#ifdef FUZZING + /* Random mode switching */ + if ((rand()&0xF)==0) + { + if ((rand()&0x1)==0) + st->mode = MODE_CELT_ONLY; + else + st->mode = MODE_SILK_ONLY; + } else { + if (st->prev_mode==MODE_CELT_ONLY) + st->mode = MODE_CELT_ONLY; + else + st->mode = MODE_SILK_ONLY; + } +#else + int chan; + opus_int32 mode_voice, mode_music; + opus_int32 threshold; + + chan = (st->channels==2) && st->force_channels!=1; + mode_voice = mode_thresholds[chan][0]; + mode_music = mode_thresholds[chan][1]; + threshold = mode_music + ((voice_est*voice_est*(mode_voice-mode_music))>>14); + + /* Hysteresis */ + if (st->prev_mode == MODE_CELT_ONLY) + threshold -= 4000; + else if (st->prev_mode>0) + threshold += 4000; + + st->mode = (equiv_rate >= threshold) ? MODE_CELT_ONLY: MODE_SILK_ONLY; + + /* When FEC is enabled and there's enough packet loss, use SILK */ + if (st->silk_mode.useInBandFEC && st->silk_mode.packetLossPercentage > (128-voice_est)>>4) + st->mode = MODE_SILK_ONLY; + /* When encoding voice and DTX is enabled, set the encoder to SILK mode (at least for now) */ + if (st->silk_mode.useDTX && voice_est > 100) + st->mode = MODE_SILK_ONLY; +#endif + } else { + st->mode = st->user_forced_mode; + } + + /* Override the chosen mode to make sure we meet the requested frame size */ + if (st->mode != MODE_CELT_ONLY && frame_size < st->Fs/100) + st->mode = MODE_CELT_ONLY; + + if (st->stream_channels == 1 && st->prev_channels ==2 && st->silk_mode.toMono==0 + && st->mode != MODE_CELT_ONLY && st->prev_mode != MODE_CELT_ONLY) + { + /* Delay stereo->mono transition by two frames so that SILK can do a smooth downmix */ + st->silk_mode.toMono = 1; + st->stream_channels = 2; + } else { + st->silk_mode.toMono = 0; + } + + if (st->prev_mode > 0 && + ((st->mode != MODE_CELT_ONLY && st->prev_mode == MODE_CELT_ONLY) || + (st->mode == MODE_CELT_ONLY && st->prev_mode != MODE_CELT_ONLY))) + { + redundancy = 1; + celt_to_silk = (st->mode != MODE_CELT_ONLY); + if (!celt_to_silk) + { + /* Switch to SILK/hybrid if frame size is 10 ms or more*/ + if (frame_size >= st->Fs/100) + { + st->mode = st->prev_mode; + to_celt = 1; + } else { + redundancy=0; + } + } + } + /* For the first frame at a new SILK bandwidth */ + if (st->silk_bw_switch) + { + redundancy = 1; + celt_to_silk = 1; + st->silk_bw_switch = 0; + } + + if (redundancy) + { + /* Fair share of the max size allowed */ + redundancy_bytes = IMIN(257, max_data_bytes*(opus_int32)(st->Fs/200)/(frame_size+st->Fs/200)); + /* For VBR, target the actual bitrate (subject to the limit above) */ + if (st->use_vbr) + redundancy_bytes = IMIN(redundancy_bytes, st->bitrate_bps/1600); + } + + if (st->mode != MODE_CELT_ONLY && st->prev_mode == MODE_CELT_ONLY) + { + silk_EncControlStruct dummy; + silk_InitEncoder( silk_enc, &dummy); + prefill=1; + } + + /* Automatic (rate-dependent) bandwidth selection */ + if (st->mode == MODE_CELT_ONLY || st->first || st->silk_mode.allowBandwidthSwitch) + { + const opus_int32 *voice_bandwidth_thresholds, *music_bandwidth_thresholds; + opus_int32 bandwidth_thresholds[8]; + int bandwidth = OPUS_BANDWIDTH_FULLBAND; + opus_int32 equiv_rate2; + + equiv_rate2 = equiv_rate; + if (st->mode != MODE_CELT_ONLY) + { + /* Adjust the threshold +/- 10% depending on complexity */ + equiv_rate2 = equiv_rate2 * (45+st->silk_mode.complexity)/50; + /* CBR is less efficient by ~1 kb/s */ + if (!st->use_vbr) + equiv_rate2 -= 1000; + } + if (st->channels==2 && st->force_channels!=1) + { + voice_bandwidth_thresholds = stereo_voice_bandwidth_thresholds; + music_bandwidth_thresholds = stereo_music_bandwidth_thresholds; + } else { + voice_bandwidth_thresholds = mono_voice_bandwidth_thresholds; + music_bandwidth_thresholds = mono_music_bandwidth_thresholds; + } + /* Interpolate bandwidth thresholds depending on voice estimation */ + for (i=0;i<8;i++) + { + bandwidth_thresholds[i] = music_bandwidth_thresholds[i] + + ((voice_est*voice_est*(voice_bandwidth_thresholds[i]-music_bandwidth_thresholds[i]))>>14); + } + do { + int threshold, hysteresis; + threshold = bandwidth_thresholds[2*(bandwidth-OPUS_BANDWIDTH_MEDIUMBAND)]; + hysteresis = bandwidth_thresholds[2*(bandwidth-OPUS_BANDWIDTH_MEDIUMBAND)+1]; + if (!st->first) + { + if (st->bandwidth >= bandwidth) + threshold -= hysteresis; + else + threshold += hysteresis; + } + if (equiv_rate2 >= threshold) + break; + } while (--bandwidth>OPUS_BANDWIDTH_NARROWBAND); + st->bandwidth = bandwidth; + /* Prevents any transition to SWB/FB until the SILK layer has fully + switched to WB mode and turned the variable LP filter off */ + if (!st->first && st->mode != MODE_CELT_ONLY && !st->silk_mode.inWBmodeWithoutVariableLP && st->bandwidth > OPUS_BANDWIDTH_WIDEBAND) + st->bandwidth = OPUS_BANDWIDTH_WIDEBAND; + } + + if (st->bandwidth>st->max_bandwidth) + st->bandwidth = st->max_bandwidth; + + if (st->user_bandwidth != OPUS_AUTO) + st->bandwidth = st->user_bandwidth; + + /* This prevents us from using hybrid at unsafe CBR/max rates */ + if (st->mode != MODE_CELT_ONLY && max_rate < 15000) + { + st->bandwidth = IMIN(st->bandwidth, OPUS_BANDWIDTH_WIDEBAND); + } + + /* Prevents Opus from wasting bits on frequencies that are above + the Nyquist rate of the input signal */ + if (st->Fs <= 24000 && st->bandwidth > OPUS_BANDWIDTH_SUPERWIDEBAND) + st->bandwidth = OPUS_BANDWIDTH_SUPERWIDEBAND; + if (st->Fs <= 16000 && st->bandwidth > OPUS_BANDWIDTH_WIDEBAND) + st->bandwidth = OPUS_BANDWIDTH_WIDEBAND; + if (st->Fs <= 12000 && st->bandwidth > OPUS_BANDWIDTH_MEDIUMBAND) + st->bandwidth = OPUS_BANDWIDTH_MEDIUMBAND; + if (st->Fs <= 8000 && st->bandwidth > OPUS_BANDWIDTH_NARROWBAND) + st->bandwidth = OPUS_BANDWIDTH_NARROWBAND; + + /* If max_data_bytes represents less than 8 kb/s, switch to CELT-only mode */ + if (max_data_bytes < (frame_rate > 50 ? 12000 : 8000)*frame_size / (st->Fs * 8)) + st->mode = MODE_CELT_ONLY; + + /* CELT mode doesn't support mediumband, use wideband instead */ + if (st->mode == MODE_CELT_ONLY && st->bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) + st->bandwidth = OPUS_BANDWIDTH_WIDEBAND; + + /* Can't support higher than wideband for >20 ms frames */ + if (frame_size > st->Fs/50 && (st->mode == MODE_CELT_ONLY || st->bandwidth > OPUS_BANDWIDTH_WIDEBAND)) + { + VARDECL(unsigned char, tmp_data); + int nb_frames; + int bak_mode, bak_bandwidth, bak_channels, bak_to_mono; + OpusRepacketizer rp; + opus_int32 bytes_per_frame; + + + nb_frames = frame_size > st->Fs/25 ? 3 : 2; + bytes_per_frame = IMIN(1276,(out_data_bytes-3)/nb_frames); + + ALLOC(tmp_data, nb_frames*bytes_per_frame, unsigned char); + + opus_repacketizer_init(&rp); + + bak_mode = st->user_forced_mode; + bak_bandwidth = st->user_bandwidth; + bak_channels = st->force_channels; + + st->user_forced_mode = st->mode; + st->user_bandwidth = st->bandwidth; + st->force_channels = st->stream_channels; + bak_to_mono = st->silk_mode.toMono; + + if (bak_to_mono) + st->force_channels = 1; + else + st->prev_channels = st->stream_channels; + for (i=0;isilk_mode.toMono = 0; + /* When switching from SILK/Hybrid to CELT, only ask for a switch at the last frame */ + if (to_celt && i==nb_frames-1) + st->user_forced_mode = MODE_CELT_ONLY; + tmp_len = opus_encode_native(st, pcm+i*(st->channels*st->Fs/50), st->Fs/50, tmp_data+i*bytes_per_frame, bytes_per_frame); + if (tmp_len<0) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + ret = opus_repacketizer_cat(&rp, tmp_data+i*bytes_per_frame, tmp_len); + if (ret<0) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + } + ret = opus_repacketizer_out(&rp, data, out_data_bytes); + if (ret<0) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + st->user_forced_mode = bak_mode; + st->user_bandwidth = bak_bandwidth; + st->force_channels = bak_channels; + st->silk_mode.toMono = bak_to_mono; + RESTORE_STACK; + return ret; + } + + curr_bandwidth = st->bandwidth; + + /* Chooses the appropriate mode for speech + *NEVER* switch to/from CELT-only mode here as this will invalidate some assumptions */ + if (st->mode == MODE_SILK_ONLY && curr_bandwidth > OPUS_BANDWIDTH_WIDEBAND) + st->mode = MODE_HYBRID; + if (st->mode == MODE_HYBRID && curr_bandwidth <= OPUS_BANDWIDTH_WIDEBAND) + st->mode = MODE_SILK_ONLY; + + /* printf("%d %d %d %d\n", st->bitrate_bps, st->stream_channels, st->mode, curr_bandwidth); */ + bytes_target = IMIN(max_data_bytes-redundancy_bytes, st->bitrate_bps * frame_size / (st->Fs * 8)) - 1; + + data += 1; + + ec_enc_init(&enc, data, max_data_bytes-1); + + ALLOC(pcm_buf, (delay_compensation+frame_size)*st->channels, opus_val16); + for (i=0;ichannels;i++) + pcm_buf[i] = st->delay_buffer[(st->encoder_buffer-delay_compensation)*st->channels+i]; + + if (st->mode == MODE_CELT_ONLY) + hp_freq_smth1 = silk_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 ); + else + hp_freq_smth1 = ((silk_encoder*)silk_enc)->state_Fxx[0].sCmn.variable_HP_smth1_Q15; + + st->variable_HP_smth2_Q15 = silk_SMLAWB( st->variable_HP_smth2_Q15, + hp_freq_smth1 - st->variable_HP_smth2_Q15, SILK_FIX_CONST( VARIABLE_HP_SMTH_COEF2, 16 ) ); + + /* convert from log scale to Hertz */ + cutoff_Hz = silk_log2lin( silk_RSHIFT( st->variable_HP_smth2_Q15, 8 ) ); + + if (st->application == OPUS_APPLICATION_VOIP) + { + hp_cutoff(pcm, cutoff_Hz, &pcm_buf[delay_compensation*st->channels], st->hp_mem, frame_size, st->channels, st->Fs); + } else { + for (i=0;ichannels;i++) + pcm_buf[delay_compensation*st->channels + i] = pcm[i]; + } + + /* SILK processing */ + if (st->mode != MODE_CELT_ONLY) + { +#ifdef FIXED_POINT + const opus_int16 *pcm_silk; +#else + VARDECL(opus_int16, pcm_silk); + ALLOC(pcm_silk, st->channels*frame_size, opus_int16); +#endif + st->silk_mode.bitRate = 8*bytes_target*frame_rate; + if( st->mode == MODE_HYBRID ) { + st->silk_mode.bitRate /= st->stream_channels; + if( curr_bandwidth == OPUS_BANDWIDTH_SUPERWIDEBAND ) { + if( st->Fs == 100 * frame_size ) { + /* 24 kHz, 10 ms */ + st->silk_mode.bitRate = ( ( st->silk_mode.bitRate + 2000 + st->use_vbr * 1000 ) * 2 ) / 3; + } else { + /* 24 kHz, 20 ms */ + st->silk_mode.bitRate = ( ( st->silk_mode.bitRate + 1000 + st->use_vbr * 1000 ) * 2 ) / 3; + } + } else { + if( st->Fs == 100 * frame_size ) { + /* 48 kHz, 10 ms */ + st->silk_mode.bitRate = ( st->silk_mode.bitRate + 8000 + st->use_vbr * 3000 ) / 2; + } else { + /* 48 kHz, 20 ms */ + st->silk_mode.bitRate = ( st->silk_mode.bitRate + 9000 + st->use_vbr * 1000 ) / 2; + } + } + st->silk_mode.bitRate *= st->stream_channels; + /* don't let SILK use more than 80% */ + if( st->silk_mode.bitRate > ( st->bitrate_bps - 8*st->Fs/frame_size ) * 4/5 ) { + st->silk_mode.bitRate = ( st->bitrate_bps - 8*st->Fs/frame_size ) * 4/5; + } + } + + st->silk_mode.payloadSize_ms = 1000 * frame_size / st->Fs; + st->silk_mode.nChannelsAPI = st->channels; + st->silk_mode.nChannelsInternal = st->stream_channels; + if (curr_bandwidth == OPUS_BANDWIDTH_NARROWBAND) { + st->silk_mode.desiredInternalSampleRate = 8000; + } else if (curr_bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) { + st->silk_mode.desiredInternalSampleRate = 12000; + } else { + silk_assert( st->mode == MODE_HYBRID || curr_bandwidth == OPUS_BANDWIDTH_WIDEBAND ); + st->silk_mode.desiredInternalSampleRate = 16000; + } + if( st->mode == MODE_HYBRID ) { + /* Don't allow bandwidth reduction at lowest bitrates in hybrid mode */ + st->silk_mode.minInternalSampleRate = 16000; + } else { + st->silk_mode.minInternalSampleRate = 8000; + } + + if (st->mode == MODE_SILK_ONLY) + { + opus_int32 effective_max_rate = max_rate; + st->silk_mode.maxInternalSampleRate = 16000; + if (frame_rate > 50) + effective_max_rate = effective_max_rate*2/3; + if (effective_max_rate < 13000) + { + st->silk_mode.maxInternalSampleRate = 12000; + st->silk_mode.desiredInternalSampleRate = IMIN(12000, st->silk_mode.desiredInternalSampleRate); + } + if (effective_max_rate < 9600) + { + st->silk_mode.maxInternalSampleRate = 8000; + st->silk_mode.desiredInternalSampleRate = IMIN(8000, st->silk_mode.desiredInternalSampleRate); + } + } else { + st->silk_mode.maxInternalSampleRate = 16000; + } + + st->silk_mode.useCBR = !st->use_vbr; + + /* Call SILK encoder for the low band */ + nBytes = IMIN(1275, max_data_bytes-1-redundancy_bytes); + + st->silk_mode.maxBits = nBytes*8; + /* Only allow up to 90% of the bits for hybrid mode*/ + if (st->mode == MODE_HYBRID) + st->silk_mode.maxBits = (opus_int32)st->silk_mode.maxBits*9/10; + if (st->silk_mode.useCBR) + { + st->silk_mode.maxBits = (st->silk_mode.bitRate * frame_size / (st->Fs * 8))*8; + /* Reduce the initial target to make it easier to reach the CBR rate */ + st->silk_mode.bitRate = IMAX(1, st->silk_mode.bitRate-2000); + } + + if (prefill) + { + opus_int32 zero=0; +#ifdef FIXED_POINT + pcm_silk = st->delay_buffer; +#else + for (i=0;iencoder_buffer*st->channels;i++) + pcm_silk[i] = FLOAT2INT16(st->delay_buffer[i]); +#endif + silk_Encode( silk_enc, &st->silk_mode, pcm_silk, st->encoder_buffer, NULL, &zero, 1 ); + } + +#ifdef FIXED_POINT + pcm_silk = pcm_buf+delay_compensation*st->channels; +#else + for (i=0;ichannels;i++) + pcm_silk[i] = FLOAT2INT16(pcm_buf[delay_compensation*st->channels + i]); +#endif + ret = silk_Encode( silk_enc, &st->silk_mode, pcm_silk, frame_size, &enc, &nBytes, 0 ); + if( ret ) { + /*fprintf (stderr, "SILK encode error: %d\n", ret);*/ + /* Handle error */ + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + if (nBytes==0) + { + st->rangeFinal = 0; + data[-1] = gen_toc(st->mode, st->Fs/frame_size, curr_bandwidth, st->stream_channels); + RESTORE_STACK; + return 1; + } + /* Extract SILK internal bandwidth for signaling in first byte */ + if( st->mode == MODE_SILK_ONLY ) { + if( st->silk_mode.internalSampleRate == 8000 ) { + curr_bandwidth = OPUS_BANDWIDTH_NARROWBAND; + } else if( st->silk_mode.internalSampleRate == 12000 ) { + curr_bandwidth = OPUS_BANDWIDTH_MEDIUMBAND; + } else if( st->silk_mode.internalSampleRate == 16000 ) { + curr_bandwidth = OPUS_BANDWIDTH_WIDEBAND; + } + } else { + silk_assert( st->silk_mode.internalSampleRate == 16000 ); + } + + st->silk_mode.opusCanSwitch = st->silk_mode.switchReady; + /* FIXME: How do we allocate the redundancy for CBR? */ + if (st->silk_mode.opusCanSwitch) + { + redundancy = 1; + celt_to_silk = 0; + st->silk_bw_switch = 1; + } + } + + /* CELT processing */ + { + int endband=21; + + switch(curr_bandwidth) + { + case OPUS_BANDWIDTH_NARROWBAND: + endband = 13; + break; + case OPUS_BANDWIDTH_MEDIUMBAND: + case OPUS_BANDWIDTH_WIDEBAND: + endband = 17; + break; + case OPUS_BANDWIDTH_SUPERWIDEBAND: + endband = 19; + break; + case OPUS_BANDWIDTH_FULLBAND: + endband = 21; + break; + } + celt_encoder_ctl(celt_enc, CELT_SET_END_BAND(endband)); + celt_encoder_ctl(celt_enc, CELT_SET_CHANNELS(st->stream_channels)); + } + celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(OPUS_BITRATE_MAX)); + if (st->mode != MODE_SILK_ONLY) + { + celt_encoder_ctl(celt_enc, OPUS_SET_VBR(0)); + /* Allow prediction unless we decide to disable it later */ + celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(2)); + + if (st->mode == MODE_HYBRID) + { + int len; + + len = (ec_tell(&enc)+7)>>3; + if (redundancy) + len += st->mode == MODE_HYBRID ? 3 : 1; + if( st->use_vbr ) { + nb_compr_bytes = len + bytes_target - (st->silk_mode.bitRate * frame_size) / (8 * st->Fs); + } else { + /* check if SILK used up too much */ + nb_compr_bytes = len > bytes_target ? len : bytes_target; + } + } else { + if (st->use_vbr) + { + celt_encoder_ctl(celt_enc, OPUS_SET_VBR(1)); + celt_encoder_ctl(celt_enc, OPUS_SET_VBR_CONSTRAINT(st->vbr_constraint)); + celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(st->bitrate_bps)); + nb_compr_bytes = max_data_bytes-1-redundancy_bytes; + } else { + nb_compr_bytes = bytes_target; + } + } + + } else { + nb_compr_bytes = 0; + } + + ALLOC(tmp_prefill, st->channels*st->Fs/400, opus_val16); + if (st->mode != MODE_SILK_ONLY && st->mode != st->prev_mode && st->prev_mode > 0) + { + for (i=0;ichannels*st->Fs/400;i++) + tmp_prefill[i] = st->delay_buffer[(st->encoder_buffer-st->delay_compensation-st->Fs/400)*st->channels + i]; + } + + for (i=0;ichannels*(st->encoder_buffer-(frame_size+delay_compensation));i++) + st->delay_buffer[i] = st->delay_buffer[i+st->channels*frame_size]; + for (;iencoder_buffer*st->channels;i++) + st->delay_buffer[i] = pcm_buf[(frame_size+delay_compensation-st->encoder_buffer)*st->channels+i]; + + + if (st->mode != MODE_HYBRID || st->stream_channels==1) + st->silk_mode.stereoWidth_Q14 = 1<<14; + if( st->channels == 2 ) { + /* Apply stereo width reduction (at low bitrates) */ + if( st->hybrid_stereo_width_Q14 < (1 << 14) || st->silk_mode.stereoWidth_Q14 < (1 << 14) ) { + opus_val16 g1, g2; + const CELTMode *celt_mode; + + celt_encoder_ctl(celt_enc, CELT_GET_MODE(&celt_mode)); + g1 = st->hybrid_stereo_width_Q14; + g2 = (opus_val16)(st->silk_mode.stereoWidth_Q14); +#ifdef FIXED_POINT + g1 = g1==16384 ? Q15ONE : SHL16(g1,1); + g2 = g2==16384 ? Q15ONE : SHL16(g2,1); +#else + g1 *= (1.f/16384); + g2 *= (1.f/16384); +#endif + stereo_fade(pcm_buf, pcm_buf, g1, g2, celt_mode->overlap, + frame_size, st->channels, celt_mode->window, st->Fs); + st->hybrid_stereo_width_Q14 = st->silk_mode.stereoWidth_Q14; + } + } + + if ( st->mode != MODE_CELT_ONLY && ec_tell(&enc)+17+20*(st->mode == MODE_HYBRID) <= 8*(max_data_bytes-1)) + { + /* For SILK mode, the redundancy is inferred from the length */ + if (st->mode == MODE_HYBRID && (redundancy || ec_tell(&enc)+37 <= 8*nb_compr_bytes)) + ec_enc_bit_logp(&enc, redundancy, 12); + if (redundancy) + { + int max_redundancy; + ec_enc_bit_logp(&enc, celt_to_silk, 1); + if (st->mode == MODE_HYBRID) + max_redundancy = (max_data_bytes-1)-nb_compr_bytes-1; + else + max_redundancy = (max_data_bytes-1)-((ec_tell(&enc)+7)>>3); + /* Target the same bit-rate for redundancy as for the rest, + up to a max of 257 bytes */ + redundancy_bytes = IMIN(max_redundancy, st->bitrate_bps/1600); + redundancy_bytes = IMIN(257, IMAX(2, redundancy_bytes)); + if (st->mode == MODE_HYBRID) + ec_enc_uint(&enc, redundancy_bytes-2, 256); + } + } else { + redundancy = 0; + } + + if (!redundancy) + { + st->silk_bw_switch = 0; + redundancy_bytes = 0; + } + if (st->mode != MODE_CELT_ONLY)start_band=17; + + if (st->mode == MODE_SILK_ONLY) + { + ret = (ec_tell(&enc)+7)>>3; + ec_enc_done(&enc); + nb_compr_bytes = ret; + } else { + nb_compr_bytes = IMIN((max_data_bytes-1)-redundancy_bytes, nb_compr_bytes); + ec_enc_shrink(&enc, nb_compr_bytes); + } + + + /* 5 ms redundant frame for CELT->SILK */ + if (redundancy && celt_to_silk) + { + int err; + celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(0)); + celt_encoder_ctl(celt_enc, OPUS_SET_VBR(0)); + err = celt_encode_with_ec(celt_enc, pcm_buf, st->Fs/200, data+nb_compr_bytes, redundancy_bytes, NULL); + if (err < 0) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + celt_encoder_ctl(celt_enc, OPUS_GET_FINAL_RANGE(&redundant_rng)); + celt_encoder_ctl(celt_enc, OPUS_RESET_STATE); + } + + celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(start_band)); + + if (st->mode != MODE_SILK_ONLY) + { + if (st->mode != st->prev_mode && st->prev_mode > 0) + { + unsigned char dummy[2]; + celt_encoder_ctl(celt_enc, OPUS_RESET_STATE); + + /* Prefilling */ + celt_encode_with_ec(celt_enc, tmp_prefill, st->Fs/400, dummy, 2, NULL); + celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(0)); + } + /* If false, we already busted the budget and we'll end up with a "PLC packet" */ + if (ec_tell(&enc) <= 8*nb_compr_bytes) + { + ret = celt_encode_with_ec(celt_enc, pcm_buf, frame_size, NULL, nb_compr_bytes, &enc); + if (ret < 0) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + } + } + + /* 5 ms redundant frame for SILK->CELT */ + if (redundancy && !celt_to_silk) + { + int err; + unsigned char dummy[2]; + int N2, N4; + N2 = st->Fs/200; + N4 = st->Fs/400; + + celt_encoder_ctl(celt_enc, OPUS_RESET_STATE); + celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(0)); + celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(0)); + + /* NOTE: We could speed this up slightly (at the expense of code size) by just adding a function that prefills the buffer */ + celt_encode_with_ec(celt_enc, pcm_buf+st->channels*(frame_size-N2-N4), N4, dummy, 2, NULL); + + err = celt_encode_with_ec(celt_enc, pcm_buf+st->channels*(frame_size-N2), N2, data+nb_compr_bytes, redundancy_bytes, NULL); + if (err < 0) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + celt_encoder_ctl(celt_enc, OPUS_GET_FINAL_RANGE(&redundant_rng)); + } + + + + /* Signalling the mode in the first byte */ + data--; + data[0] = gen_toc(st->mode, st->Fs/frame_size, curr_bandwidth, st->stream_channels); + + st->rangeFinal = enc.rng ^ redundant_rng; + + if (to_celt) + st->prev_mode = MODE_CELT_ONLY; + else + st->prev_mode = st->mode; + st->prev_channels = st->stream_channels; + st->prev_framesize = frame_size; + + st->first = 0; + + /* In the unlikely case that the SILK encoder busted its target, tell + the decoder to call the PLC */ + if (ec_tell(&enc) > (max_data_bytes-1)*8) + { + if (max_data_bytes < 2) + { + RESTORE_STACK; + return OPUS_BUFFER_TOO_SMALL; + } + data[1] = 0; + ret = 1; + st->rangeFinal = 0; + } else if (st->mode==MODE_SILK_ONLY&&!redundancy) + { + /*When in LPC only mode it's perfectly + reasonable to strip off trailing zero bytes as + the required range decoder behavior is to + fill these in. This can't be done when the MDCT + modes are used because the decoder needs to know + the actual length for allocation purposes.*/ + while(ret>2&&data[ret]==0)ret--; + } + /* Count ToC and redundancy */ + ret += 1+redundancy_bytes; + if (!st->use_vbr && ret >= 3) + { + if (pad_frame(data, ret, max_data_bytes)) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + ret = max_data_bytes; + } + RESTORE_STACK; + return ret; +} + +#ifdef FIXED_POINT + +#ifndef DISABLE_FLOAT_API +opus_int32 opus_encode_float(OpusEncoder *st, const float *pcm, int frame_size, + unsigned char *data, opus_int32 max_data_bytes) +{ + int i, ret; + VARDECL(opus_int16, in); + ALLOC_STACK; + + if(frame_size<0) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + + ALLOC(in, frame_size*st->channels, opus_int16); + + for (i=0;ichannels;i++) + in[i] = FLOAT2INT16(pcm[i]); + ret = opus_encode(st, in, frame_size, data, max_data_bytes); + RESTORE_STACK; + return ret; +} +#endif + +#else +opus_int32 opus_encode(OpusEncoder *st, const opus_int16 *pcm, int frame_size, + unsigned char *data, opus_int32 max_data_bytes) +{ + int i, ret; + VARDECL(float, in); + ALLOC_STACK; + + ALLOC(in, frame_size*st->channels, float); + + for (i=0;ichannels;i++) + in[i] = (1.0f/32768)*pcm[i]; + ret = opus_encode_float(st, in, frame_size, data, max_data_bytes); + RESTORE_STACK; + return ret; +} +#endif + + +int opus_encoder_ctl(OpusEncoder *st, int request, ...) +{ + int ret; + CELTEncoder *celt_enc; + va_list ap; + + ret = OPUS_OK; + va_start(ap, request); + + celt_enc = (CELTEncoder*)((char*)st+st->celt_enc_offset); + + switch (request) + { + case OPUS_SET_APPLICATION_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if ( (value != OPUS_APPLICATION_VOIP && value != OPUS_APPLICATION_AUDIO + && value != OPUS_APPLICATION_RESTRICTED_LOWDELAY) + || (!st->first && st->application != value)) + { + ret = OPUS_BAD_ARG; + break; + } + st->application = value; + } + break; + case OPUS_GET_APPLICATION_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + *value = st->application; + } + break; + case OPUS_SET_BITRATE_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value != OPUS_AUTO && value != OPUS_BITRATE_MAX) + { + if (value <= 0) + goto bad_arg; + else if (value <= 500) + value = 500; + else if (value > (opus_int32)300000*st->channels) + value = (opus_int32)300000*st->channels; + } + st->user_bitrate_bps = value; + } + break; + case OPUS_GET_BITRATE_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + *value = user_bitrate_to_bitrate(st, st->prev_framesize, 1276); + } + break; + case OPUS_SET_FORCE_CHANNELS_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if((value<1 || value>st->channels) && value != OPUS_AUTO) + return OPUS_BAD_ARG; + st->force_channels = value; + } + break; + case OPUS_GET_FORCE_CHANNELS_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + *value = st->force_channels; + } + break; + case OPUS_SET_MAX_BANDWIDTH_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value < OPUS_BANDWIDTH_NARROWBAND || value > OPUS_BANDWIDTH_FULLBAND) + return OPUS_BAD_ARG; + st->max_bandwidth = value; + if (st->max_bandwidth == OPUS_BANDWIDTH_NARROWBAND) { + st->silk_mode.maxInternalSampleRate = 8000; + } else if (st->max_bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) { + st->silk_mode.maxInternalSampleRate = 12000; + } else { + st->silk_mode.maxInternalSampleRate = 16000; + } + } + break; + case OPUS_GET_MAX_BANDWIDTH_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + *value = st->max_bandwidth; + } + break; + case OPUS_SET_BANDWIDTH_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if ((value < OPUS_BANDWIDTH_NARROWBAND || value > OPUS_BANDWIDTH_FULLBAND) && value != OPUS_AUTO) + return OPUS_BAD_ARG; + st->user_bandwidth = value; + if (st->user_bandwidth == OPUS_BANDWIDTH_NARROWBAND) { + st->silk_mode.maxInternalSampleRate = 8000; + } else if (st->user_bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) { + st->silk_mode.maxInternalSampleRate = 12000; + } else { + st->silk_mode.maxInternalSampleRate = 16000; + } + } + break; + case OPUS_GET_BANDWIDTH_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + *value = st->bandwidth; + } + break; + case OPUS_SET_DTX_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>1) + return OPUS_BAD_ARG; + st->silk_mode.useDTX = value; + } + break; + case OPUS_GET_DTX_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + *value = st->silk_mode.useDTX; + } + break; + case OPUS_SET_COMPLEXITY_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>10) + return OPUS_BAD_ARG; + st->silk_mode.complexity = value; + celt_encoder_ctl(celt_enc, OPUS_SET_COMPLEXITY(value)); + } + break; + case OPUS_GET_COMPLEXITY_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + *value = st->silk_mode.complexity; + } + break; + case OPUS_SET_INBAND_FEC_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>1) + return OPUS_BAD_ARG; + st->silk_mode.useInBandFEC = value; + } + break; + case OPUS_GET_INBAND_FEC_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + *value = st->silk_mode.useInBandFEC; + } + break; + case OPUS_SET_PACKET_LOSS_PERC_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value < 0 || value > 100) + return OPUS_BAD_ARG; + st->silk_mode.packetLossPercentage = value; + celt_encoder_ctl(celt_enc, OPUS_SET_PACKET_LOSS_PERC(value)); + } + break; + case OPUS_GET_PACKET_LOSS_PERC_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + *value = st->silk_mode.packetLossPercentage; + } + break; + case OPUS_SET_VBR_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>1) + return OPUS_BAD_ARG; + st->use_vbr = value; + st->silk_mode.useCBR = 1-value; + } + break; + case OPUS_GET_VBR_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + *value = st->use_vbr; + } + break; + case OPUS_SET_VOICE_RATIO_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value>100 || value<-1) + goto bad_arg; + st->voice_ratio = value; + } + break; + case OPUS_GET_VOICE_RATIO_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + *value = st->voice_ratio; + } + break; + case OPUS_SET_VBR_CONSTRAINT_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>1) + return OPUS_BAD_ARG; + st->vbr_constraint = value; + } + break; + case OPUS_GET_VBR_CONSTRAINT_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + *value = st->vbr_constraint; + } + break; + case OPUS_SET_SIGNAL_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value!=OPUS_AUTO && value!=OPUS_SIGNAL_VOICE && value!=OPUS_SIGNAL_MUSIC) + return OPUS_BAD_ARG; + st->signal_type = value; + } + break; + case OPUS_GET_SIGNAL_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + *value = st->signal_type; + } + break; + case OPUS_GET_LOOKAHEAD_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + *value = st->Fs/400; + if (st->application != OPUS_APPLICATION_RESTRICTED_LOWDELAY) + *value += st->delay_compensation; + } + break; + case OPUS_GET_SAMPLE_RATE_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (value==NULL) + { + ret = OPUS_BAD_ARG; + break; + } + *value = st->Fs; + } + break; + case OPUS_GET_FINAL_RANGE_REQUEST: + { + opus_uint32 *value = va_arg(ap, opus_uint32*); + *value = st->rangeFinal; + } + break; + case OPUS_SET_LSB_DEPTH_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + ret = celt_encoder_ctl(celt_enc, OPUS_SET_LSB_DEPTH(value)); + } + break; + case OPUS_GET_LSB_DEPTH_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + celt_encoder_ctl(celt_enc, OPUS_GET_LSB_DEPTH(value)); + } + break; + case OPUS_RESET_STATE: + { + void *silk_enc; + silk_EncControlStruct dummy; + silk_enc = (char*)st+st->silk_enc_offset; + + OPUS_CLEAR((char*)&st->OPUS_ENCODER_RESET_START, + sizeof(OpusEncoder)- + ((char*)&st->OPUS_ENCODER_RESET_START - (char*)st)); + + celt_encoder_ctl(celt_enc, OPUS_RESET_STATE); + silk_InitEncoder( silk_enc, &dummy ); + st->stream_channels = st->channels; + st->hybrid_stereo_width_Q14 = 1 << 14; + st->first = 1; + st->mode = MODE_HYBRID; + st->bandwidth = OPUS_BANDWIDTH_FULLBAND; + st->variable_HP_smth2_Q15 = silk_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 ); + } + break; + case OPUS_SET_FORCE_MODE_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if ((value < MODE_SILK_ONLY || value > MODE_CELT_ONLY) && value != OPUS_AUTO) + goto bad_arg; + st->user_forced_mode = value; + } + break; + default: + /* fprintf(stderr, "unknown opus_encoder_ctl() request: %d", request);*/ + ret = OPUS_UNIMPLEMENTED; + break; + } + va_end(ap); + return ret; +bad_arg: + va_end(ap); + return OPUS_BAD_ARG; +} + +void opus_encoder_destroy(OpusEncoder *st) +{ + opus_free(st); +} diff --git a/code/opus-1.0.2/src/opus_multistream.c b/code/opus-1.0.2/src/opus_multistream.c new file mode 100644 index 00000000..a7f25a52 --- /dev/null +++ b/code/opus-1.0.2/src/opus_multistream.c @@ -0,0 +1,1027 @@ +/* Copyright (c) 2011 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "opus_multistream.h" +#include "opus.h" +#include "opus_private.h" +#include "stack_alloc.h" +#include +#include "float_cast.h" +#include "os_support.h" + +typedef struct ChannelLayout { + int nb_channels; + int nb_streams; + int nb_coupled_streams; + unsigned char mapping[256]; +} ChannelLayout; + +struct OpusMSEncoder { + ChannelLayout layout; + int bitrate; + /* Encoder states go here */ +}; + +struct OpusMSDecoder { + ChannelLayout layout; + /* Decoder states go here */ +}; + +#ifdef FIXED_POINT +#define opus_encode_native opus_encode +#else +#define opus_encode_native opus_encode_float +#endif + +static int validate_layout(const ChannelLayout *layout) +{ + int i, max_channel; + + max_channel = layout->nb_streams+layout->nb_coupled_streams; + if (max_channel>255) + return 0; + for (i=0;inb_channels;i++) + { + if (layout->mapping[i] >= max_channel && layout->mapping[i] != 255) + return 0; + } + return 1; +} + + +static int get_left_channel(const ChannelLayout *layout, int stream_id, int prev) +{ + int i; + i = (prev<0) ? 0 : prev+1; + for (;inb_channels;i++) + { + if (layout->mapping[i]==stream_id*2) + return i; + } + return -1; +} + +static int get_right_channel(const ChannelLayout *layout, int stream_id, int prev) +{ + int i; + i = (prev<0) ? 0 : prev+1; + for (;inb_channels;i++) + { + if (layout->mapping[i]==stream_id*2+1) + return i; + } + return -1; +} + +static int get_mono_channel(const ChannelLayout *layout, int stream_id, int prev) +{ + int i; + i = (prev<0) ? 0 : prev+1; + for (;inb_channels;i++) + { + if (layout->mapping[i]==stream_id+layout->nb_coupled_streams) + return i; + } + return -1; +} + +static int validate_encoder_layout(const ChannelLayout *layout) +{ + int s; + for (s=0;snb_streams;s++) + { + if (s < layout->nb_coupled_streams) + { + if (get_left_channel(layout, s, -1)==-1) + return 0; + if (get_right_channel(layout, s, -1)==-1) + return 0; + } else { + if (get_mono_channel(layout, s, -1)==-1) + return 0; + } + } + return 1; +} + +opus_int32 opus_multistream_encoder_get_size(int nb_streams, int nb_coupled_streams) +{ + int coupled_size; + int mono_size; + + if(nb_streams<1||nb_coupled_streams>nb_streams||nb_coupled_streams<0)return 0; + coupled_size = opus_encoder_get_size(2); + mono_size = opus_encoder_get_size(1); + return align(sizeof(OpusMSEncoder)) + + nb_coupled_streams * align(coupled_size) + + (nb_streams-nb_coupled_streams) * align(mono_size); +} + + + +int opus_multistream_encoder_init( + OpusMSEncoder *st, + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping, + int application +) +{ + int coupled_size; + int mono_size; + int i, ret; + char *ptr; + + if ((channels>255) || (channels<1) || (coupled_streams>streams) || + (coupled_streams+streams>255) || (streams<1) || (coupled_streams<0)) + return OPUS_BAD_ARG; + + st->layout.nb_channels = channels; + st->layout.nb_streams = streams; + st->layout.nb_coupled_streams = coupled_streams; + + for (i=0;ilayout.nb_channels;i++) + st->layout.mapping[i] = mapping[i]; + if (!validate_layout(&st->layout) || !validate_encoder_layout(&st->layout)) + return OPUS_BAD_ARG; + ptr = (char*)st + align(sizeof(OpusMSEncoder)); + coupled_size = opus_encoder_get_size(2); + mono_size = opus_encoder_get_size(1); + + for (i=0;ilayout.nb_coupled_streams;i++) + { + ret = opus_encoder_init((OpusEncoder*)ptr, Fs, 2, application); + if(ret!=OPUS_OK)return ret; + ptr += align(coupled_size); + } + for (;ilayout.nb_streams;i++) + { + ret = opus_encoder_init((OpusEncoder*)ptr, Fs, 1, application); + if(ret!=OPUS_OK)return ret; + ptr += align(mono_size); + } + return OPUS_OK; +} + +OpusMSEncoder *opus_multistream_encoder_create( + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping, + int application, + int *error +) +{ + int ret; + OpusMSEncoder *st; + if ((channels>255) || (channels<1) || (coupled_streams>streams) || + (coupled_streams+streams>255) || (streams<1) || (coupled_streams<0)) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + st = (OpusMSEncoder *)opus_alloc(opus_multistream_encoder_get_size(streams, coupled_streams)); + if (st==NULL) + { + if (error) + *error = OPUS_ALLOC_FAIL; + return NULL; + } + ret = opus_multistream_encoder_init(st, Fs, channels, streams, coupled_streams, mapping, application); + if (ret != OPUS_OK) + { + opus_free(st); + st = NULL; + } + if (error) + *error = ret; + return st; +} + +typedef void (*opus_copy_channel_in_func)( + opus_val16 *dst, + int dst_stride, + const void *src, + int src_stride, + int src_channel, + int frame_size +); + +/* Max size in case the encoder decides to return three frames */ +#define MS_FRAME_TMP (3*1275+7) +static int opus_multistream_encode_native +( + OpusMSEncoder *st, + opus_copy_channel_in_func copy_channel_in, + const void *pcm, + int frame_size, + unsigned char *data, + opus_int32 max_data_bytes +) +{ + opus_int32 Fs; + int coupled_size; + int mono_size; + int s; + char *ptr; + int tot_size; + VARDECL(opus_val16, buf); + unsigned char tmp_data[MS_FRAME_TMP]; + OpusRepacketizer rp; + ALLOC_STACK; + + ptr = (char*)st + align(sizeof(OpusMSEncoder)); + opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_SAMPLE_RATE(&Fs)); + /* Validate frame_size before using it to allocate stack space. + This mirrors the checks in opus_encode[_float](). */ + if (400*frame_size != Fs && 200*frame_size != Fs && + 100*frame_size != Fs && 50*frame_size != Fs && + 25*frame_size != Fs && 50*frame_size != 3*Fs) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + ALLOC(buf, 2*frame_size, opus_val16); + coupled_size = opus_encoder_get_size(2); + mono_size = opus_encoder_get_size(1); + + if (max_data_bytes < 4*st->layout.nb_streams-1) + { + RESTORE_STACK; + return OPUS_BUFFER_TOO_SMALL; + } + /* Counting ToC */ + tot_size = 0; + for (s=0;slayout.nb_streams;s++) + { + OpusEncoder *enc; + int len; + int curr_max; + + opus_repacketizer_init(&rp); + enc = (OpusEncoder*)ptr; + if (s < st->layout.nb_coupled_streams) + { + int left, right; + left = get_left_channel(&st->layout, s, -1); + right = get_right_channel(&st->layout, s, -1); + (*copy_channel_in)(buf, 2, + pcm, st->layout.nb_channels, left, frame_size); + (*copy_channel_in)(buf+1, 2, + pcm, st->layout.nb_channels, right, frame_size); + ptr += align(coupled_size); + } else { + int chan = get_mono_channel(&st->layout, s, -1); + (*copy_channel_in)(buf, 1, + pcm, st->layout.nb_channels, chan, frame_size); + ptr += align(mono_size); + } + /* number of bytes left (+Toc) */ + curr_max = max_data_bytes - tot_size; + /* Reserve three bytes for the last stream and four for the others */ + curr_max -= IMAX(0,4*(st->layout.nb_streams-s-1)-1); + curr_max = IMIN(curr_max,MS_FRAME_TMP); + len = opus_encode_native(enc, buf, frame_size, tmp_data, curr_max); + if (len<0) + { + RESTORE_STACK; + return len; + } + /* We need to use the repacketizer to add the self-delimiting lengths + while taking into account the fact that the encoder can now return + more than one frame at a time (e.g. 60 ms CELT-only) */ + opus_repacketizer_cat(&rp, tmp_data, len); + len = opus_repacketizer_out_range_impl(&rp, 0, opus_repacketizer_get_nb_frames(&rp), data, max_data_bytes-tot_size, s != st->layout.nb_streams-1); + data += len; + tot_size += len; + } + RESTORE_STACK; + return tot_size; + +} + +#if !defined(DISABLE_FLOAT_API) +static void opus_copy_channel_in_float( + opus_val16 *dst, + int dst_stride, + const void *src, + int src_stride, + int src_channel, + int frame_size +) +{ + const float *float_src; + int i; + float_src = (const float *)src; + for (i=0;ilayout.nb_streams + st->layout.nb_coupled_streams; + value /= chan; + for (s=0;slayout.nb_streams;s++) + { + OpusEncoder *enc; + enc = (OpusEncoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + opus_encoder_ctl(enc, request, value * (s < st->layout.nb_coupled_streams ? 2 : 1)); + } + } + break; + case OPUS_GET_BITRATE_REQUEST: + { + int s; + opus_int32 *value = va_arg(ap, opus_int32*); + *value = 0; + for (s=0;slayout.nb_streams;s++) + { + opus_int32 rate; + OpusEncoder *enc; + enc = (OpusEncoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + opus_encoder_ctl(enc, request, &rate); + *value += rate; + } + } + break; + case OPUS_GET_LSB_DEPTH_REQUEST: + case OPUS_GET_VBR_REQUEST: + case OPUS_GET_APPLICATION_REQUEST: + case OPUS_GET_BANDWIDTH_REQUEST: + case OPUS_GET_COMPLEXITY_REQUEST: + case OPUS_GET_PACKET_LOSS_PERC_REQUEST: + case OPUS_GET_DTX_REQUEST: + case OPUS_GET_VOICE_RATIO_REQUEST: + case OPUS_GET_VBR_CONSTRAINT_REQUEST: + case OPUS_GET_SIGNAL_REQUEST: + case OPUS_GET_LOOKAHEAD_REQUEST: + case OPUS_GET_SAMPLE_RATE_REQUEST: + case OPUS_GET_INBAND_FEC_REQUEST: + { + OpusEncoder *enc; + /* For int32* GET params, just query the first stream */ + opus_int32 *value = va_arg(ap, opus_int32*); + enc = (OpusEncoder*)ptr; + ret = opus_encoder_ctl(enc, request, value); + } + break; + case OPUS_GET_FINAL_RANGE_REQUEST: + { + int s; + opus_uint32 *value = va_arg(ap, opus_uint32*); + opus_uint32 tmp; + *value=0; + for (s=0;slayout.nb_streams;s++) + { + OpusEncoder *enc; + enc = (OpusEncoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + ret = opus_encoder_ctl(enc, request, &tmp); + if (ret != OPUS_OK) break; + *value ^= tmp; + } + } + break; + case OPUS_SET_LSB_DEPTH_REQUEST: + case OPUS_SET_COMPLEXITY_REQUEST: + case OPUS_SET_VBR_REQUEST: + case OPUS_SET_VBR_CONSTRAINT_REQUEST: + case OPUS_SET_BANDWIDTH_REQUEST: + case OPUS_SET_SIGNAL_REQUEST: + case OPUS_SET_APPLICATION_REQUEST: + case OPUS_SET_INBAND_FEC_REQUEST: + case OPUS_SET_PACKET_LOSS_PERC_REQUEST: + case OPUS_SET_DTX_REQUEST: + case OPUS_SET_FORCE_MODE_REQUEST: + { + int s; + /* This works for int32 params */ + opus_int32 value = va_arg(ap, opus_int32); + for (s=0;slayout.nb_streams;s++) + { + OpusEncoder *enc; + + enc = (OpusEncoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + ret = opus_encoder_ctl(enc, request, value); + if (ret != OPUS_OK) + break; + } + } + break; + case OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST: + { + int s; + opus_int32 stream_id; + OpusEncoder **value; + stream_id = va_arg(ap, opus_int32); + if (stream_id<0 || stream_id >= st->layout.nb_streams) + ret = OPUS_BAD_ARG; + value = va_arg(ap, OpusEncoder**); + for (s=0;slayout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + } + *value = (OpusEncoder*)ptr; + } + break; + default: + ret = OPUS_UNIMPLEMENTED; + break; + } + + va_end(ap); + return ret; +} + +void opus_multistream_encoder_destroy(OpusMSEncoder *st) +{ + opus_free(st); +} + + +/* DECODER */ + +opus_int32 opus_multistream_decoder_get_size(int nb_streams, int nb_coupled_streams) +{ + int coupled_size; + int mono_size; + + if(nb_streams<1||nb_coupled_streams>nb_streams||nb_coupled_streams<0)return 0; + coupled_size = opus_decoder_get_size(2); + mono_size = opus_decoder_get_size(1); + return align(sizeof(OpusMSDecoder)) + + nb_coupled_streams * align(coupled_size) + + (nb_streams-nb_coupled_streams) * align(mono_size); +} + +int opus_multistream_decoder_init( + OpusMSDecoder *st, + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping +) +{ + int coupled_size; + int mono_size; + int i, ret; + char *ptr; + + if ((channels>255) || (channels<1) || (coupled_streams>streams) || + (coupled_streams+streams>255) || (streams<1) || (coupled_streams<0)) + return OPUS_BAD_ARG; + + st->layout.nb_channels = channels; + st->layout.nb_streams = streams; + st->layout.nb_coupled_streams = coupled_streams; + + for (i=0;ilayout.nb_channels;i++) + st->layout.mapping[i] = mapping[i]; + if (!validate_layout(&st->layout)) + return OPUS_BAD_ARG; + + ptr = (char*)st + align(sizeof(OpusMSDecoder)); + coupled_size = opus_decoder_get_size(2); + mono_size = opus_decoder_get_size(1); + + for (i=0;ilayout.nb_coupled_streams;i++) + { + ret=opus_decoder_init((OpusDecoder*)ptr, Fs, 2); + if(ret!=OPUS_OK)return ret; + ptr += align(coupled_size); + } + for (;ilayout.nb_streams;i++) + { + ret=opus_decoder_init((OpusDecoder*)ptr, Fs, 1); + if(ret!=OPUS_OK)return ret; + ptr += align(mono_size); + } + return OPUS_OK; +} + + +OpusMSDecoder *opus_multistream_decoder_create( + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping, + int *error +) +{ + int ret; + OpusMSDecoder *st; + if ((channels>255) || (channels<1) || (coupled_streams>streams) || + (coupled_streams+streams>255) || (streams<1) || (coupled_streams<0)) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + st = (OpusMSDecoder *)opus_alloc(opus_multistream_decoder_get_size(streams, coupled_streams)); + if (st==NULL) + { + if (error) + *error = OPUS_ALLOC_FAIL; + return NULL; + } + ret = opus_multistream_decoder_init(st, Fs, channels, streams, coupled_streams, mapping); + if (error) + *error = ret; + if (ret != OPUS_OK) + { + opus_free(st); + st = NULL; + } + return st; +} + +typedef void (*opus_copy_channel_out_func)( + void *dst, + int dst_stride, + int dst_channel, + const opus_val16 *src, + int src_stride, + int frame_size +); + +static int opus_multistream_decode_native( + OpusMSDecoder *st, + const unsigned char *data, + opus_int32 len, + void *pcm, + opus_copy_channel_out_func copy_channel_out, + int frame_size, + int decode_fec +) +{ + opus_int32 Fs; + int coupled_size; + int mono_size; + int s, c; + char *ptr; + int do_plc=0; + VARDECL(opus_val16, buf); + ALLOC_STACK; + + /* Limit frame_size to avoid excessive stack allocations. */ + opus_multistream_decoder_ctl(st, OPUS_GET_SAMPLE_RATE(&Fs)); + frame_size = IMIN(frame_size, Fs/25*3); + ALLOC(buf, 2*frame_size, opus_val16); + ptr = (char*)st + align(sizeof(OpusMSDecoder)); + coupled_size = opus_decoder_get_size(2); + mono_size = opus_decoder_get_size(1); + + if (len==0) + do_plc = 1; + if (len < 0) + return OPUS_BAD_ARG; + if (!do_plc && len < 2*st->layout.nb_streams-1) + return OPUS_INVALID_PACKET; + for (s=0;slayout.nb_streams;s++) + { + OpusDecoder *dec; + int packet_offset, ret; + + dec = (OpusDecoder*)ptr; + ptr += (s < st->layout.nb_coupled_streams) ? align(coupled_size) : align(mono_size); + + if (!do_plc && len<=0) + { + RESTORE_STACK; + return OPUS_INVALID_PACKET; + } + packet_offset = 0; + ret = opus_decode_native(dec, data, len, buf, frame_size, decode_fec, s!=st->layout.nb_streams-1, &packet_offset); + data += packet_offset; + len -= packet_offset; + if (ret > frame_size) + { + RESTORE_STACK; + return OPUS_BUFFER_TOO_SMALL; + } + if (s>0 && ret != frame_size) + { + RESTORE_STACK; + return OPUS_INVALID_PACKET; + } + if (ret <= 0) + { + RESTORE_STACK; + return ret; + } + frame_size = ret; + if (s < st->layout.nb_coupled_streams) + { + int chan, prev; + prev = -1; + /* Copy "left" audio to the channel(s) where it belongs */ + while ( (chan = get_left_channel(&st->layout, s, prev)) != -1) + { + (*copy_channel_out)(pcm, st->layout.nb_channels, chan, + buf, 2, frame_size); + prev = chan; + } + prev = -1; + /* Copy "right" audio to the channel(s) where it belongs */ + while ( (chan = get_right_channel(&st->layout, s, prev)) != -1) + { + (*copy_channel_out)(pcm, st->layout.nb_channels, chan, + buf+1, 2, frame_size); + prev = chan; + } + } else { + int chan, prev; + prev = -1; + /* Copy audio to the channel(s) where it belongs */ + while ( (chan = get_mono_channel(&st->layout, s, prev)) != -1) + { + (*copy_channel_out)(pcm, st->layout.nb_channels, chan, + buf, 1, frame_size); + prev = chan; + } + } + } + /* Handle muted channels */ + for (c=0;clayout.nb_channels;c++) + { + if (st->layout.mapping[c] == 255) + { + (*copy_channel_out)(pcm, st->layout.nb_channels, c, + NULL, 0, frame_size); + } + } + RESTORE_STACK; + return frame_size; +} + +#if !defined(DISABLE_FLOAT_API) +static void opus_copy_channel_out_float( + void *dst, + int dst_stride, + int dst_channel, + const opus_val16 *src, + int src_stride, + int frame_size +) +{ + float *float_dst; + int i; + float_dst = (float*)dst; + if (src != NULL) + { + for (i=0;ilayout.nb_streams;s++) + { + OpusDecoder *dec; + dec = (OpusDecoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + ret = opus_decoder_ctl(dec, request, &tmp); + if (ret != OPUS_OK) break; + *value ^= tmp; + } + } + break; + case OPUS_RESET_STATE: + { + int s; + for (s=0;slayout.nb_streams;s++) + { + OpusDecoder *dec; + + dec = (OpusDecoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + ret = opus_decoder_ctl(dec, OPUS_RESET_STATE); + if (ret != OPUS_OK) + break; + } + } + break; + case OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST: + { + int s; + opus_int32 stream_id; + OpusDecoder **value; + stream_id = va_arg(ap, opus_int32); + if (stream_id<0 || stream_id >= st->layout.nb_streams) + ret = OPUS_BAD_ARG; + value = va_arg(ap, OpusDecoder**); + for (s=0;slayout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + } + *value = (OpusDecoder*)ptr; + } + break; + case OPUS_SET_GAIN_REQUEST: + { + int s; + /* This works for int32 params */ + opus_int32 value = va_arg(ap, opus_int32); + for (s=0;slayout.nb_streams;s++) + { + OpusDecoder *dec; + + dec = (OpusDecoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + ret = opus_decoder_ctl(dec, request, value); + if (ret != OPUS_OK) + break; + } + } + break; + default: + ret = OPUS_UNIMPLEMENTED; + break; + } + + va_end(ap); + return ret; +} + + +void opus_multistream_decoder_destroy(OpusMSDecoder *st) +{ + opus_free(st); +} diff --git a/code/opus-1.0.2/src/opus_private.h b/code/opus-1.0.2/src/opus_private.h new file mode 100644 index 00000000..52482bc1 --- /dev/null +++ b/code/opus-1.0.2/src/opus_private.h @@ -0,0 +1,85 @@ +/* Copyright (c) 2012 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (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 OPUS_PRIVATE_H +#define OPUS_PRIVATE_H + +#include "arch.h" +#include "opus.h" + +struct OpusRepacketizer { + unsigned char toc; + int nb_frames; + const unsigned char *frames[48]; + short len[48]; + int framesize; +}; + + +#define MODE_SILK_ONLY 1000 +#define MODE_HYBRID 1001 +#define MODE_CELT_ONLY 1002 + +#define OPUS_SET_VOICE_RATIO_REQUEST 11018 +#define OPUS_GET_VOICE_RATIO_REQUEST 11019 + +/** Configures the encoder's expected percentage of voice + * opposed to music or other signals. + * + * @note This interface is currently more aspiration than actuality. It's + * ultimately expected to bias an automatic signal classifier, but it currently + * just shifts the static bitrate to mode mapping around a little bit. + * + * @param[in] x int: Voice percentage in the range 0-100, inclusive. + * @hideinitializer */ +#define OPUS_SET_VOICE_RATIO(x) OPUS_SET_VOICE_RATIO_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured voice ratio value, @see OPUS_SET_VOICE_RATIO + * + * @param[out] x int*: Voice percentage in the range 0-100, inclusive. + * @hideinitializer */ +#define OPUS_GET_VOICE_RATIO(x) OPUS_GET_VOICE_RATIO_REQUEST, __opus_check_int_ptr(x) + + +#define OPUS_SET_FORCE_MODE_REQUEST 11002 +#define OPUS_SET_FORCE_MODE(x) OPUS_SET_FORCE_MODE_REQUEST, __opus_check_int(x) + + +int encode_size(int size, unsigned char *data); + +int opus_decode_native(OpusDecoder *st, const unsigned char *data, opus_int32 len, + opus_val16 *pcm, int frame_size, int decode_fec, int self_delimited, int *packet_offset); + +/* Make sure everything's aligned to sizeof(void *) bytes */ +static inline int align(int i) +{ + return (i+sizeof(void *)-1)&-((int)sizeof(void *)); +} + +opus_int32 opus_repacketizer_out_range_impl(OpusRepacketizer *rp, int begin, int end, unsigned char *data, opus_int32 maxlen, int self_delimited); + +#endif /* OPUS_PRIVATE_H */ diff --git a/code/opus-1.0.2/src/repacketizer.c b/code/opus-1.0.2/src/repacketizer.c new file mode 100644 index 00000000..26315b62 --- /dev/null +++ b/code/opus-1.0.2/src/repacketizer.c @@ -0,0 +1,208 @@ +/* Copyright (c) 2011 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "opus.h" +#include "opus_private.h" +#include "os_support.h" + + +int opus_repacketizer_get_size(void) +{ + return sizeof(OpusRepacketizer); +} + +OpusRepacketizer *opus_repacketizer_init(OpusRepacketizer *rp) +{ + rp->nb_frames = 0; + return rp; +} + +OpusRepacketizer *opus_repacketizer_create(void) +{ + OpusRepacketizer *rp; + rp=(OpusRepacketizer *)opus_alloc(opus_repacketizer_get_size()); + if(rp==NULL)return NULL; + return opus_repacketizer_init(rp); +} + +void opus_repacketizer_destroy(OpusRepacketizer *rp) +{ + opus_free(rp); +} + +int opus_repacketizer_cat(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len) +{ + unsigned char tmp_toc; + int curr_nb_frames,ret; + /* Set of check ToC */ + if (len<1) return OPUS_INVALID_PACKET; + if (rp->nb_frames == 0) + { + rp->toc = data[0]; + rp->framesize = opus_packet_get_samples_per_frame(data, 8000); + } else if ((rp->toc&0xFC) != (data[0]&0xFC)) + { + /*fprintf(stderr, "toc mismatch: 0x%x vs 0x%x\n", rp->toc, data[0]);*/ + return OPUS_INVALID_PACKET; + } + curr_nb_frames = opus_packet_get_nb_frames(data, len); + if(curr_nb_frames<1) return OPUS_INVALID_PACKET; + + /* Check the 120 ms maximum packet size */ + if ((curr_nb_frames+rp->nb_frames)*rp->framesize > 960) + { + return OPUS_INVALID_PACKET; + } + + ret=opus_packet_parse(data, len, &tmp_toc, &rp->frames[rp->nb_frames], &rp->len[rp->nb_frames], NULL); + if(ret<1)return ret; + + rp->nb_frames += curr_nb_frames; + return OPUS_OK; +} + +int opus_repacketizer_get_nb_frames(OpusRepacketizer *rp) +{ + return rp->nb_frames; +} + +opus_int32 opus_repacketizer_out_range_impl(OpusRepacketizer *rp, int begin, int end, unsigned char *data, opus_int32 maxlen, int self_delimited) +{ + int i, count; + opus_int32 tot_size; + short *len; + const unsigned char **frames; + + if (begin<0 || begin>=end || end>rp->nb_frames) + { + /*fprintf(stderr, "%d %d %d\n", begin, end, rp->nb_frames);*/ + return OPUS_BAD_ARG; + } + count = end-begin; + + len = rp->len+begin; + frames = rp->frames+begin; + if (self_delimited) + tot_size = 1 + (len[count-1]>=252); + else + tot_size = 0; + + switch (count) + { + case 1: + { + /* Code 0 */ + tot_size += len[0]+1; + if (tot_size > maxlen) + return OPUS_BUFFER_TOO_SMALL; + *data++ = rp->toc&0xFC; + } + break; + case 2: + { + if (len[1] == len[0]) + { + /* Code 1 */ + tot_size += 2*len[0]+1; + if (tot_size > maxlen) + return OPUS_BUFFER_TOO_SMALL; + *data++ = (rp->toc&0xFC) | 0x1; + } else { + /* Code 2 */ + tot_size += len[0]+len[1]+2+(len[0]>=252); + if (tot_size > maxlen) + return OPUS_BUFFER_TOO_SMALL; + *data++ = (rp->toc&0xFC) | 0x2; + data += encode_size(len[0], data); + } + } + break; + default: + { + /* Code 3 */ + int vbr; + + vbr = 0; + for (i=1;i=252) + len[i]; + tot_size += len[count-1]; + + if (tot_size > maxlen) + return OPUS_BUFFER_TOO_SMALL; + *data++ = (rp->toc&0xFC) | 0x3; + *data++ = count | 0x80; + for (i=0;i maxlen) + return OPUS_BUFFER_TOO_SMALL; + *data++ = (rp->toc&0xFC) | 0x3; + *data++ = count; + } + } + break; + } + if (self_delimited) { + int sdlen = encode_size(len[count-1], data); + data += sdlen; + } + /* Copy the actual data */ + for (i=0;inb_frames, data, maxlen, 0); +} + + diff --git a/code/opusfile-0.2/include/opusfile.h b/code/opusfile-0.2/include/opusfile.h new file mode 100644 index 00000000..bc7c7384 --- /dev/null +++ b/code/opusfile-0.2/include/opusfile.h @@ -0,0 +1,1623 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 1994-2012 * + * by the Xiph.Org Foundation and contributors http://www.xiph.org/ * + * * + ******************************************************************** + + function: stdio-based convenience library for opening/seeking/decoding + last mod: $Id: vorbisfile.h 17182 2010-04-29 03:48:32Z xiphmont $ + + ********************************************************************/ +#if !defined(_opusfile_h) +# define _opusfile_h (1) +# include + +/**\mainpage + \section Introduction + + This is the documentation for the libopusfile C API. + + The libopusfile package provides a convenient high-level API for + decoding and basic manipulation of all Ogg Opus audio streams. + libopusfile is implemented as a layer on top of Xiph.Org's + reference + libogg + and + libopus + libraries. + + libopusfile provides several sets of built-in routines for + file/stream access, and may also use custom stream I/O routines provided by + the embedded environment. + There are built-in I/O routines provided for ANSI-compliant + stdio (FILE *), memory buffers, and URLs + (including URLs, plus optionally and URLs). + + \section Organization + + The main API is divided into several sections: + - \ref stream_open_close + - \ref stream_info + - \ref stream_decoding + - \ref stream_seeking + + Several additional sections are not tied to the main API. + - \ref stream_callbacks + - \ref header_info + - \ref error_codes*/ + + +# if defined(__cplusplus) +extern "C" { +# endif + +# include +# include +# include + +/*Enable special features for gcc and gcc-compatible compilers.*/ +# if !defined(OP_GNUC_PREREQ) +# if defined(__GNUC__)&&defined(__GNUC_MINOR__) +# define OP_GNUC_PREREQ(_maj,_min) \ + ((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min)) +# else +# define OP_GNUC_PREREQ(_maj,_min) 0 +# endif +# endif + +# if OP_GNUC_PREREQ(4,0) +# pragma GCC visibility push(default) +# endif + +typedef struct OpusHead OpusHead; +typedef struct OpusTags OpusTags; +typedef struct OggOpusFile OggOpusFile; + +/*Warning attributes for libopusfile functions.*/ +# if OP_GNUC_PREREQ(3,4) +# define OP_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) +# else +# define OP_WARN_UNUSED_RESULT +# endif +# if OP_GNUC_PREREQ(3,4) +# define OP_ARG_NONNULL(_x) __attribute__((__nonnull__(_x))) +# else +# define OP_ARG_NONNULL(_x) +# endif + +/**\defgroup error_codes Error Codes*/ +/*@{*/ +/**\name List of possible error codes + Many of the functions in this library return a negative error code when a + function fails. + This list provides a brief explanation of the common errors. + See each individual function for more details on what a specific error code + means in that context.*/ +/*@{*/ + +/**A request did not succeed.*/ +#define OP_FALSE (-1) +/*Currently not used externally.*/ +#define OP_EOF (-2) +/**There was a hole in the page sequence numbers (e.g., a page was corrupt or + missing).*/ +#define OP_HOLE (-3) +/**An underlying read, seek, or tell operation failed when it should have + succeeded.*/ +#define OP_EREAD (-128) +/**A NULL pointer was passed where one was unexpected, or an + internal memory allocation failed, or an internal library error was + encountered.*/ +#define OP_EFAULT (-129) +/**The stream used a feature that is not implemented, such as an unsupported + channel family.*/ +#define OP_EIMPL (-130) +/**One or more parameters to a function were invalid.*/ +#define OP_EINVAL (-131) +/**A purported Ogg Opus stream did not begin with an Ogg page, a purported + header packet did not start with one of the required strings, "OpusHead" or + "OpusTags", or a link in a chained file was encountered that did not + contain any logical Opus streams.*/ +#define OP_ENOTFORMAT (-132) +/**A required header packet was not properly formatted, contained illegal + values, or was missing altogether.*/ +#define OP_EBADHEADER (-133) +/**The ID header contained an unrecognized version number.*/ +#define OP_EVERSION (-134) +/*Currently not used at all.*/ +#define OP_ENOTAUDIO (-135) +/**An audio packet failed to decode properly. + This is usually caused by a multistream Ogg packet where the durations of + the individual Opus packets contained in it are not all the same.*/ +#define OP_EBADPACKET (-136) +/**We failed to find data we had seen before, or the bitstream structure was + sufficiently malformed that seeking to the target destination was + impossible.*/ +#define OP_EBADLINK (-137) +/**An operation that requires seeking was requested on an unseekable stream.*/ +#define OP_ENOSEEK (-138) +/**The first or last granule position of a link failed basic validity checks.*/ +#define OP_EBADTIMESTAMP (-139) + +/*@}*/ +/*@}*/ + +/**\defgroup header_info Header Information*/ +/*@{*/ + +/**The maximum number of channels in an Ogg Opus stream.*/ +#define OPUS_CHANNEL_COUNT_MAX (255) + +/**Ogg Opus bitstream information. + This contains the basic playback parameters for a stream, and corresponds to + the initial ID header packet of an Ogg Opus stream.*/ +struct OpusHead{ + /**The Ogg Opus format version, in the range 0...255. + The top 4 bits represent a "major" version, and the bottom four bits + represent backwards-compatible "minor" revisions. + The current specification describes version 1. + This library will recognize versions up through 15 as backwards compatible + with the current specification. + An earlier draft of the specification described a version 0, but the only + difference between version 1 and version 0 is that version 0 did + not specify the semantics for handling the version field.*/ + int version; + /**The number of channels, in the range 1...255.*/ + int channel_count; + /**The number of samples that should be discarded from the beginning of the + stream.*/ + unsigned pre_skip; + /**The sampling rate of the original input. + All Opus audio is coded at 48 kHz, and should also be decoded at 48 kHz + for playback (unless the target hardware does not support this sampling + rate). + However, this field may be used to resample the audio back to the original + sampling rate, for example, when saving the output to a file.*/ + opus_uint32 input_sample_rate; + /**The gain to apply to the decoded output, in dB, as a Q8 value in the range + -32768...32767. + The decoder will automatically scale the output by + pow(10,output_gain/(20.0*256)).*/ + int output_gain; + /**The channel mapping family, in the range 0...255. + Channel mapping family 0 covers mono or stereo in a single stream. + Channel mapping family 1 covers 1 to 8 channels in one or more streams, + using the Vorbis speaker assignments. + Channel mapping family 255 covers 1 to 255 channels in one or more + streams, but without any defined speaker assignment.*/ + int mapping_family; + /**The number of Opus streams in each Ogg packet, in the range 1...255.*/ + int stream_count; + /**The number of coupled Opus streams in each Ogg packet, in the range + 0...127. + This must satisfy 0 <= coupled_count <= stream_count and + coupled_count + stream_count <= 255. + The coupled streams appear first, before all uncoupled streams, in an Ogg + Opus packet.*/ + int coupled_count; + /**The mapping from coded stream channels to output channels. + Let index=mapping[k] be the value for channel k. + If index<2*coupled_count, then it refers to the left channel + from stream (index/2) if even, and the right channel from + stream (index/2) if odd. + Otherwise, it refers to the output of the uncoupled stream + (index-coupled_count).*/ + unsigned char mapping[OPUS_CHANNEL_COUNT_MAX]; +}; + +/**The metadata from an Ogg Opus stream. + + This structure holds the in-stream metadata corresponding to the 'comment' + header packet of an Ogg Opus stream. + The comment header is meant to be used much like someone jotting a quick + note on the label of a CD. + It should be a short, to the point text note that can be more than a couple + words, but not more than a short paragraph. + + The metadata is stored as a series of (tag, value) pairs, in length-encoded + string vectors, using the same format as Vorbis (without the final "framing + bit"), Theora, and Speex, except for the packet header. + The first occurrence of the '=' character delimits the tag and value. + A particular tag may occur more than once, and order is significant. + The character set encoding for the strings is always UTF-8, but the tag + names are limited to ASCII, and treated as case-insensitive. + See the Vorbis + comment header specification for details. + + In filling in this structure, libopusfile will null-terminate the + #user_comments strings for safety. + However, the bitstream format itself treats them as 8-bit clean vectors, + possibly containing NUL characters, so the #comment_lengths array should be + treated as their authoritative length. + + This structure is binary and source-compatible with a + vorbis_comment, and pointers to it may be freely cast to + vorbis_comment pointers, and vice versa. + It is provided as a separate type to avoid introducing a compile-time + dependency on the libvorbis headers.*/ +struct OpusTags{ + /**The array of comment string vectors.*/ + char **user_comments; + /**An array of the corresponding length of each vector, in bytes.*/ + int *comment_lengths; + /**The total number of comment streams.*/ + int comments; + /**The null-terminated vendor string. + This identifies the software used to encode the stream.*/ + char *vendor; +}; + +/**\name Functions for manipulating header data + + These functions manipulate the #OpusHead and #OpusTags structures, + which describe the audio parameters and tag-value metadata, respectively. + These can be used to query the headers returned by libopusfile, or + to parse Opus headers from sources other than an Ogg Opus stream, provided + they use the same format.*/ +/*@{*/ + +/**Parses the contents of the ID header packet of an Ogg Opus stream. + \param[out] _head Returns the contents of the parsed packet. + The contents of this structure are untouched on error. + This may be NULL to merely test the header + for validity. + \param[in] _data The contents of the ID header packet. + \param _len The number of bytes of data in the ID header packet. + \return 0 on success or a negative value on error. + \retval #OP_ENOTFORMAT If the data does not start with the "OpusHead" + string. + \retval #OP_EVERSION If the version field signaled a version this library + does not know how to parse. + \retval #OP_EIMPL If the channel mapping family was 255, which general + purpose players should not attempt to play. + \retval #OP_EBADHEADER If the contents of the packet otherwise violate the + Ogg Opus specification: +
      +
    • Insufficient data,
    • +
    • Too much data for the known minor versions,
    • +
    • An unrecognized channel mapping family,
    • +
    • Zero channels or too many channels,
    • +
    • Zero coded streams,
    • +
    • Too many coupled streams, or
    • +
    • An invalid channel mapping index.
    • +
    */ +OP_WARN_UNUSED_RESULT int opus_head_parse(OpusHead *_head, + const unsigned char *_data,size_t _len) OP_ARG_NONNULL(2); + +/**Converts a granule position to a sample offset for a given Ogg Opus stream. + The sample offset is simply _gp-_head->pre_skip. + Granule position values smaller than OpusHead#pre_skip correspond to audio + that should never be played, and thus have no associated sample offset. + This function returns -1 for such values. + This function also correctly handles extremely large granule positions, + which may have wrapped around to a negative number when stored in a signed + ogg_int64_t value. + \param _head The #OpusHead information from the ID header of the stream. + \param _gp The granule position to convert. + \return The sample offset associated with the given granule position + (counting at a 48 kHz sampling rate), or the special value -1 on + error (i.e., the granule position was smaller than the pre-skip + amount).*/ +ogg_int64_t opus_granule_sample(const OpusHead *_head,ogg_int64_t _gp) + OP_ARG_NONNULL(1); + +/**Parses the contents of the 'comment' header packet of an Ogg Opus stream. + \param[out] _tags An uninitialized #OpusTags structure. + This returns the contents of the parsed packet. + The contents of this structure are untouched on error. + This may be NULL to merely test the header + for validity. + \param[in] _data The contents of the 'comment' header packet. + \param _len The number of bytes of data in the 'info' header packet. + \retval 0 Success. + \retval #OP_ENOTFORMAT If the data does not start with the "OpusTags" + string. + \retval #OP_EBADHEADER If the contents of the packet otherwise violate the + Ogg Opus specification. + \retval #OP_EFAULT If there wasn't enough memory to store the tags.*/ +OP_WARN_UNUSED_RESULT int opus_tags_parse(OpusTags *_tags, + const unsigned char *_data,size_t _len) OP_ARG_NONNULL(2); + +/**Initializes an #OpusTags structure. + This should be called on a freshly allocated #OpusTags structure before + attempting to use it. + \param _tags The #OpusTags structure to initialize.*/ +void opus_tags_init(OpusTags *_tags) OP_ARG_NONNULL(1); + +/**Add a (tag, value) pair to an initialized #OpusTags structure. + \note Neither opus_tags_add() nor opus_tags_add_comment() support values + containing embedded NULs, although the bitstream format does support them. + To add such tags, you will need to manipulate the #OpusTags structure + directly. + \param _tags The #OpusTags structure to add the (tag, value) pair to. + \param _tag A NUL-terminated, case-insensitive, ASCII string containing + the tag to add (without an '=' character). + \param _value A NUL-terminated UTF-8 containing the corresponding value. + \return 0 on success, or a negative value on failure. + \retval #OP_EFAULT An internal memory allocation failed.*/ +int opus_tags_add(OpusTags *_tags,const char *_tag,const char *_value) + OP_ARG_NONNULL(1) OP_ARG_NONNULL(2) OP_ARG_NONNULL(3); + +/**Add a comment to an initialized #OpusTags structure. + \note Neither opus_tags_add_comment() nor opus_tags_add() support comments + containing embedded NULs, although the bitstream format does support them. + To add such tags, you will need to manipulate the #OpusTags structure + directly. + \param _tags The #OpusTags structure to add the comment to. + \param _comment A NUL-terminated UTF-8 string containing the comment in + "TAG=value" form. + \return 0 on success, or a negative value on failure. + \retval #OP_EFAULT An internal memory allocation failed.*/ +int opus_tags_add_comment(OpusTags *_tags,const char *_comment) + OP_ARG_NONNULL(1) OP_ARG_NONNULL(2); + +/**Look up a comment value by its tag. + \param _tags An initialized #OpusTags structure. + \param _tag The tag to look up. + \param _count The instance of the tag. + The same tag can appear multiple times, each with a distinct + value, so an index is required to retrieve them all. + The order in which these values appear is significant and + should be preserved. + Use opus_tags_query_count() to get the legal range for the + \a _count parameter. + \return A pointer to the queried tag's value. + This points directly to data in the #OpusTags structure. + It should not be modified or freed by the application, and + modifications to the structure may invalidate the pointer. + \retval NULL If no matching tag is found.*/ +const char *opus_tags_query(const OpusTags *_tags,const char *_tag,int _count) + OP_ARG_NONNULL(1) OP_ARG_NONNULL(2); + +/**Look up the number of instances of a tag. + Call this first when querying for a specific tag and then iterate over the + number of instances with separate calls to opus_tags_query() to retrieve + all the values for that tag in order. + \param _tags An initialized #OpusTags structure. + \param _tag The tag to look up. + \return The number of instances of this particular tag.*/ +int opus_tags_query_count(const OpusTags *_tags,const char *_tag) + OP_ARG_NONNULL(1) OP_ARG_NONNULL(2); + +/**Clears the #OpusTags structure. + This should be called on an #OpusTags structure after it is no longer + needed. + It will free all memory used by the structure members. + \param _tags The #OpusTags structure to clear.*/ +void opus_tags_clear(OpusTags *_tags) OP_ARG_NONNULL(1); + +/*@}*/ + +/*@}*/ + +/**\defgroup url_options URL Reading Options*/ +/*@{*/ +/**\name URL reading options + Options for op_url_stream_create() and associated functions. + These allow you to provide proxy configuration parameters, skip SSL + certificate checks, etc. + Options are processed in order, and if the same option is passed multiple + times, only the value specified by the last occurrence has an effect + (unless otherwise specified). + They may be expanded in the future.*/ +/*@{*/ + +/*These are the raw numbers used to define the request codes. + They should not be used directly.*/ +#define OP_SSL_SKIP_CERTIFICATE_CHECK_REQUEST (6464) +#define OP_HTTP_PROXY_HOST_REQUEST (6528) +#define OP_HTTP_PROXY_PORT_REQUEST (6592) +#define OP_HTTP_PROXY_USER_REQUEST (6656) +#define OP_HTTP_PROXY_PASS_REQUEST (6720) + +#define OP_URL_OPT(_request) ((_request)+(char *)0) + +/*These macros trigger compilation errors or warnings if the wrong types are + provided to one of the URL options.*/ +#define OP_CHECK_INT(_x) ((void)((_x)==(opus_int32)0),(opus_int32)(_x)) +#define OP_CHECK_CONST_CHAR_PTR(_x) ((_x)+((_x)-(const char *)(_x))) + +/**Skip the certificate check when connecting via TLS/SSL (https). + \param _b opus_int32: Whether or not to skip the certificate + check. + The check will be skipped if \a _b is non-zero, and will not be + skipped if \a _b is zero. + \hideinitializer*/ +#define OP_SSL_SKIP_CERTIFICATE_CHECK(_b) \ + OP_URL_OPT(OP_SSL_SKIP_CERTIFICATE_CHECK_REQUEST),OP_CHECK_INT(_b) + +/**Proxy connections through the given host. + If no port is specified via #OP_HTTP_PROXY_PORT, the port number defaults + to 8080 (http-alt). + All proxy parameters are ignored for non-http and non-https URLs. + \param _host const char *: The proxy server hostname. + This may be NULL to disable the use of a proxy + server. + \hideinitializer*/ +#define OP_HTTP_PROXY_HOST(_host) \ + OP_URL_OPT(OP_HTTP_PROXY_HOST_REQUEST),OP_CHECK_CONST_CHAR_PTR(_host) + +/**Use the given port when proxying connections. + This option only has an effect if #OP_HTTP_PROXY_HOST is specified with a + non-NULL \a _host. + If this option is not provided, the proxy port number defaults to 8080 + (http-alt). + All proxy parameters are ignored for non-http and non-https URLs. + \param _port opus_int32: The proxy server port. + This must be in the range 0...65535 (inclusive), or the + URL function this is passed to will fail. + \hideinitializer*/ +#define OP_HTTP_PROXY_PORT(_port) \ + OP_URL_OPT(OP_HTTP_PROXY_PORT_REQUEST),OP_CHECK_INT(_port) + +/**Use the given user name for authentication when proxying connections. + All proxy parameters are ignored for non-http and non-https URLs. + \param _user const char *: The proxy server user name. + This may be NULL to disable proxy + authentication. + A non-NULL value only has an effect + if #OP_HTTP_PROXY_HOST and #OP_HTTP_PROXY_PASS + are also specified with non-NULL + arguments. + \hideinitializer*/ +#define OP_HTTP_PROXY_USER(_user) \ + OP_URL_OPT(OP_HTTP_PROXY_USER_REQUEST),OP_CHECK_CONST_CHAR_PTR(_host) + +/**Use the given password for authentication when proxying connections. + All proxy parameters are ignored for non-http and non-https URLs. + \param _pass const char *: The proxy server password. + This may be NULL to disable proxy + authentication. + A non-NULL value only has an effect + if #OP_HTTP_PROXY_HOST and #OP_HTTP_PROXY_USER + are also specified with non-NULL + arguments. + \hideinitializer*/ +#define OP_HTTP_PROXY_PASS(_pass) \ + OP_URL_OPT(OP_HTTP_PROXY_PASS_REQUEST),OP_CHECK_CONST_CHAR_PTR(_host) + +/*@}*/ +/*@}*/ + +/**\defgroup stream_callbacks Abstract Stream Reading Interface*/ +/*@{*/ +/**\name Functions for reading from streams + These functions define the interface used to read from and seek in a stream + of data. + A stream does not need to implement seeking, but the decoder will not be + able to seek if it does not do so. + These functions also include some convenience routines for working with + standard FILE pointers, complete streams stored in a single + block of memory, or URLs.*/ +/*@{*/ + +typedef struct OpusFileCallbacks OpusFileCallbacks; + +/**Reads up to \a _nbytes bytes of data from \a _stream. + \param _stream The stream to read from. + \param[out] _ptr The buffer to store the data in. + \param _nbytes The maximum number of bytes to read. + This function may return fewer, though it will not + return zero unless it reaches end-of-file. + \return The number of bytes successfully read, or a negative value on + error.*/ +typedef int (*op_read_func)(void *_stream,unsigned char *_ptr,int _nbytes); + +/**Sets the position indicator for \a _stream. + The new position, measured in bytes, is obtained by adding \a _offset + bytes to the position specified by \a _whence. + If \a _whence is set to SEEK_SET, SEEK_CUR, or + SEEK_END, the offset is relative to the start of the stream, + the current position indicator, or end-of-file, respectively. + \retval 0 Success. + \retval -1 Seeking is not supported or an error occurred. + errno need not be set.*/ +typedef int (*op_seek_func)(void *_stream,opus_int64 _offset,int _whence); + +/**Obtains the current value of the position indicator for \a _stream. + \return The current position indicator.*/ +typedef opus_int64 (*op_tell_func)(void *_stream); + +/**Closes the underlying stream. + \retval 0 Success. + \retval EOF An error occurred. + errno need not be set.*/ +typedef int (*op_close_func)(void *_stream); + +/**The callbacks used to access non-FILE stream resources. + The function prototypes are basically the same as for the stdio functions + fread(), fseek(), ftell(), and + fclose(). + The differences are that the FILE * arguments have been + replaced with a void *, which is to be used as a pointer to + whatever internal data these functions might need, that #seek and #tell + take and return 64-bit offsets, and that #seek must return -1 if + the stream is unseekable.*/ +struct OpusFileCallbacks{ + /**Used to read data from the stream. + This must not be NULL.*/ + op_read_func read; + /**Used to seek in the stream. + This may be NULL if seeking is not implemented.*/ + op_seek_func seek; + /**Used to return the current read position in the stream. + This may be NULL if seeking is not implemented.*/ + op_tell_func tell; + /**Used to close the stream when the decoder is freed. + This may be NULL to leave the stream open.*/ + op_close_func close; +}; + +/**Opens a stream with fopen() and fills in a set of callbacks + that can be used to access it. + This is useful to avoid writing your own portable 64-bit seeking wrappers, + and also avoids cross-module linking issues on Windows, where a + FILE * must be accessed by routines defined in the same module + that opened it. + \param[out] _cb The callbacks to use for this file. + If there is an error opening the file, nothing will be + filled in here. + \param _path The path to the file to open. + \param _mode The mode to open the file in. + \return A stream handle to use with the callbacks, or NULL on + error.*/ +OP_WARN_UNUSED_RESULT void *op_fopen(OpusFileCallbacks *_cb, + const char *_path,const char *_mode) OP_ARG_NONNULL(1) OP_ARG_NONNULL(2) + OP_ARG_NONNULL(3); + +/**Opens a stream with fdopen() and fills in a set of callbacks + that can be used to access it. + This is useful to avoid writing your own portable 64-bit seeking wrappers, + and also avoids cross-module linking issues on Windows, where a + FILE * must be accessed by routines defined in the same module + that opened it. + \param[out] _cb The callbacks to use for this file. + If there is an error opening the file, nothing will be + filled in here. + \param _fd The file descriptor to open. + \param _mode The mode to open the file in. + \return A stream handle to use with the callbacks, or NULL on + error.*/ +OP_WARN_UNUSED_RESULT void *op_fdopen(OpusFileCallbacks *_cb, + int _fd,const char *_mode) OP_ARG_NONNULL(1) OP_ARG_NONNULL(3); + +/**Opens a stream with freopen() and fills in a set of callbacks + that can be used to access it. + This is useful to avoid writing your own portable 64-bit seeking wrappers, + and also avoids cross-module linking issues on Windows, where a + FILE * must be accessed by routines defined in the same module + that opened it. + \param[out] _cb The callbacks to use for this file. + If there is an error opening the file, nothing will be + filled in here. + \param _path The path to the file to open. + \param _mode The mode to open the file in. + \param _stream A stream previously returned by op_fopen(), op_fdopen(), + or op_freopen(). + \return A stream handle to use with the callbacks, or NULL on + error.*/ +OP_WARN_UNUSED_RESULT void *op_freopen(OpusFileCallbacks *_cb, + const char *_path,const char *_mode,void *_stream) OP_ARG_NONNULL(1) + OP_ARG_NONNULL(2) OP_ARG_NONNULL(3) OP_ARG_NONNULL(4); + +/**Creates a stream that reads from the given block of memory. + This block of memory must contain the complete stream to decode. + This is useful for caching small streams (e.g., sound effects) in RAM. + \param[out] _cb The callbacks to use for this stream. + If there is an error creating the stream, nothing will be + filled in here. + \param _data The block of memory to read from. + \param _size The size of the block of memory. + \return A stream handle to use with the callbacks, or NULL on + error.*/ +OP_WARN_UNUSED_RESULT void *op_mem_stream_create(OpusFileCallbacks *_cb, + const unsigned char *_data,size_t _size) OP_ARG_NONNULL(1); + +/**Creates a stream that reads from the given URL. + This function behaves identically to op_url_stream_create(), except that it + takes a va_list instead of a variable number of arguments. + It does not call the va_end macro, and because it invokes the + va_arg macro, the value of \a _ap is undefined after the call. + \param[out] _cb The callbacks to use for this stream. + If there is an error creating the stream, nothing will + be filled in here. + \param _url The URL to read from. + Currently only the , , and + schemes are supported. + Both and may be disabled at compile + time, in which case opening such URLs will always fail. + \param[in,out] _ap A list of the \ref url_options "optional flags" to use. + This is a variable-length list of options terminated + with NULL. + \return A stream handle to use with the callbacks, or NULL on + error.*/ +OP_WARN_UNUSED_RESULT void *op_url_stream_vcreate(OpusFileCallbacks *_cb, + const char *_url,va_list _ap) OP_ARG_NONNULL(1) OP_ARG_NONNULL(2); + +/**Creates a stream that reads from the given URL using the specified proxy. + \param[out] _cb The callbacks to use for this stream. + If there is an error creating the stream, nothing will be + filled in here. + \param _url The URL to read from. + Currently only the , , and schemes + are supported. + Both and may be disabled at compile time, + in which case opening such URLs will always fail. + \param ... The \ref url_options "optional flags" to use. + This is a variable-length list of options terminated with + NULL. + \return A stream handle to use with the callbacks, or NULL on + error.*/ +OP_WARN_UNUSED_RESULT void *op_url_stream_create(OpusFileCallbacks *_cb, + const char *_url,...) OP_ARG_NONNULL(1) OP_ARG_NONNULL(2); + +/*@}*/ +/*@}*/ + +/**\defgroup stream_open_close Opening and Closing*/ +/*@{*/ +/**\name Functions for opening and closing streams + + These functions allow you to test a stream to see if it is Opus, open it, + and close it. + Several flavors are provided for each of the built-in stream types, plus a + more general version which takes a set of application-provided callbacks.*/ +/*@{*/ + +/**Test to see if this is an Opus stream. + For good results, you will need at least 57 bytes (for a pure Opus-only + stream). + Something like 512 bytes will give more reliable results for multiplexed + streams. + This function is meant to be a quick-rejection filter. + Its purpose is not to guarantee that a stream is a valid Opus stream, but to + ensure that it looks enough like Opus that it isn't going to be recognized + as some other format (except possibly an Opus stream that is also + multiplexed with other codecs, such as video). + \param[out] _head The parsed ID header contents. + You may pass NULL if you do not need + this information. + If the function fails, the contents of this structure + remain untouched. + \param _initial_data An initial buffer of data from the start of the + stream. + \param _initial_bytes The number of bytes in \a _initial_data. + \return 0 if the data appears to be Opus, or a negative value on error. + \retval #OP_FALSE There was not enough data to tell if this was an Opus + stream or not. + \retval #OP_EFAULT An internal memory allocation failed. + \retval #OP_EIMPL The stream used a feature that is not implemented, + such as an unsupported channel family. + \retval #OP_ENOTFORMAT If the data did not contain a recognizable ID + header for an Opus stream. + \retval #OP_EVERSION If the version field signaled a version this library + does not know how to parse. + \retval #OP_EBADHEADER The ID header was not properly formatted or contained + illegal values.*/ +int op_test(OpusHead *_head, + const unsigned char *_initial_data,size_t _initial_bytes); + +/**Open a stream from the given file path. + \param _path The path to the file to open. + \param[out] _error Returns 0 on success, or a failure code on error. + You may pass in NULL if you don't want the + failure code. + The failure code will be #OP_EFAULT if the file could not + be opened, or one of the other failure codes from + op_open_callbacks() otherwise. + \return A freshly opened \c OggOpusFile, or NULL on error.*/ +OP_WARN_UNUSED_RESULT OggOpusFile *op_open_file(const char *_path,int *_error) + OP_ARG_NONNULL(1); + +/**Open a stream from a memory buffer. + \param _data The memory buffer to open. + \param _size The number of bytes in the buffer. + \param[out] _error Returns 0 on success, or a failure code on error. + You may pass in NULL if you don't want the + failure code. + See op_open_callbacks() for a full list of failure codes. + \return A freshly opened \c OggOpusFile, or NULL on error.*/ +OP_WARN_UNUSED_RESULT OggOpusFile *op_open_memory(const unsigned char *_data, + size_t _size,int *_error); + +/**Open a stream from a URL. + This function behaves identically to op_open_url(), except that it + takes a va_list instead of a variable number of arguments. + It does not call the va_end macro, and because it invokes the + va_arg macro, the value of \a _ap is undefined after the call. + \param _url The URL to open. + Currently only the , , and + schemes are supported. + Both and may be disabled at compile + time, in which case opening such URLs will always + fail. + \param[out] _error Returns 0 on success, or a failure code on error. + You may pass in NULL if you don't want + the failure code. + See op_open_callbacks() for a full list of failure + codes. + \param[in,out] _ap A list of the \ref url_options "optional flags" to + use. + This is a variable-length list of options terminated + with NULL. + \return A freshly opened \c OggOpusFile, or NULL on error.*/ +OP_WARN_UNUSED_RESULT OggOpusFile *op_vopen_url(const char *_url, + int *_error,va_list _ap) OP_ARG_NONNULL(1); + +/**Open a stream from a URL. + However, this approach will not work for live streams or HTTP/1.0 servers + (which do not support Range requets). + \param _url The URL to open. + Currently only the , , and schemes + are supported. + Both and may be disabled at compile + time, in which case opening such URLs will always fail. + \param[out] _error Returns 0 on success, or a failure code on error. + You may pass in NULL if you don't want the + failure code. + See op_open_callbacks() for a full list of failure codes. + \param ... The \ref url_options "optional flags" to use. + This is a variable-length list of options terminated with + NULL. + \return A freshly opened \c OggOpusFile, or NULL on error.*/ +OP_WARN_UNUSED_RESULT OggOpusFile *op_open_url(const char *_url, + int *_error,...) OP_ARG_NONNULL(1); + +/**Open a stream using the given set of callbacks to access it. + \param _source The stream to read from (e.g., a FILE *). + \param _cb The callbacks with which to access the stream. + read() must + be implemented. + seek() and + tell() may + be NULL, or may always return -1 to + indicate a source is unseekable, but if + seek() is + implemented and succeeds on a particular source, then + tell() must + also. + close() may + be NULL, but if it is not, it will be + called when the \c OggOpusFile is destroyed by + op_free(). + It will not be called if op_open_callbacks() fails + with an error. + \param _initial_data An initial buffer of data from the start of the + stream. + Applications can read some number of bytes from the + start of the stream to help identify this as an Opus + stream, and then provide them here to allow the + stream to be opened, even if it is unseekable. + \param _initial_bytes The number of bytes in \a _initial_data. + If the stream is seekable, its current position (as + reported by + tell() + at the start of this function) must be equal to + \a _initial_bytes. + Otherwise, seeking to absolute positions will + generate inconsistent results. + \param[out] _error Returns 0 on success, or a failure code on error. + You may pass in NULL if you don't want + the failure code. + The failure code will be one of +
    +
    #OP_EREAD
    +
    An underlying read, seek, or tell operation + failed when it should have succeeded, or we failed + to find data in the stream we had seen before.
    +
    #OP_EFAULT
    +
    There was a memory allocation failure, or an + internal library error.
    +
    #OP_EIMPL
    +
    The stream used a feature that is not + implemented, such as an unsupported channel + family.
    +
    #OP_EINVAL
    +
    seek() + was implemented and succeeded on this source, but + tell() + did not, or the starting position indicator was + not equal to \a _initial_bytes.
    +
    #OP_ENOTFORMAT
    +
    The stream contained a link that did not have + any logical Opus streams in it.
    +
    #OP_EBADHEADER
    +
    A required header packet was not properly + formatted, contained illegal values, or was missing + altogether.
    +
    #OP_EVERSION
    +
    An ID header contained an unrecognized version + number.
    +
    #OP_EBADLINK
    +
    We failed to find data we had seen before after + seeking.
    +
    #OP_EBADTIMESTAMP
    +
    The first or last timestamp in a link failed + basic validity checks.
    +
    + \return A freshly opened \c OggOpusFile, or NULL on error.*/ +OP_WARN_UNUSED_RESULT OggOpusFile *op_open_callbacks(void *_source, + const OpusFileCallbacks *_cb,const unsigned char *_initial_data, + size_t _initial_bytes,int *_error) OP_ARG_NONNULL(2); + +/**Partially open a stream from the given file path. + \see op_test_callbacks + \param _path The path to the file to open. + \param[out] _error Returns 0 on success, or a failure code on error. + You may pass in NULL if you don't want the + failure code. + The failure code will be #OP_EFAULT if the file could not + be opened, or one of the other failure codes from + op_open_callbacks() otherwise. + \return A partially opened \c OggOpusFile, or NULL on error.*/ +OP_WARN_UNUSED_RESULT OggOpusFile *op_test_file(const char *_path,int *_error) + OP_ARG_NONNULL(1); + +/**Partially open a stream from a memory buffer. + \see op_test_callbacks + \param _data The memory buffer to open. + \param _size The number of bytes in the buffer. + \param[out] _error Returns 0 on success, or a failure code on error. + You may pass in NULL if you don't want the + failure code. + See op_open_callbacks() for a full list of failure codes. + \return A partially opened \c OggOpusFile, or NULL on error.*/ +OP_WARN_UNUSED_RESULT OggOpusFile *op_test_memory(const unsigned char *_data, + size_t _size,int *_error); + +/**Partially open a stream from a URL. + This function behaves identically to op_test_url(), except that it + takes a va_list instead of a variable number of arguments. + It does not call the va_end macro, and because it invokes the + va_arg macro, the value of \a _ap is undefined after the call. + \see op_test_url + \see op_test_callbacks + \param _url The URL to open. + Currently only the , , and + schemes are supported. + Both and may be disabled at compile + time, in which case opening such URLs will always + fail. + \param[out] _error Returns 0 on success, or a failure code on error. + You may pass in NULL if you don't want + the failure code. + See op_open_callbacks() for a full list of failure + codes. + \param[in,out] _ap A list of the \ref url_options "optional flags" to + use. + This is a variable-length list of options terminated + with NULL. + \return A partially opened \c OggOpusFile, or NULL on error.*/ +OP_WARN_UNUSED_RESULT OggOpusFile *op_vtest_url(const char *_url, + int *_error,va_list _ap) OP_ARG_NONNULL(1); + +/**Partially open a stream from a URL. + \see op_test_callbacks + \param _url The URL to open. + Currently only the , , and + schemes are supported. + Both and may be disabled at compile + time, in which case opening such URLs will always fail. + \param[out] _error Returns 0 on success, or a failure code on error. + You may pass in NULL if you don't want the + failure code. + See op_open_callbacks() for a full list of failure + codes. + \param ... The \ref url_options "optional flags" to use. + This is a variable-length list of options terminated + with NULL. + \return A partially opened \c OggOpusFile, or NULL on error.*/ +OP_WARN_UNUSED_RESULT OggOpusFile *op_test_url(const char *_url, + int *_error,...) OP_ARG_NONNULL(1); + +/**Partially open a stream using the given set of callbacks to access it. + This tests for Opusness and loads the headers for the first link. + It does not seek (although it tests for seekability). + You can query a partially open stream for the few pieces of basic + information returned by op_serialno(), op_channel_count(), op_head(), and + op_tags() (but only for the first link). + You may also determine if it is seekable via a call to op_seekable(). + You cannot read audio from the stream, seek, get the size or duration, + get information from links other than the first one, or even get the total + number of links until you finish opening the stream with op_test_open(). + If you do not need to do any of these things, you can dispose of it with + op_free() instead. + + This function is provided mostly to simplify porting existing code that used + libvorbisfile. + For new code, you are likely better off using op_test() instead, which + is less resource-intensive, requires less data to succeed, and imposes a + hard limit on the amount of data it examines (important for unseekable + sources, where all such data must be buffered until you are sure of the + stream type). + \param _source The stream to read from (e.g., a FILE *). + \param _cb The callbacks with which to access the stream. + read() must + be implemented. + seek() and + tell() may + be NULL, or may always return -1 to + indicate a source is unseekable, but if + seek() is + implemented and succeeds on a particular source, then + tell() must + also. + close() may + be NULL, but if it is not, it will be + called when the \c OggOpusFile is destroyed by + op_free(). + It will not be called if op_open_callbacks() fails + with an error. + \param _initial_data An initial buffer of data from the start of the + stream. + Applications can read some number of bytes from the + start of the stream to help identify this as an Opus + stream, and then provide them here to allow the + stream to be tested more thoroughly, even if it is + unseekable. + \param _initial_bytes The number of bytes in \a _initial_data. + If the stream is seekable, its current position (as + reported by + tell() + at the start of this function) must be equal to + \a _initial_bytes. + Otherwise, seeking to absolute positions will + generate inconsistent results. + \param[out] _error Returns 0 on success, or a failure code on error. + You may pass in NULL if you don't want + the failure code. + See op_open_callbacks() for a full list of failure + codes. + \return A partially opened \c OggOpusFile, or NULL on error.*/ +OP_WARN_UNUSED_RESULT OggOpusFile *op_test_callbacks(void *_source, + const OpusFileCallbacks *_cb,const unsigned char *_initial_data, + size_t _initial_bytes,int *_error) OP_ARG_NONNULL(2); + +/**Finish opening a stream partially opened with op_test_callbacks() or one of + the associated convenience functions. + If this function fails, you are still responsible for freeing the + \c OggOpusFile with op_free(). + \param _of The \c OggOpusFile to finish opening. + \return 0 on success, or a negative value on error. + \retval #OP_EREAD An underlying read, seek, or tell operation failed + when it should have succeeded. + \retval #OP_EFAULT There was a memory allocation failure, or an + internal library error. + \retval #OP_EIMPL The stream used a feature that is not implemented, + such as an unsupported channel family. + \retval #OP_EINVAL The stream was not partially opened with + op_test_callbacks() or one of the associated + convenience functions. + \retval #OP_ENOTFORMAT The stream contained a link that did not have any + logical Opus streams in it. + \retval #OP_EBADHEADER A required header packet was not properly + formatted, contained illegal values, or was + missing altogether. + \retval #OP_EVERSION An ID header contained an unrecognized version + number. + \retval #OP_EBADLINK We failed to find data we had seen before after + seeking. + \retval #OP_EBADTIMESTAMP The first or last timestamp in a link failed basic + validity checks.*/ +int op_test_open(OggOpusFile *_of) OP_ARG_NONNULL(1); + +/**Release all memory used by an \c OggOpusFile. + \param _of The \c OggOpusFile to free.*/ +void op_free(OggOpusFile *_of); + +/*@}*/ +/*@}*/ + +/**\defgroup stream_info Stream Information*/ +/*@{*/ +/**\name Functions for obtaining information about streams + + These functions allow you to get basic information about a stream, including + seekability, the number of links (for chained streams), plus the size, + duration, bitrate, header parameters, and meta information for each link + (or, where available, the stream as a whole). + Some of these (size, duration) are only available for seekable streams. + You can also query the current stream position, link, and playback time, + and instantaneous bitrate during playback. + + Some of these functions may be used successfully on the partially open + streams returned by op_test_callbacks() or one of the associated + convenience functions. + Their documention will indicate so explicitly.*/ +/*@{*/ + +/**Returns whether or not the data source being read is seekable. + This is true if +
      +
    1. The seek() and + tell() callbacks are both + non-NULL,
    2. +
    3. The seek() callback was + successfully executed at least once, and
    4. +
    5. The tell() callback was + successfully able to report the position indicator afterwards.
    6. +
    + This function may be called on partially-opened streams. + \param _of The \c OggOpusFile whose seekable status is to be returned. + \return A non-zero value if seekable, and 0 if unseekable.*/ +int op_seekable(OggOpusFile *_of) OP_ARG_NONNULL(1); + +/**Returns the number of links in this chained stream. + This function may be called on partially-opened streams, but it will always + return 1. + The actual number of links is not known until the stream is fully opened. + \param _of The \c OggOpusFile from which to retrieve the link count. + \return For fully-open seekable sources, this returns the total number of + links in the whole stream. + For partially-open or unseekable sources, this always returns 1.*/ +int op_link_count(OggOpusFile *_of) OP_ARG_NONNULL(1); + +/**Get the serial number of the given link in a (possibly-chained) Ogg Opus + stream. + This function may be called on partially-opened streams, but it will always + return the serial number of the Opus stream in the first link. + \param _of The \c OggOpusFile from which to retrieve the serial number. + \param _li The index of the link whose serial number should be retrieved. + Use a negative number to get the serial number of the current + link. + \return The serial number of the given link. + If \a _li is greater than the total number of links, this returns + the serial number of the last link. + If the source is not seekable, this always returns the serial number + of the current link.*/ +opus_uint32 op_serialno(OggOpusFile *_of,int _li) OP_ARG_NONNULL(1); + +/**Get the channel count of the given link in a (possibly-chained) Ogg Opus + stream. + This is equivalent to op_head(_of,_li)->channel_count, but + is provided for convenience. + This function may be called on partially-opened streams, but it will always + return the channel count of the Opus stream in the first link. + \param _of The \c OggOpusFile from which to retrieve the channel count. + \param _li The index of the link whose channel count should be retrieved. + Use a negative number to get the channel count of the current + link. + \return The channel count of the given link. + If \a _li is greater than the total number of links, this returns + the channel count of the last link. + If the source is not seekable, this always returns the channel count + of the current link.*/ +int op_channel_count(OggOpusFile *_of,int _li) OP_ARG_NONNULL(1); + +/**Get the total (compressed) size of the stream, or of an individual link in + a (possibly-chained) Ogg Opus stream, including all headers and Ogg muxing + overhead. + \param _of The \c OggOpusFile from which to retrieve the compressed size. + \param _li The index of the link whose compressed size should be computed. + Use a negative number to get the compressed size of the entire + stream. + \return The compressed size of the entire stream if \a _li is negative, the + compressed size of link \a _li if it is non-negative, or a negative + value on error. + The compressed size of the entire stream may be smaller than that + of the underlying source if trailing garbage was detected in the + file. + \retval #OP_EINVAL The source is not seekable (so we can't know the length), + \a _li wasn't less than the total number of links in + the stream, or the stream was only partially open.*/ +opus_int64 op_raw_total(OggOpusFile *_of,int _li) OP_ARG_NONNULL(1); + +/**Get the total PCM length (number of samples at 48 kHz) of the stream, or of + an individual link in a (possibly-chained) Ogg Opus stream. + Users looking for op_time_total() should use op_pcm_total() + instead. + Because timestamps in Opus are fixed at 48 kHz, there is no need for a + separate function to convert this to seconds (and leaving it out avoids + introducing floating point to the API, for those that wish to avoid it). + \param _of The \c OggOpusFile from which to retrieve the PCM offset. + \param _li The index of the link whose PCM length should be computed. + Use a negative number to get the PCM length of the entire stream. + \return The PCM length of the entire stream if \a _li is negative, the PCM + length of link \a _li if it is non-negative, or a negative value on + error. + \retval #OP_EINVAL The source is not seekable (so we can't know the length), + \a _li wasn't less than the total number of links in + the stream, or the stream was only partially open.*/ +ogg_int64_t op_pcm_total(OggOpusFile *_of,int _li) OP_ARG_NONNULL(1); + +/**Get the ID header information for the given link in a (possibly chained) Ogg + Opus stream. + This function may be called on partially-opened streams, but it will always + return the ID header information of the Opus stream in the first link. + \param _of The \c OggOpusFile from which to retrieve the ID header + information. + \param _li The index of the link whose ID header information should be + retrieved. + Use a negative number to get the ID header information of the + current link. + For an unseekable stream, \a _li is ignored, and the ID header + information for the current link is always returned, if + available. + \return The contents of the ID header for the given link.*/ +const OpusHead *op_head(OggOpusFile *_of,int _li) OP_ARG_NONNULL(1); + +/**Get the comment header information for the given link in a (possibly + chained) Ogg Opus stream. + This function may be called on partially-opened streams, but it will always + return the tags from the Opus stream in the first link. + \param _of The \c OggOpusFile from which to retrieve the comment header + information. + \param _li The index of the link whose comment header information should be + retrieved. + Use a negative number to get the comment header information of + the current link. + For an unseekable stream, \a _li is ignored, and the comment + header information for the current link is always returned, if + available. + \return The contents of the comment header for the given link, or + NULL if this is an unseekable stream that encountered + an invalid link.*/ +const OpusTags *op_tags(OggOpusFile *_of,int _li) OP_ARG_NONNULL(1); + +/**Retrieve the index of the current link. + This is the link that produced the data most recently read by + op_read_float() or its associated functions, or, after a seek, the link + that the seek target landed in. + Reading more data may advance the link index (even on the first read after a + seek). + \param _of The \c OggOpusFile from which to retrieve the current link index. + \return The index of the current link on success, or a negative value on + failure. + For seekable streams, this is a number between 0 and the value + returned by op_link_count(). + For unseekable streams, this value starts at 0 and increments by one + each time a new link is encountered (even though op_link_count() + always returns 1). + \retval #OP_EINVAL The stream was only partially open.*/ +int op_current_link(OggOpusFile *_of) OP_ARG_NONNULL(1); + +/**Computes the bitrate for a given link in a (possibly chained) Ogg Opus + stream. + The stream must be seekable to compute the bitrate. + For unseekable streams, use op_bitrate_instant() to get periodic estimates. + \param _of The \c OggOpusFile from which to retrieve the bitrate. + \param _li The index of the link whose bitrate should be computed. + USe a negative number to get the bitrate of the whole stream. + \return The bitrate on success, or a negative value on error. + \retval #OP_EINVAL The stream was only partially open, the stream was not + seekable, or \a _li was larger than the number of + links.*/ +opus_int32 op_bitrate(OggOpusFile *_of,int _li) OP_ARG_NONNULL(1); + +/**Compute the instantaneous bitrate, measured as the ratio of bits to playable + samples decoded since a) the last call to op_bitrate_instant(), b) the last + seek, or c) the start of playback, whichever was most recent. + This will spike somewhat after a seek or at the start/end of a chain + boundary, as pre-skip, pre-roll, and end-trimming causes samples to be + decoded but not played. + \param _of The \c OggOpusFile from which to retrieve the bitrate. + \return The bitrate, in bits per second, or a negative value on error. + \retval #OP_FALSE No data has been decoded since any of the events + described above. + \retval #OP_EINVAL The stream was only partially open.*/ +opus_int32 op_bitrate_instant(OggOpusFile *_of) OP_ARG_NONNULL(1); + +/**Obtain the current value of the position indicator for \a _of. + \param _of The \c OggOpusFile from which to retrieve the position indicator. + \return The byte position that is currently being read from. + \retval #OP_EINVAL The stream was only partially open.*/ +opus_int64 op_raw_tell(OggOpusFile *_of) OP_ARG_NONNULL(1); + +/**Obtain the PCM offset of the next sample to be read. + If the stream is not properly timestamped, this might not increment by the + proper amount between reads, or even return monotonically increasing + values. + \param _of The \c OggOpusFile from which to retrieve the PCM offset. + \return The PCM offset of the next sample to be read. + \retval #OP_EINVAL The stream was only partially open.*/ +ogg_int64_t op_pcm_tell(OggOpusFile *_of) OP_ARG_NONNULL(1); + +/*@}*/ +/*@}*/ + +/**\defgroup stream_seeking Seeking*/ +/*@{*/ +/**\name Functions for seeking in Opus streams + + These functions let you seek in Opus streams, if the underlying source + support it. + Seeking is implemented for all built-in stream I/O routines, though some + individual sources may not be seekable (pipes, live HTTP streams, or HTTP + streams from a server that does not support Range requests). + + op_raw_seek() is the fastest: it is guaranteed to perform at most one + physical seek, but, since the target is a byte position, makes no guarantee + how close to a given time it will come. + op_pcm_seek() provides sample-accurate seeking. + The number of physical seeks it requires is still quite small (often 1 or + 2, even in highly variable bitrate streams). + + Seeking in Opus requires decoding some pre-roll amount before playback to + allow the internal state to converge (as if recovering from packet loss). + This is handled internally by libopusfile, but means there is + little extra overhead for decoding up to the exact position requested + (since it must decode some amount of audio anyway). + It also means that decoding after seeking may not return exactly the same + values as would be obtained by decoding the stream straight through. + However, such differences are expected to be smaller than the loss + introduced by Opus's lossy compression.*/ +/*@{*/ + +/**Seek to a byte offset relative to the compressed data. + This also scans packets to update the PCM cursor. + It will cross a logical bitstream boundary, but only if it can't get any + packets out of the tail of the link to which it seeks. + \param _of The \c OggOpusFile in which to seek. + \param _byte_offset The byte position to seek to. + \return 0 on success, or a negative error code on failure. + \retval #OP_EREAD The underlying seek operation failed. + \retval #OP_EINVAL The stream was only partially open, or the target was + outside the valid range for the stream. + \retval #OP_ENOSEEK This stream is not seekable. + \retval #OP_EBADLINK Failed to initialize a decoder for a stream for an + unknown reason.*/ +int op_raw_seek(OggOpusFile *_of,opus_int64 _byte_offset) OP_ARG_NONNULL(1); + +/**Seek to the specified PCM offset, such that decoding will begin at exactly + the requested position. + \param _of The \c OggOpusFile in which to seek. + \param _pcm_offset The PCM offset to seek to. + This is in samples at 48 kHz relative to the start of the + stream. + \return 0 on success, or a negative value on error. + \retval #OP_EREAD An underlying read or seek operation failed. + \retval #OP_EINVAL The stream was only partially open, or the target was + outside the valid range for the stream. + \retval #OP_ENOSEEK This stream is not seekable. + \retval #OP_EBADLINK We failed to find data we had seen before, or the + bitstream structure was sufficiently malformed that + seeking to the target destination was impossible.*/ +int op_pcm_seek(OggOpusFile *_of,ogg_int64_t _pcm_offset) OP_ARG_NONNULL(1); + +/*@}*/ +/*@}*/ + +/**\defgroup stream_decoding Decoding*/ +/*@{*/ +/**\name Functions for decoding audio data + + These functions retrieve actual decoded audio data from the stream. + The general functions, op_read() and op_read_float() return 16-bit or + floating-point output, both using native endian ordering. + The number of channels returned can change from link to link in a chained + stream. + There are special functions, op_read_stereo() and op_read_float_stereo(), + which always output two channels, to simplify applications which do not + wish to handle multichannel audio. + These downmix multichannel files to two channels, so they can always return + samples in the same format for every link in a chained file. + + If the rest of your audio processing chain can handle floating point, those + routines should be preferred, as floating point output avoids introducing + clipping and other issues which might be avoided entirely if, e.g., you + scale down the volume at some other stage. + However, if you intend to direct consume 16-bit samples, the conversion in + libopusfile provides noise-shaping dithering API. + + libopusfile can also be configured at compile time to use the + fixed-point libopus API. + If so, the floating-point API may also be disabled. + In that configuration, nothing in libopusfile will use any + floating-point operations, to simplify support on devices without an + adequate FPU. + + \warning HTTPS streams may be be vulnerable to truncation attacks if you do + not check the error return code from op_read_float() or its associated + functions. + If the remote peer does not close the connection gracefully (with a TLS + "close notify" message), these functions will return OP_EREAD instead of 0 + when they reach the end of the file. + If you are reading from an URL (particularly if seeking is not + supported), you should make sure to check for this error and warn the user + appropriately.*/ +/*@{*/ + +/**Reads more samples from the stream. + \note Although \a _buf_size must indicate the total number of values that + can be stored in \a _pcm, the return value is the number of samples + per channel. + This is done because +
      +
    1. The channel count cannot be known a prior (reading more samples might + advance us into the next link, with a different channel count), so + \a _buf_size cannot also be in units of samples per channel,
    2. +
    3. Returning the samples per channel matches the libopus API + as closely as we're able,
    4. +
    5. Returning the total number of values instead of samples per channel + would mean the caller would need a division to compute the samples per + channel, and might worry about the possibility of getting back samples + for some channels and not others, and
    6. +
    7. This approach is relatively fool-proof: if an application passes too + small a value to \a _buf_size, they will simply get fewer samples back, + and if they assume the return value is the total number of values, then + they will simply read too few (rather than reading too many and going + off the end of the buffer).
    8. +
    + \param _of The \c OggOpusFile from which to read. + \param[out] _pcm A buffer in which to store the output PCM samples, as + signed native-endian 16-bit values with a nominal + range of [-32768,32767). + Multiple channels are interleaved using the + Vorbis + channel ordering. + This must have room for at least \a _buf_size values. + \param _buf_size The number of values that can be stored in \a _pcm. + It is reccommended that this be large enough for at + least 120 ms of data at 48 kHz per channel (5760 + values per channel). + Smaller buffers will simply return less data, possibly + consuming more memory to buffer the data internally. + libopusfile may return less data than + requested. + If so, there is no guarantee that the remaining data + in \a _pcm will be unmodified. + \param[out] _li The index of the link this data was decoded from. + You may pass NULL if you do not need this + information. + If this function fails (returning a negative value), + this parameter is left unset. + \return The number of samples read per channel on success, or a negative + value on failure. + The channel count can be retrieved on success by calling + op_head(_of,*_li). + The number of samples returned may be 0 if the buffer was too small + to store even a single sample for all channels, or if end-of-file + was reached. + The list of possible failure codes follows. + Most of them can only be returned by unseekable, chained streams + that encounter a new link. + \retval #OP_HOLE There was a hole in the data, and some samples + may have been skipped. + Call this function again to continue decoding + past the hole. + \retval #OP_EREAD An underlying read operation failed. + This may signal a truncation attack from an + source. + \retval #OP_EFAULT An internal memory allocation failed. + \retval #OP_EIMPL An unseekable stream encountered a new link that + used a feature that is not implemented, such as + an unsupported channel family. + \retval #OP_EINVAL The stream was only partially open. + \retval #OP_ENOTFORMAT An unseekable stream encountered a new link that + did not have any logical Opus streams in it. + \retval #OP_EBADHEADER An unseekable stream encountered a new link with a + required header packet that was not properly + formatted, contained illegal values, or was + missing altogether. + \retval #OP_EVERSION An unseekable stream encountered a new link with + an ID header that contained an unrecognized + version number. + \retval #OP_EBADPACKET Failed to properly decode the next packet. + \retval #OP_EBADLINK We failed to find data we had seen before. + \retval #OP_EBADTIMESTAMP An unseekable stream encountered a new link with + a starting timestamp that failed basic validity + checks.*/ +OP_WARN_UNUSED_RESULT int op_read(OggOpusFile *_of, + opus_int16 *_pcm,int _buf_size,int *_li) OP_ARG_NONNULL(1); + +/**Reads more samples from the stream. + \note Although \a _buf_size must indicate the total number of values that + can be stored in \a _pcm, the return value is the number of samples + per channel. +
      +
    1. The channel count cannot be known a prior (reading more samples might + advance us into the next link, with a different channel count), so + \a _buf_size cannot also be in units of samples per channel,
    2. +
    3. Returning the samples per channel matches the libopus API + as closely as we're able,
    4. +
    5. Returning the total number of values instead of samples per channel + would mean the caller would need a division to compute the samples per + channel, and might worry about the possibility of getting back samples + for some channels and not others, and
    6. +
    7. This approach is relatively fool-proof: if an application passes too + small a value to \a _buf_size, they will simply get fewer samples back, + and if they assume the return value is the total number of values, then + they will simply read too few (rather than reading too many and going + off the end of the buffer).
    8. +
    + \param _of The \c OggOpusFile from which to read. + \param[out] _pcm A buffer in which to store the output PCM samples as + signed floats with a nominal range of + [-1.0,1.0]. + Multiple channels are interleaved using the + Vorbis + channel ordering. + This must have room for at least \a _buf_size floats. + \param _buf_size The number of floats that can be stored in \a _pcm. + It is reccommended that this be large enough for at + least 120 ms of data at 48 kHz per channel (5760 + samples per channel). + Smaller buffers will simply return less data, possibly + consuming more memory to buffer the data internally. + If less than \a _buf_size values are returned, + libopusfile makes no guarantee that the + remaining data in \a _pcm will be unmodified. + \param[out] _li The index of the link this data was decoded from. + You may pass NULL if you do not need this + information. + If this function fails (returning a negative value), + this parameter is left unset. + \return The number of samples read per channel on success, or a negative + value on failure. + The channel count can be retrieved on success by calling + op_head(_of,*_li). + The number of samples returned may be 0 if the buffer was too small + to store even a single sample for all channels, or if end-of-file + was reached. + The list of possible failure codes follows. + Most of them can only be returned by unseekable, chained streams + that encounter a new link. + \retval #OP_HOLE There was a hole in the data, and some samples + may have been skipped. + Call this function again to continue decoding + past the hole. + \retval #OP_EREAD An underlying read operation failed. + This may signal a truncation attack from an + source. + \retval #OP_EFAULT An internal memory allocation failed. + \retval #OP_EIMPL An unseekable stream encountered a new link that + used a feature that is not implemented, such as + an unsupported channel family. + \retval #OP_EINVAL The stream was only partially open. + \retval #OP_ENOTFORMAT An unseekable stream encountered a new link that + did not have any logical Opus streams in it. + \retval #OP_EBADHEADER An unseekable stream encountered a new link with a + required header packet that was not properly + formatted, contained illegal values, or was + missing altogether. + \retval #OP_EVERSION An unseekable stream encountered a new link with + an ID header that contained an unrecognized + version number. + \retval #OP_EBADPACKET Failed to properly decode the next packet. + \retval #OP_EBADLINK We failed to find data we had seen before. + \retval #OP_EBADTIMESTAMP An unseekable stream encountered a new link with + a starting timestamp that failed basic validity + checks.*/ +OP_WARN_UNUSED_RESULT int op_read_float(OggOpusFile *_of, + float *_pcm,int _buf_size,int *_li) OP_ARG_NONNULL(1); + +/**Reads more samples from the stream and downmixes to stereo, if necessary. + This function is intended for simple players that want a uniform output + format, even if the channel count changes between links in a chained + stream. + \note \a _buf_size indicates the total number of values that can be stored + in \a _pcm, while the return value is the number of samples per + channel, even though the channel count is known, for consistency with + op_read(). + \param _of The \c OggOpusFile from which to read. + \param[out] _pcm A buffer in which to store the output PCM samples, as + signed native-endian 16-bit values with a nominal + range of [-32768,32767). + The left and right channels are interleaved in the + buffer. + This must have room for at least \a _buf_size values. + \param _buf_size The number of values that can be stored in \a _pcm. + It is reccommended that this be large enough for at + least 120 ms of data at 48 kHz per channel (11520 + values total). + Smaller buffers will simply return less data, possibly + consuming more memory to buffer the data internally. + If less than \a _buf_size values are returned, + libopusfile makes no guarantee that the + remaining data in \a _pcm will be unmodified. + \return The number of samples read per channel on success, or a negative + value on failure. + The number of samples returned may be 0 if the buffer was too small + to store even a single sample for both channels, or if end-of-file + was reached. + The list of possible failure codes follows. + Most of them can only be returned by unseekable, chained streams + that encounter a new link. + \retval #OP_HOLE There was a hole in the data, and some samples + may have been skipped. + Call this function again to continue decoding + past the hole. + \retval #OP_EREAD An underlying read operation failed. + This may signal a truncation attack from an + source. + \retval #OP_EFAULT An internal memory allocation failed. + \retval #OP_EIMPL An unseekable stream encountered a new link that + used a feature that is not implemented, such as + an unsupported channel family. + \retval #OP_EINVAL The stream was only partially open. + \retval #OP_ENOTFORMAT An unseekable stream encountered a new link that + did not have any logical Opus streams in it. + \retval #OP_EBADHEADER An unseekable stream encountered a new link with a + required header packet that was not properly + formatted, contained illegal values, or was + missing altogether. + \retval #OP_EVERSION An unseekable stream encountered a new link with + an ID header that contained an unrecognized + version number. + \retval #OP_EBADPACKET Failed to properly decode the next packet. + \retval #OP_EBADLINK We failed to find data we had seen before. + \retval #OP_EBADTIMESTAMP An unseekable stream encountered a new link with + a starting timestamp that failed basic validity + checks.*/ +OP_WARN_UNUSED_RESULT int op_read_stereo(OggOpusFile *_of, + opus_int16 *_pcm,int _buf_size) OP_ARG_NONNULL(1); + +/**Reads more samples from the stream and downmixes to stereo, if necessary. + This function is intended for simple players that want a uniform output + format, even if the channel count changes between links in a chained + stream. + \note \a _buf_size indicates the total number of values that can be stored + in \a _pcm, while the return value is the number of samples per + channel, even though the channel count is known, for consistency with + op_read_float(). + \param _of The \c OggOpusFile from which to read. + \param[out] _pcm A buffer in which to store the output PCM samples, as + signed floats with a nominal range of + [-1.0,1.0]. + The left and right channels are interleaved in the + buffer. + This must have room for at least \a _buf_size values. + \param _buf_size The number of values that can be stored in \a _pcm. + It is reccommended that this be large enough for at + least 120 ms of data at 48 kHz per channel (11520 + values total). + Smaller buffers will simply return less data, possibly + consuming more memory to buffer the data internally. + If less than \a _buf_size values are returned, + libopusfile makes no guarantee that the + remaining data in \a _pcm will be unmodified. + \return The number of samples read per channel on success, or a negative + value on failure. + The number of samples returned may be 0 if the buffer was too small + to store even a single sample for both channels, or if end-of-file + was reached. + The list of possible failure codes follows. + Most of them can only be returned by unseekable, chained streams + that encounter a new link. + \retval #OP_HOLE There was a hole in the data, and some samples + may have been skipped. + Call this function again to continue decoding + past the hole. + \retval #OP_EREAD An underlying read operation failed. + This may signal a truncation attack from an + source. + \retval #OP_EFAULT An internal memory allocation failed. + \retval #OP_EIMPL An unseekable stream encountered a new link that + used a feature that is not implemented, such as + an unsupported channel family. + \retval #OP_EINVAL The stream was only partially open. + \retval #OP_ENOTFORMAT An unseekable stream encountered a new link that + that did not have any logical Opus streams in it. + \retval #OP_EBADHEADER An unseekable stream encountered a new link with a + required header packet that was not properly + formatted, contained illegal values, or was + missing altogether. + \retval #OP_EVERSION An unseekable stream encountered a new link with + an ID header that contained an unrecognized + version number. + \retval #OP_EBADPACKET Failed to properly decode the next packet. + \retval #OP_EBADLINK We failed to find data we had seen before. + \retval #OP_EBADTIMESTAMP An unseekable stream encountered a new link with + a starting timestamp that failed basic validity + checks.*/ +OP_WARN_UNUSED_RESULT int op_read_float_stereo(OggOpusFile *_of, + float *_pcm,int _buf_size) OP_ARG_NONNULL(1); + +/*@}*/ +/*@}*/ + +# if OP_GNUC_PREREQ(4,0) +# pragma GCC visibility pop +# endif + +# if defined(__cplusplus) +} +# endif + +#endif diff --git a/code/opusfile-0.2/src/http.c b/code/opusfile-0.2/src/http.c new file mode 100644 index 00000000..09580c6f --- /dev/null +++ b/code/opusfile-0.2/src/http.c @@ -0,0 +1,3075 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 2012 * + * by the Xiph.Org Foundation and contributors http://www.xiph.org/ * + * * + ********************************************************************/ +#include "internal.h" +#include +#include +#include +#include + +/*RFCs referenced in this file: + RFC 761: DOD Standard Transmission Control Protocol + RFC 1535: A Security Problem and Proposed Correction With Widely Deployed DNS + Software + RFC 1738: Uniform Resource Locators (URL) + RFC 1945: Hypertext Transfer Protocol -- HTTP/1.0 + RFC 2068: Hypertext Transfer Protocol -- HTTP/1.1 + RFC 2145: Use and Interpretation of HTTP Version Numbers + RFC 2246: The TLS Protocol Version 1.0 + RFC 2459: Internet X.509 Public Key Infrastructure Certificate and + Certificate Revocation List (CRL) Profile + RFC 2616: Hypertext Transfer Protocol -- HTTP/1.1 + RFC 2617: HTTP Authentication: Basic and Digest Access Authentication + RFC 2817: Upgrading to TLS Within HTTP/1.1 + RFC 2818: HTTP Over TLS + RFC 3492: Punycode: A Bootstring encoding of Unicode for Internationalized + Domain Names in Applications (IDNA) + RFC 3986: Uniform Resource Identifier (URI): Generic Syntax + RFC 3987: Internationalized Resource Identifiers (IRIs) + RFC 4343: Domain Name System (DNS) Case Insensitivity Clarification + RFC 5894: Internationalized Domain Names for Applications (IDNA): + Background, Explanation, and Rationale + RFC 6066: Transport Layer Security (TLS) Extensions: Extension Definitions + RFC 6125: Representation and Verification of Domain-Based Application Service + Identity within Internet Public Key Infrastructure Using X.509 (PKIX) + Certificates in the Context of Transport Layer Security (TLS)*/ + +typedef struct OpusParsedURL OpusParsedURL; +typedef struct OpusStringBuf OpusStringBuf; +typedef struct OpusHTTPConn OpusHTTPConn; +typedef struct OpusHTTPStream OpusHTTPStream; + +static char *op_string_range_dup(const char *_start,const char *_end){ + size_t len; + char *ret; + OP_ASSERT(_start<=_end); + len=_end-_start; + /*This is to help avoid overflow elsewhere, later.*/ + if(OP_UNLIKELY(len>=INT_MAX))return NULL; + ret=(char *)_ogg_malloc(sizeof(*ret)*(len+1)); + if(OP_LIKELY(ret!=NULL)){ + memcpy(ret,_start,sizeof(*ret)*(len)); + ret[len]='\0'; + } + return ret; +} + +static char *op_string_dup(const char *_s){ + return op_string_range_dup(_s,_s+strlen(_s)); +} + +static char *op_string_tolower(char *_s){ + int i; + for(i=0;_s[i]!='\0';i++){ + int c; + c=_s[i]; + if(c>='A'&&c<='Z')c+='a'-'A'; + _s[i]=(char)c; + } + return _s; +} + +/*URI character classes (from RFC 3986).*/ +#define OP_URL_ALPHA \ + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" +#define OP_URL_DIGIT "0123456789" +#define OP_URL_HEXDIGIT "0123456789ABCDEFabcdef" +/*Not a character class, but the characters allowed in .*/ +#define OP_URL_SCHEME OP_URL_ALPHA OP_URL_DIGIT "+-." +#define OP_URL_GEN_DELIMS "#/:?@[]" +#define OP_URL_SUB_DELIMS "!$&'()*+,;=" +#define OP_URL_RESERVED OP_URL_GEN_DELIMS OP_URL_SUB_DELIMS +#define OP_URL_UNRESERVED OP_URL_ALPHA OP_URL_DIGIT "-._~" +/*Not a character class, but the characters allowed in .*/ +#define OP_URL_PCT_ENCODED "%" +/*Not a character class or production rule, but for convenience.*/ +#define OP_URL_PCHAR_BASE \ + OP_URL_UNRESERVED OP_URL_PCT_ENCODED OP_URL_SUB_DELIMS +#define OP_URL_PCHAR OP_URL_PCHAR_BASE ":@" +/*Not a character class, but the characters allowed in and + .*/ +#define OP_URL_PCHAR_NA OP_URL_PCHAR_BASE ":" +/*Not a character class, but the characters allowed in .*/ +#define OP_URL_PCHAR_NC OP_URL_PCHAR_BASE "@" +/*Not a character clsss, but the characters allowed in .*/ +#define OP_URL_PATH OP_URL_PCHAR "/" +/*Not a character class, but the characters allowed in / .*/ +#define OP_URL_QUERY_FRAG OP_URL_PCHAR "/?" + +/*Check the <% HEXDIG HEXDIG> escapes of a URL for validity. + Return: 0 if valid, or a negative value on failure.*/ +static int op_validate_url_escapes(const char *_s){ + int i; + for(i=0;_s[i];i++){ + if(_s[i]=='%'){ + if(OP_UNLIKELY(!isxdigit(_s[i+1])) + ||OP_UNLIKELY(!isxdigit(_s[i+2])) + /*RFC 3986 says %00 "should be rejected if the application is not + expecting to receive raw data within a component."*/ + ||OP_UNLIKELY(_s[i+1]=='0'&&_s[i+2]=='0')){ + return OP_FALSE; + } + i+=2; + } + } + return 0; +} + +/*Convert a hex digit to its actual value. + _c: The hex digit to convert. + Presumed to be valid ('0'...'9', 'A'...'F', or 'a'...'f'). + Return: The value of the digit, in the range [0,15].*/ +static int op_hex_value(int _c){ + return _c>='a'?_c-'a'+10:_c>='A'?_c-'A'+10:_c-'0'; +} + +/*Unescape all the <% HEXDIG HEXDIG> sequences in a string in-place. + This does no validity checking.*/ +static char *op_unescape_url_component(char *_s){ + int i; + int j; + for(i=j=0;_s[i];i++,j++){ + if(_s[i]=='%'){ + _s[i]=(char)(op_hex_value(_s[i+1])<<4|op_hex_value(_s[i+2])); + i+=2; + } + } + return _s; +} + +/*Parse a file: URL. + This code is not meant to be fast: strspn() with large sets is likely to be + slow, but it is very convenient. + It is meant to be RFC 1738-compliant (as updated by RFC 3986).*/ +static const char *op_parse_file_url(const char *_src){ + const char *scheme_end; + const char *path; + const char *path_end; + scheme_end=_src+strspn(_src,OP_URL_SCHEME); + if(OP_UNLIKELY(*scheme_end!=':') + ||scheme_end-_src!=4||op_strncasecmp(_src,"file",4)!=0){ + /*Unsupported protocol.*/ + return NULL; + } + /*Make sure all escape sequences are valid to simplify unescaping later.*/ + if(OP_UNLIKELY(op_validate_url_escapes(scheme_end+1)<0))return NULL; + if(scheme_end[1]=='/'&&scheme_end[2]=='/'){ + const char *host; + /*file: URLs can have a host! + Yeah, I was surprised, too, but that's what RFC 1738 says. + It also says, "The file URL scheme is unusual in that it does not specify + an Internet protocol or access method for such files; as such, its + utility in network protocols between hosts is limited," which is a mild + understatement.*/ + host=scheme_end+3; + /*The empty host is what we expect.*/ + if(OP_LIKELY(*host=='/'))path=host; + else{ + const char *host_end; + char host_buf[28]; + /*RFC 1738 says localhost "is interpreted as `the machine from which the + URL is being interpreted,'" so let's check for it.*/ + host_end=host+strspn(host,OP_URL_PCHAR_BASE); + /*No allowed. + This also rejects IP-Literals.*/ + if(*host_end!='/')return NULL; + /*An escaped "localhost" can take at most 27 characters.*/ + if(OP_UNLIKELY(host_end-host>27))return NULL; + memcpy(host_buf,host,sizeof(*host_buf)*(host_end-host)); + host_buf[host_end-host]='\0'; + op_unescape_url_component(host_buf); + op_string_tolower(host_buf); + /*Some other host: give up.*/ + if(OP_UNLIKELY(strcmp(host_buf,"localhost")!=0))return NULL; + path=host_end; + } + } + else path=scheme_end+1; + path_end=path+strspn(path,OP_URL_PATH); + /*This will reject a or component, too. + I don't know what to do with queries, but a temporal fragment would at + least make sense. + RFC 1738 pretty clearly defines a that's equivalent to the + RFC 3986 component for other schemes, but not the file: scheme, + so I'm going to just reject it.*/ + if(*path_end!='\0')return NULL; + return path; +} + +#if defined(OP_ENABLE_HTTP) +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include + +/*The maximum number of simultaneous connections. + RFC 2616 says this SHOULD NOT be more than 2, but everyone on the modern web + ignores that (e.g., IE 8 bumped theirs up from 2 to 6, Firefox uses 15). + If it makes you feel better, we'll only ever actively read from one of these + at a time. + The others are kept around mainly to avoid slow-starting a new connection + when seeking, and time out rapidly.*/ +# define OP_NCONNS_MAX (4) + +/*The number of redirections at which we give up. + The value here is the current default in Firefox. + RFC 2068 mandated a maximum of 5, but RFC 2616 relaxed that to "a client + SHOULD detect infinite redirection loops." + Fortunately, 20 is less than infinity.*/ +# define OP_REDIRECT_LIMIT (20) + +/*The initial size of the buffer used to read a response message (before the + body).*/ +# define OP_RESPONSE_SIZE_MIN (510) +/*The maximum size of a response message (before the body). + Responses larger than this will be discarded. + I've seen a real server return 20 kB of data for a 302 Found response. + Increasing this beyond 32kB will cause problems on platforms with a 16-bit + int.*/ +# define OP_RESPONSE_SIZE_MAX (32766) + +/*The number of milliseconds we will allow a connection to sit idle before we + refuse to resurrect it. + Apache as of 2.2 has reduced its default timeout to 5 seconds (from 15), so + that's what we'll use here.*/ +# define OP_CONNECTION_IDLE_TIMEOUT_MS (5*1000) + +/*The number of milliseconds we will wait to send or receive data before giving + up.*/ +# define OP_POLL_TIMEOUT_MS (30*1000) + +/*We will always attempt to read ahead at least this much in preference to + opening a new connection.*/ +# define OP_READAHEAD_THRESH_MIN (32*(opus_int32)1024) + +/*The amount of data to request after a seek. + This is a trade-off between read throughput after a seek vs. the the ability + to quickly perform another seek with the same connection.*/ +# define OP_PIPELINE_CHUNK_SIZE (32*(opus_int32)1024) +/*Subsequent chunks are requested with larger and larger sizes until they pass + this threshold, after which we just ask for the rest of the resource.*/ +# define OP_PIPELINE_CHUNK_SIZE_MAX (1024*(opus_int32)1024) +/*This is the maximum number of requests we'll make with a single connection. + Many servers will simply disconnect after we attempt some number of requests, + possibly without sending a Connection: close header, meaning we won't + discover it until we try to read beyond the end of the current chunk. + We can reconnect when that happens, but this is slow. + Instead, we impose a limit ourselves (set to the default for Apache + installations and thus likely the most common value in use).*/ +# define OP_PIPELINE_MAX_REQUESTS (100) +/*This should be the number of requests, starting from a chunk size of + OP_PIPELINE_CHUNK_SIZE and doubling each time, until we exceed + OP_PIPELINE_CHUNK_SIZE_MAX and just request the rest of the file. + We won't reuse a connection when seeking unless it has at least this many + requests left, to reduce the chances we'll have to open a new connection + while reading forward afterwards.*/ +# define OP_PIPELINE_MIN_REQUESTS (7) + +/*Is this an https URL? + For now we can simply check the last letter of the scheme.*/ +# define OP_URL_IS_SSL(_url) ((_url)->scheme[4]=='s') + +/*Does this URL use the default port for its scheme?*/ +# define OP_URL_IS_DEFAULT_PORT(_url) \ + (!OP_URL_IS_SSL(_url)&&(_url)->port==80 \ + ||OP_URL_IS_SSL(_url)&&(_url)->port==443) + +struct OpusParsedURL{ + /*Either "http" or "https".*/ + char *scheme; + /*The user name from the component, or NULL.*/ + char *user; + /*The password from the component, or NULL.*/ + char *pass; + /*The component. + This may not be NULL.*/ + char *host; + /*The and components. + This may not be NULL.*/ + char *path; + /*The component. + This is set to the default port if the URL did not contain one.*/ + unsigned port; +}; + +/*Parse a URL. + This code is not meant to be fast: strspn() with large sets is likely to be + slow, but it is very convenient. + It is meant to be RFC 3986-compliant. + We currently do not support IRIs (Internationalized Resource Identifiers, + RFC 3987). + Callers should translate them to URIs first.*/ +static int op_parse_url_impl(OpusParsedURL *_dst,const char *_src){ + const char *scheme_end; + const char *authority; + const char *userinfo_end; + const char *user; + const char *user_end; + const char *pass; + const char *hostport; + const char *hostport_end; + const char *host_end; + const char *port; + opus_int32 port_num; + const char *port_end; + const char *path; + const char *path_end; + const char *uri_end; + scheme_end=_src+strspn(_src,OP_URL_SCHEME); + if(OP_UNLIKELY(*scheme_end!=':') + ||OP_UNLIKELY(scheme_end-_src<4)||OP_UNLIKELY(scheme_end-_src>5) + ||OP_UNLIKELY(op_strncasecmp(_src,"https",scheme_end-_src)!=0)){ + /*Unsupported protocol.*/ + return OP_EIMPL; + } + if(OP_UNLIKELY(scheme_end[1]!='/')||OP_UNLIKELY(scheme_end[2]!='/')){ + /*We require an component.*/ + return OP_EINVAL; + } + authority=scheme_end+3; + /*Make sure all escape sequences are valid to simplify unescaping later.*/ + if(OP_UNLIKELY(op_validate_url_escapes(authority)<0))return OP_EINVAL; + /*Look for a component.*/ + userinfo_end=authority+strspn(authority,OP_URL_PCHAR_NA); + if(*userinfo_end=='@'){ + /*Found one.*/ + user=authority; + /*Look for a password (yes, clear-text passwords are deprecated, I know, + but what else are people supposed to use? use SSL if you care).*/ + user_end=authority+strspn(authority,OP_URL_PCHAR_BASE); + if(*user_end==':')pass=user_end+1; + else pass=NULL; + hostport=userinfo_end+1; + } + else{ + /*We shouldn't have to initialize user_end, but gcc is too dumb to figure + out that user!=NULL below means we didn't take this else branch.*/ + user=user_end=NULL; + pass=NULL; + hostport=authority; + } + /*Try to figure out where the component ends.*/ + if(hostport[0]=='['){ + hostport++; + /*We have an , which can contain colons.*/ + hostport_end=host_end=hostport+strspn(hostport,OP_URL_PCHAR_NA); + if(OP_UNLIKELY(*hostport_end++!=']'))return OP_EINVAL; + } + /*Currently we don't support IDNA (RFC 5894), because I don't want to deal + with the policy about which domains should not be internationalized to + avoid confusing similarities. + Give this API Punycode (RFC 3492) domain names instead.*/ + else hostport_end=host_end=hostport+strspn(hostport,OP_URL_PCHAR_BASE); + /*TODO: Validate host.*/ + /*Is there a port number?*/ + port_num=-1; + if(*hostport_end==':'){ + int i; + port=hostport_end+1; + port_end=port+strspn(port,OP_URL_DIGIT); + path=port_end; + /*Not part of RFC 3986, but require port numbers in the range 0...65535.*/ + if(OP_LIKELY(port_end-port>0)){ + while(*port=='0')port++; + if(OP_UNLIKELY(port_end-port>5))return OP_EINVAL; + port_num=0; + for(i=0;i65535))return OP_EINVAL; + } + } + else path=hostport_end; + path_end=path+strspn(path,OP_URL_PATH); + /*If the path is not empty, it must begin with a '/'.*/ + if(OP_LIKELY(path_end>path)&&OP_UNLIKELY(path[0]!='/'))return OP_EINVAL; + /*Consume the component, if any (right now we don't split this out + from the component).*/ + if(*path_end=='?')path_end=path_end+strspn(path_end,OP_URL_QUERY_FRAG); + /*Discard the component, if any. + This doesn't get sent to the server. + Some day we should add support for Media Fragment URIs + .*/ + if(*path_end=='#')uri_end=path_end+1+strspn(path_end+1,OP_URL_QUERY_FRAG); + else uri_end=path_end; + /*If there's anything left, this was not a valid URL.*/ + if(OP_UNLIKELY(*uri_end!='\0'))return OP_EINVAL; + _dst->scheme=op_string_range_dup(_src,scheme_end); + if(OP_UNLIKELY(_dst->scheme==NULL))return OP_EFAULT; + op_string_tolower(_dst->scheme); + if(user!=NULL){ + _dst->user=op_string_range_dup(user,user_end); + if(OP_UNLIKELY(_dst->user==NULL))return OP_EFAULT; + op_unescape_url_component(_dst->user); + /*Unescaping might have created a ':' in the username. + That's not allowed by RFC 2617's Basic Authentication Scheme.*/ + if(OP_UNLIKELY(strchr(_dst->user,':')!=NULL))return OP_EINVAL; + } + else _dst->user=NULL; + if(pass!=NULL){ + _dst->pass=op_string_range_dup(pass,userinfo_end); + if(OP_UNLIKELY(_dst->pass==NULL))return OP_EFAULT; + op_unescape_url_component(_dst->pass); + } + else _dst->pass=NULL; + _dst->host=op_string_range_dup(hostport,host_end); + if(OP_UNLIKELY(_dst->host==NULL))return OP_EFAULT; + if(port_num<0){ + if(_src[4]=='s')port_num=443; + else port_num=80; + } + _dst->port=(unsigned)port_num; + /*RFC 2616 says an empty component is equivalent to "/", and we + MUST use the latter in the Request-URI. + Reserve space for the slash here.*/ + if(path==path_end||path[0]=='?')path--; + _dst->path=op_string_range_dup(path,path_end); + if(OP_UNLIKELY(_dst->path==NULL))return OP_EFAULT; + /*And force-set it here.*/ + _dst->path[0]='/'; + return 0; +} + +static void op_parsed_url_init(OpusParsedURL *_url){ + memset(_url,0,sizeof(*_url)); +} + +static void op_parsed_url_clear(OpusParsedURL *_url){ + _ogg_free(_url->scheme); + _ogg_free(_url->user); + _ogg_free(_url->pass); + _ogg_free(_url->host); + _ogg_free(_url->path); +} + +static int op_parse_url(OpusParsedURL *_dst,const char *_src){ + OpusParsedURL url; + int ret; + op_parsed_url_init(&url); + ret=op_parse_url_impl(&url,_src); + if(OP_UNLIKELY(ret<0))op_parsed_url_clear(&url); + else *_dst=*&url; + return ret; +} + +/*A buffer to hold growing strings. + The main purpose of this is to consolidate allocation checks and simplify + cleanup on a failed allocation.*/ +struct OpusStringBuf{ + char *buf; + int nbuf; + int cbuf; +}; + +static void op_sb_init(OpusStringBuf *_sb){ + _sb->buf=NULL; + _sb->nbuf=0; + _sb->cbuf=0; +} + +static void op_sb_clear(OpusStringBuf *_sb){ + _ogg_free(_sb->buf); +} + +static int op_sb_ensure_capacity(OpusStringBuf *_sb,int _capacity){ + char *buf; + int cbuf; + buf=_sb->buf; + cbuf=_sb->cbuf; + if(_capacity>=cbuf-1){ + if(OP_UNLIKELY(cbuf>INT_MAX-1>>1))return OP_EFAULT; + if(OP_UNLIKELY(_capacity>=INT_MAX-1))return OP_EFAULT; + cbuf=OP_MAX(2*cbuf+1,_capacity+1); + buf=_ogg_realloc(buf,sizeof(*buf)*cbuf); + if(OP_UNLIKELY(buf==NULL))return OP_EFAULT; + _sb->buf=buf; + _sb->cbuf=cbuf; + } + return 0; +} + +static int op_sb_grow(OpusStringBuf *_sb,int _max_size){ + char *buf; + int cbuf; + buf=_sb->buf; + cbuf=_sb->cbuf; + OP_ASSERT(_max_size<=INT_MAX-1); + cbuf=cbuf<=_max_size-1>>1?2*cbuf+1:_max_size+1; + buf=_ogg_realloc(buf,sizeof(*buf)*cbuf); + if(OP_UNLIKELY(buf==NULL))return OP_EFAULT; + _sb->buf=buf; + _sb->cbuf=cbuf; + return 0; +} + +static int op_sb_append(OpusStringBuf *_sb,const char *_s,int _len){ + char *buf; + int nbuf; + int ret; + nbuf=_sb->nbuf; + if(OP_UNLIKELY(nbuf>INT_MAX-_len))return OP_EFAULT; + ret=op_sb_ensure_capacity(_sb,nbuf+_len); + if(OP_UNLIKELY(ret<0))return ret; + buf=_sb->buf; + memcpy(buf+nbuf,_s,sizeof(*buf)*_len); + nbuf+=_len; + buf[nbuf]='\0'; + _sb->nbuf=nbuf; + return 0; +} + +static int op_sb_append_string(OpusStringBuf *_sb,const char *_s){ + return op_sb_append(_sb,_s,strlen(_s)); +} + +static int op_sb_append_port(OpusStringBuf *_sb,unsigned _port){ + char port_buf[7]; + OP_ASSERT(_port<=65535U); + sprintf(port_buf,":%u",_port); + return op_sb_append_string(_sb,port_buf); +} + +static int op_sb_append_nonnegative_int64(OpusStringBuf *_sb,opus_int64 _i){ + char digit; + int nbuf_start; + int ret; + OP_ASSERT(_i>=0); + nbuf_start=_sb->nbuf; + ret=0; + do{ + digit='0'+_i%10; + ret|=op_sb_append(_sb,&digit,1); + _i/=10; + } + while(_i>0); + if(OP_LIKELY(ret>=0)){ + char *buf; + int nbuf_end; + buf=_sb->buf; + nbuf_end=_sb->nbuf-1; + /*We've added the digits backwards. + Reverse them.*/ + while(nbuf_startnext_pos=-1; + _conn->ssl_conn=NULL; + _conn->next=NULL; + _conn->fd=-1; +} + +static void op_http_conn_clear(OpusHTTPConn *_conn){ + if(_conn->ssl_conn!=NULL)SSL_free(_conn->ssl_conn); + /*SSL frees the BIO for us.*/ + if(_conn->fd>=0)close(_conn->fd); +} + +/*The global stream state.*/ +struct OpusHTTPStream{ + /*The list of connections.*/ + OpusHTTPConn conns[OP_NCONNS_MAX]; + /*The context object used as a framework for TLS/SSL functions.*/ + SSL_CTX *ssl_ctx; + /*The cached session to reuse for future connections.*/ + SSL_SESSION *ssl_session; + /*The LRU list (ordered from MRU to LRU) of currently connected + connections.*/ + OpusHTTPConn *lru_head; + /*The free list.*/ + OpusHTTPConn *free_head; + /*The URL to connect to.*/ + OpusParsedURL url; + /*Information about the address we connected to.*/ + struct addrinfo addr_info; + /*The address we connected to.*/ + union{ + struct sockaddr s; + struct sockaddr_in v4; + struct sockaddr_in6 v6; + } addr; + /*A buffer used to build HTTP requests.*/ + OpusStringBuf request; + /*A buffer used to build proxy CONNECT requests.*/ + OpusStringBuf proxy_connect; + /*A buffer used to receive the response headers.*/ + OpusStringBuf response; + /*The Content-Length, if specified, or -1 otherwise. + This will always be specified for seekable streams.*/ + opus_int64 content_length; + /*The position indicator used when no connection is active.*/ + opus_int64 pos; + /*The connection we're currently reading from. + This can be -1 if no connection is active.*/ + int cur_conni; + /*Whether or not the server supports range requests.*/ + int seekable; + /*Whether or not the server supports HTTP/1.1 with persistent connections.*/ + int pipeline; + /*Whether or not we should skip certificate checks.*/ + int skip_certificate_check; + /*The offset of the tail of the request. + Only the offset in the Range: header appears after this, allowing us to + quickly edit the request to ask for a new range.*/ + int request_tail; + /*The estimated time required to open a new connection, in milliseconds.*/ + opus_int32 connect_rate; +}; + +static void op_http_stream_init(OpusHTTPStream *_stream){ + OpusHTTPConn **pnext; + int ci; + pnext=&_stream->free_head; + for(ci=0;ciconns+ci); + *pnext=_stream->conns+ci; + pnext=&_stream->conns[ci].next; + } + _stream->ssl_ctx=NULL; + _stream->ssl_session=NULL; + _stream->lru_head=NULL; + op_parsed_url_init(&_stream->url); + op_sb_init(&_stream->request); + op_sb_init(&_stream->proxy_connect); + op_sb_init(&_stream->response); + _stream->seekable=0; +} + +/*Close the connection and move it to the free list. + _stream: The stream containing the free list. + _conn: The connection to close. + _penxt: The linked-list pointer currently pointing to this connection. + _gracefully: Whether or not to shut down cleanly.*/ +static void op_http_conn_close(OpusHTTPStream *_stream,OpusHTTPConn *_conn, + OpusHTTPConn **_pnext,int _gracefully){ + /*If we don't shut down gracefully, the server MUST NOT re-use our session + according to RFC 2246, because it can't tell the difference between an + abrupt close and a truncation attack. + So we shut down gracefully if we can. + However, we will not wait if this would block (it's not worth the savings + from session resumption to do so). + Clients (that's us) MAY resume a TLS session that ended with an incomplete + close, according to RFC 2818, so that's no reason to make sure the server + shut things down gracefully. + It also says "client implementations MUST treat any premature closes as + errors and the data received as potentially truncated," but libopusfile + treats errors and potentially truncated data in unseekable streams just + like a normal EOF. + We warn about this in the docs, and give some suggestions if you truly want + to avoid truncation attacks.*/ + if(_gracefully&&_conn->ssl_conn!=NULL)SSL_shutdown(_conn->ssl_conn); + op_http_conn_clear(_conn); + _conn->next_pos=-1; + _conn->ssl_conn=NULL; + _conn->fd=-1; + OP_ASSERT(*_pnext==_conn); + *_pnext=_conn->next; + _conn->next=_stream->free_head; + _stream->free_head=_conn; +} + +static void op_http_stream_clear(OpusHTTPStream *_stream){ + while(_stream->lru_head!=NULL){ + op_http_conn_close(_stream,_stream->lru_head,&_stream->lru_head,0); + } + if(_stream->ssl_session!=NULL)SSL_SESSION_free(_stream->ssl_session); + if(_stream->ssl_ctx!=NULL)SSL_CTX_free(_stream->ssl_ctx); + op_sb_clear(&_stream->response); + op_sb_clear(&_stream->proxy_connect); + op_sb_clear(&_stream->request); + op_parsed_url_clear(&_stream->url); +} + +static int op_http_conn_write_fully(OpusHTTPConn *_conn, + const char *_buf,int _buf_size){ + struct pollfd fd; + SSL *ssl_conn; + fd.fd=_conn->fd; + ssl_conn=_conn->ssl_conn; + while(_buf_size>0){ + int err; + if(ssl_conn!=NULL){ + int ret; + ret=SSL_write(ssl_conn,_buf,_buf_size); + if(ret>0){ + /*Wrote some data.*/ + _buf+=ret; + _buf_size-=ret; + continue; + } + /*Connection closed.*/ + else if(ret==0)return OP_FALSE; + err=SSL_get_error(ssl_conn,ret); + /*Yes, renegotiations can cause SSL_write() to block for reading.*/ + if(err==SSL_ERROR_WANT_READ)fd.events=POLLIN; + else if(err==SSL_ERROR_WANT_WRITE)fd.events=POLLOUT; + else return OP_FALSE; + } + else{ + ssize_t ret; + errno=0; + ret=write(fd.fd,_buf,_buf_size); + if(ret>0){ + _buf+=ret; + _buf_size-=ret; + continue; + } + err=errno; + if(err!=EAGAIN&&err!=EWOULDBLOCK)return OP_FALSE; + fd.events=POLLOUT; + } + if(poll(&fd,1,OP_POLL_TIMEOUT_MS)<=0)return OP_FALSE; + } + return 0; +} + +static int op_http_conn_estimate_available(OpusHTTPConn *_conn){ + int available; + int ret; + ret=ioctl(_conn->fd,FIONREAD,&available); + if(ret<0)available=0; + /*This requires the SSL read_ahead flag to be unset to work. + We ignore partial records as well as the protocol overhead for any pending + bytes. + This means we might return somewhat less than can truly be read without + blocking (if there's a partial record). + This is okay, because we're using this value to estimate network transfer + time, and we _have_ already received those bytes. + We also might return slightly more (due to protocol overhead), but that's + small enough that it probably doesn't matter.*/ + if(_conn->ssl_conn!=NULL)available+=SSL_pending(_conn->ssl_conn); + return available; +} + +static opus_int32 op_time_diff_ms(const struct timeb *_end, + const struct timeb *_start){ + opus_int64 dtime; + dtime=_end->time-_start->time; + OP_ASSERT(_end->millitm<1000); + OP_ASSERT(_start->millitm<1000); + if(OP_UNLIKELY(dtime>(0x7FFFFFFF-1000)/1000))return 0x7FFFFFFF; + if(OP_UNLIKELY(dtime<(-0x7FFFFFFF+999)/1000))return -0x7FFFFFFF-1; + return (opus_int32)dtime*1000+_end->millitm-_start->millitm; +} + +/*Update the read rate estimate for this connection.*/ +static void op_http_conn_read_rate_update(OpusHTTPConn *_conn){ + struct timeb read_time; + opus_int32 read_delta_ms; + opus_int64 read_delta_bytes; + opus_int64 read_rate; + read_delta_bytes=_conn->read_bytes; + if(read_delta_bytes<=0)return; + OP_ALWAYS_TRUE(!ftime(&read_time)); + read_delta_ms=op_time_diff_ms(&read_time,&_conn->read_time); + read_rate=_conn->read_rate; + read_delta_ms=OP_MAX(read_delta_ms,1); + read_rate+=read_delta_bytes*1000/read_delta_ms-read_rate+4>>3; + *&_conn->read_time=*&read_time; + _conn->read_bytes=0; + _conn->read_rate=read_rate; +} + +/*Tries to read from the given connection. + [out] _buf: Returns the data read. + _buf_size: The size of the buffer. + _blocking: Whether or not to block until some data is retrieved. + Return: A positive number of bytes read on success. + 0: The read would block, or the connection was closed. + OP_EREAD: There was a fatal read error.*/ +static int op_http_conn_read(OpusHTTPConn *_conn, + char *_buf,int _buf_size,int _blocking){ + struct pollfd fd; + SSL *ssl_conn; + int nread; + int nread_unblocked; + fd.fd=_conn->fd; + ssl_conn=_conn->ssl_conn; + nread=nread_unblocked=0; + do{ + int err; + if(ssl_conn!=NULL){ + int ret; + ret=SSL_read(ssl_conn,_buf+nread,_buf_size-nread); + OP_ASSERT(ret<=_buf_size-nread); + if(ret>0){ + /*Read some data. + Keep going to see if there's more.*/ + nread+=ret; + nread_unblocked+=ret; + continue; + } + /*If we already read some data, return it right now.*/ + if(nread>0)break; + err=SSL_get_error(ssl_conn,ret); + if(ret==0){ + /*Connection close. + Check for a clean shutdown to prevent truncation attacks. + This check always succeeds for SSLv2, as it has no "close notify" + message and thus can't verify an orderly shutdown.*/ + return err==SSL_ERROR_ZERO_RETURN?0:OP_EREAD; + } + if(err==SSL_ERROR_WANT_READ)fd.events=POLLIN; + /*Yes, renegotiations can cause SSL_read() to block for writing.*/ + else if(err==SSL_ERROR_WANT_WRITE)fd.events=POLLOUT; + /*Some other error.*/ + else return OP_EREAD; + } + else{ + ssize_t ret; + errno=0; + ret=read(fd.fd,_buf+nread,_buf_size-nread); + OP_ASSERT(ret<=_buf_size-nread); + if(ret>0){ + /*Read some data. + Keep going to see if there's more.*/ + nread+=ret; + nread_unblocked+=ret; + continue; + } + /*If we already read some data or the connection was closed, return + right now.*/ + if(ret==0||nread>0)break; + err=errno; + if(err!=EAGAIN&&err!=EWOULDBLOCK)return OP_EREAD; + fd.events=POLLIN; + } + _conn->read_bytes+=nread_unblocked; + op_http_conn_read_rate_update(_conn); + nread_unblocked=0; + if(!_blocking)break; + /*Need to wait to get any data at all.*/ + if(poll(&fd,1,OP_POLL_TIMEOUT_MS)<=0)return OP_EREAD; + } + while(nread<_buf_size); + _conn->read_bytes+=nread_unblocked; + return nread; +} + +/*Tries to look at the pending data for a connection without consuming it. + [out] _buf: Returns the data at which we're peeking. + _buf_size: The size of the buffer.*/ +static int op_http_conn_peek(OpusHTTPConn *_conn, + char *_buf,int _buf_size){ + struct pollfd fd; + SSL *ssl_conn; + int ret; + fd.fd=_conn->fd; + ssl_conn=_conn->ssl_conn; + for(;;){ + int err; + if(ssl_conn!=NULL){ + ret=SSL_peek(ssl_conn,_buf,_buf_size); + /*Either saw some data or the connection was closed.*/ + if(ret>=0)return ret; + err=SSL_get_error(ssl_conn,ret); + if(err==SSL_ERROR_WANT_READ)fd.events=POLLIN; + /*Yes, renegotiations can cause SSL_peek() to block for writing.*/ + else if(err==SSL_ERROR_WANT_WRITE)fd.events=POLLOUT; + else return 0; + } + else{ + errno=0; + ret=(int)recv(fd.fd,_buf,_buf_size,MSG_PEEK); + /*Either saw some data or the connection was closed.*/ + if(ret>=0)return ret; + err=errno; + if(err!=EAGAIN&&err!=EWOULDBLOCK)return 0; + fd.events=POLLIN; + } + /*Need to wait to get any data at all.*/ + if(poll(&fd,1,OP_POLL_TIMEOUT_MS)<=0)return 0; + } +} + +/*When parsing response headers, RFC 2616 mandates that all lines end in CR LF. + However, even in the year 2012, I have seen broken servers use just a LF. + This is the evil that Postel's advice from RFC 761 breeds.*/ + +/*Reads the entirety of a response to an HTTP request into the response buffer. + Actual parsing and validation is done later. + Return: The number of bytes in the response on success, OP_EREAD if the + connection was closed before reading any data, or another negative + value on any other error.*/ +static int op_http_conn_read_response(OpusHTTPConn *_conn, + OpusStringBuf *_response){ + int ret; + _response->nbuf=0; + ret=op_sb_ensure_capacity(_response,OP_RESPONSE_SIZE_MIN); + if(OP_UNLIKELY(ret<0))return ret; + for(;;){ + char *buf; + int size; + int capacity; + int read_limit; + int terminated; + size=_response->nbuf; + capacity=_response->cbuf-1; + if(OP_UNLIKELY(size>=capacity)){ + ret=op_sb_grow(_response,OP_RESPONSE_SIZE_MAX); + if(OP_UNLIKELY(ret<0))return ret; + capacity=_response->cbuf-1; + /*The response was too large. + This prevents a bad server from running us out of memory.*/ + if(OP_UNLIKELY(size>=capacity))return OP_EIMPL; + } + buf=_response->buf; + ret=op_http_conn_peek(_conn,buf+size,capacity-size); + if(OP_UNLIKELY(ret<=0))return size<=0?OP_EREAD:OP_FALSE; + /*We read some data.*/ + /*Make sure the starting characters are "HTTP". + Otherwise we could wind up waiting forever for a response from + something that is not an HTTP server.*/ + if(size<4&&op_strncasecmp(buf,"HTTP",OP_MIN(size+ret,4))!=0){ + return OP_FALSE; + } + /*How far can we read without passing the "\r\n\r\n" terminator?*/ + buf[size+ret]='\0'; + terminated=0; + for(read_limit=OP_MAX(size-3,0);read_limitnbuf=size; + /*We found the terminator and read all the data up to and including it.*/ + if(terminated&&OP_LIKELY(size>=read_limit))return size; + } + return OP_EIMPL; +} + +# define OP_HTTP_DIGIT "0123456789" + +/*The Reason-Phrase is not allowed to contain control characters, except + horizontal tab (HT: \011).*/ +# define OP_HTTP_CREASON_PHRASE \ + "\001\002\003\004\005\006\007\010\012\013\014\015\016\017\020\021" \ + "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\177" + +# define OP_HTTP_CTLS \ + "\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020" \ + "\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\177" + +/*This also includes '\t', but we get that from OP_HTTP_CTLS.*/ +# define OP_HTTP_SEPARATORS " \"(),/:;<=>?@[\\]{}" + +/*TEXT can also include LWS, but that has structure, so we parse it + separately.*/ +# define OP_HTTP_CTOKEN OP_HTTP_CTLS OP_HTTP_SEPARATORS + +/*Return: The amount of linear white space (LWS) at the start of _s.*/ +static int op_http_lwsspn(const char *_s){ + int i; + for(i=0;;){ + if(_s[0]=='\r'&&_s[1]=='\n'&&(_s[2]=='\t'||_s[2]==' '))i+=3; + /*This case is for broken servers.*/ + else if(_s[0]=='\n'&&(_s[1]=='\t'||_s[1]==' '))i+=2; + else if(_s[i]=='\t'||_s[i]==' ')i++; + else return i; + } +} + +static char *op_http_parse_status_line(int *_v1_1_compat, + char **_status_code,char *_response){ + char *next; + char *status_code; + int v1_1_compat; + size_t d; + /*RFC 2616 Section 6.1 does not say that the tokens in the Status-Line cannot + be separated by optional LWS, but since it specifically calls out where + spaces are to be placed and that CR and LF are not allowed except at the + end, I am assuming this to be true.*/ + /*We already validated that this starts with "HTTP"*/ + OP_ASSERT(op_strncasecmp(_response,"HTTP",4)==0); + next=_response+4; + if(OP_UNLIKELY(*next++!='/'))return NULL; + d=strspn(next,OP_HTTP_DIGIT); + /*"Leading zeros MUST be ignored by recipients."*/ + while(*next=='0'){ + next++; + OP_ASSERT(d>0); + d--; + } + /*We only support version 1.x*/ + if(OP_UNLIKELY(d!=1)||OP_UNLIKELY(*next++!='1'))return NULL; + if(OP_UNLIKELY(*next++!='.'))return NULL; + d=strspn(next,OP_HTTP_DIGIT); + if(OP_UNLIKELY(d<=0))return NULL; + /*"Leading zeros MUST be ignored by recipients."*/ + while(*next=='0'){ + next++; + OP_ASSERT(d>0); + d--; + } + /*We don't need to parse the version number. + Any non-zero digit means it's greater than 1.*/ + v1_1_compat=d>0; + next+=d; + if(OP_UNLIKELY(*next++!=' '))return NULL; + status_code=next; + d=strspn(next,OP_HTTP_DIGIT); + if(OP_UNLIKELY(d!=3))return NULL; + next+=d; + /*The Reason-Phrase can be empty, but the space must be here.*/ + if(OP_UNLIKELY(*next++!=' '))return NULL; + next+=strcspn(next,OP_HTTP_CREASON_PHRASE); + /*We are not mandating this be present thanks to broken servers.*/ + if(OP_LIKELY(*next=='\r'))next++; + if(OP_UNLIKELY(*next++!='\n'))return NULL; + if(_v1_1_compat!=NULL)*_v1_1_compat=v1_1_compat; + *_status_code=status_code; + return next; +} + +/*Get the next response header. + [out] _header: The header token, NUL-terminated, with leading and trailing + whitespace stripped, and converted to lower case (to simplify + case-insensitive comparisons), or NULL if there are no more + response headers. + [out] _cdr: The remaining contents of the header, excluding the initial + colon (':') and the terminating CRLF ("\r\n"), + NUL-terminated, and with leading and trailing whitespace + stripped, or NULL if there are no more response headers. + [inout] _s: On input, this points to the start of the current line of the + response headers. + On output, it points to the start of the first line following + this header, or NULL if there are no more response headers. + Return: 0 on success, or a negative value on failure.*/ +static int op_http_get_next_header(char **_header,char **_cdr,char **_s){ + char *header; + char *header_end; + char *cdr; + char *cdr_end; + char *next; + size_t d; + next=*_s; + /*The second case is for broken servers.*/ + if(next[0]=='\r'&&next[1]=='\n'||OP_UNLIKELY(next[0]=='\n')){ + /*No more headers.*/ + *_header=NULL; + *_cdr=NULL; + *_s=NULL; + return 0; + } + header=next+op_http_lwsspn(next); + d=strcspn(header,OP_HTTP_CTOKEN); + if(OP_UNLIKELY(d<=0))return OP_FALSE; + header_end=header+d; + next=header_end+op_http_lwsspn(header_end); + if(OP_UNLIKELY(*next++!=':'))return OP_FALSE; + next+=op_http_lwsspn(next); + cdr=next; + do{ + cdr_end=next+strcspn(next,OP_HTTP_CTLS); + next=cdr_end+op_http_lwsspn(cdr_end); + } + while(next>cdr_end); + /*We are not mandating this be present thanks to broken servers.*/ + if(OP_LIKELY(*next=='\r'))next++; + if(OP_UNLIKELY(*next++!='\n'))return OP_FALSE; + *header_end='\0'; + *cdr_end='\0'; + /*Field names are case-insensitive.*/ + op_string_tolower(header); + *_header=header; + *_cdr=cdr; + *_s=next; + return 0; +} + +static opus_int64 op_http_parse_nonnegative_int64(const char **_next, + const char *_cdr){ + const char *next; + opus_int64 content_length; + int i; + next=_cdr+strspn(_cdr,OP_HTTP_DIGIT); + *_next=next; + if(OP_UNLIKELY(next<=_cdr))return OP_FALSE; + while(*_cdr=='0')_cdr++; + if(OP_UNLIKELY(next-_cdr>19))return OP_EIMPL; + content_length=0; + for(i=0;i(OP_INT64_MAX-9)/10+(digit<=7))){ + return OP_EIMPL; + } + content_length=content_length*10+digit; + } + return content_length; +} + +static opus_int64 op_http_parse_content_length(const char *_cdr){ + const char *next; + opus_int64 content_length; + content_length=op_http_parse_nonnegative_int64(&next,_cdr); + if(OP_UNLIKELY(*next!='\0'))return OP_FALSE; + return content_length; +} + +static int op_http_parse_content_range(opus_int64 *_first,opus_int64 *_last, + opus_int64 *_length,const char *_cdr){ + opus_int64 first; + opus_int64 last; + opus_int64 length; + size_t d; + if(OP_UNLIKELY(op_strncasecmp(_cdr,"bytes",5)!=0))return OP_FALSE; + _cdr+=5; + d=op_http_lwsspn(_cdr); + if(OP_UNLIKELY(d<=0))return OP_FALSE; + _cdr+=d; + if(*_cdr!='*'){ + first=op_http_parse_nonnegative_int64(&_cdr,_cdr); + if(OP_UNLIKELY(first<0))return (int)first; + _cdr+=op_http_lwsspn(_cdr); + if(*_cdr++!='-')return OP_FALSE; + _cdr+=op_http_lwsspn(_cdr); + last=op_http_parse_nonnegative_int64(&_cdr,_cdr); + if(OP_UNLIKELY(last<0))return (int)last; + _cdr+=op_http_lwsspn(_cdr); + } + else{ + /*This is for a 416 response (Requested range not satisfiable).*/ + first=last=-1; + _cdr++; + } + if(OP_UNLIKELY(*_cdr++!='/'))return OP_FALSE; + if(*_cdr!='*'){ + length=op_http_parse_nonnegative_int64(&_cdr,_cdr); + if(OP_UNLIKELY(length<0))return (int)length; + } + else{ + /*The total length is unspecified.*/ + _cdr++; + length=-1; + } + if(OP_UNLIKELY(*_cdr!='\0'))return OP_FALSE; + if(OP_UNLIKELY(last=0&&OP_UNLIKELY(last>=length))return OP_FALSE; + *_first=first; + *_last=last; + *_length=length; + return 0; +} + +/*Parse the Connection response header and look for a "close" token. + Return: 1 if a "close" token is found, 0 if it's not found, and a negative + value on error.*/ +static int op_http_parse_connection(char *_cdr){ + size_t d; + int ret; + ret=0; + for(;;){ + d=strcspn(_cdr,OP_HTTP_CTOKEN); + if(OP_UNLIKELY(d<=0))return OP_FALSE; + if(op_strncasecmp(_cdr,"close",(int)d)==0)ret=1; + /*We're supposed to strip and ignore any headers mentioned in the + Connection header if this response is from an HTTP/1.0 server (to + work around forwarding of hop-by-hop headers by old proxies), but the + only hop-by-hop header we look at is Connection itself. + Everything else is a well-defined end-to-end header, and going back and + undoing the things we did based on already-examined headers would be + hard (since we only scan them once, in a destructive manner). + Therefore we just ignore all the other tokens.*/ + _cdr+=d; + d=op_http_lwsspn(_cdr); + if(d<=0)break; + _cdr+=d; + } + return OP_UNLIKELY(*_cdr!='\0')?OP_FALSE:ret; +} + +typedef int (*op_ssl_step_func)(SSL *_ssl_conn); + +/*Try to run an SSL function to completion (blocking if necessary).*/ +static int op_do_ssl_step(SSL *_ssl_conn,int _fd,op_ssl_step_func _step){ + struct pollfd fd; + fd.fd=_fd; + for(;;){ + int ret; + int err; + ret=(*_step)(_ssl_conn); + if(ret>=0)return ret; + err=SSL_get_error(_ssl_conn,ret); + if(err==SSL_ERROR_WANT_READ)fd.events=POLLIN; + else if(err==SSL_ERROR_WANT_WRITE)fd.events=POLLOUT; + else return OP_FALSE; + if(poll(&fd,1,OP_POLL_TIMEOUT_MS)<=0)return OP_FALSE; + } +} + +/*Implement a BIO type that just indicates every operation should be retried. + We use this when initializing an SSL connection via a proxy to allow the + initial handshake to proceed all the way up to the first read attempt, and + then return. + This allows the TLS client hello message to be pipelined with the HTTP + CONNECT request.*/ + +static int op_bio_retry_write(BIO *_b,const char *_buf,int _num){ + (void)_buf; + (void)_num; + BIO_clear_retry_flags(_b); + BIO_set_retry_write(_b); + return -1; +} + +static int op_bio_retry_read(BIO *_b,char *_buf,int _num){ + (void)_buf; + (void)_num; + BIO_clear_retry_flags(_b); + BIO_set_retry_read(_b); + return -1; +} + +static int op_bio_retry_puts(BIO *_b,const char *_str){ + return op_bio_retry_write(_b,_str,0); +} + +static long op_bio_retry_ctrl(BIO *_b,int _cmd,long _num,void *_ptr){ + long ret; + (void)_b; + (void)_num; + (void)_ptr; + ret=0; + switch(_cmd){ + case BIO_CTRL_RESET: + case BIO_C_RESET_READ_REQUEST:{ + BIO_clear_retry_flags(_b); + /*Fall through.*/ + } + case BIO_CTRL_EOF: + case BIO_CTRL_SET: + case BIO_CTRL_SET_CLOSE: + case BIO_CTRL_FLUSH: + case BIO_CTRL_DUP:{ + ret=1; + }break; + } + return ret; +} + +static int op_bio_retry_new(BIO *_b){ + _b->init=1; + _b->num=0; + _b->ptr=NULL; + return 1; +} + +static int op_bio_retry_free(BIO *_b){ + return _b!=NULL; +} + +/*This is not const because OpenSSL doesn't allow it, even though it won't + write to it.*/ +static BIO_METHOD op_bio_retry_method={ + BIO_TYPE_NULL, + "retry", + op_bio_retry_write, + op_bio_retry_read, + op_bio_retry_puts, + NULL, + op_bio_retry_ctrl, + op_bio_retry_new, + op_bio_retry_free, + NULL +}; + +/*Establish a CONNECT tunnel and pipeline the start of the TLS handshake for + proxying https URL requests.*/ +int op_http_conn_establish_tunnel(OpusHTTPStream *_stream, + OpusHTTPConn *_conn,int _fd,SSL *_ssl_conn,BIO *_ssl_bio){ + BIO *retry_bio; + char *status_code; + char *next; + int ret; + _conn->ssl_conn=NULL; + _conn->fd=_fd; + OP_ASSERT(_stream->proxy_connect.nbuf>0); + ret=op_http_conn_write_fully(_conn, + _stream->proxy_connect.buf,_stream->proxy_connect.nbuf); + if(OP_UNLIKELY(ret<0))return ret; + retry_bio=BIO_new(&op_bio_retry_method); + if(OP_UNLIKELY(retry_bio==NULL))return OP_EFAULT; + SSL_set_bio(_ssl_conn,retry_bio,_ssl_bio); + SSL_set_connect_state(_ssl_conn); + /*This shouldn't succeed, since we can't read yet.*/ + OP_ALWAYS_TRUE(SSL_connect(_ssl_conn)<0); + SSL_set_bio(_ssl_conn,_ssl_bio,_ssl_bio); + /*Only now do we disable write coalescing, to allow the CONNECT + request and the start of the TLS handshake to be combined.*/ + op_sock_set_tcp_nodelay(_fd,1); + ret=op_http_conn_read_response(_conn,&_stream->response); + if(OP_UNLIKELY(ret<0))return ret; + next=op_http_parse_status_line(NULL,&status_code,_stream->response.buf); + /*According to RFC 2817, "Any successful (2xx) response to a + CONNECT request indicates that the proxy has established a + connection to the requested host and port.*/ + if(OP_UNLIKELY(next==NULL)||OP_UNLIKELY(status_code[0]!='2'))return OP_FALSE; + return 0; +} + +/*Match a host name against a host with a possible wildcard pattern according + to the rules of RFC 6125 Section 6.4.3. + Return: 0 if the pattern doesn't match, and a non-zero value if it does.*/ +static int op_http_hostname_match(const char *_host,size_t _host_len, + ASN1_STRING *_pattern){ + const char *pattern; + size_t host_label_len; + size_t host_suffix_len; + size_t pattern_len; + size_t pattern_label_len; + size_t pattern_prefix_len; + size_t pattern_suffix_len; + pattern=(const char *)ASN1_STRING_data(_pattern); + pattern_len=strlen(pattern); + /*Check the pattern for embedded NULs.*/ + if(OP_UNLIKELY(pattern_len!=(size_t)ASN1_STRING_length(_pattern)))return 0; + pattern_label_len=strcspn(pattern,"."); + OP_ASSERT(pattern_label_len<=pattern_len); + pattern_prefix_len=strcspn(pattern,"*"); + if(pattern_prefix_len>=pattern_label_len){ + /*"The client SHOULD NOT attempt to match a presented identifier in which + the wildcard character comprises a label other than the left-most label + (e.g., do not match bar.*.example.net)." [RFC 6125 Section 6.4.3]*/ + if(pattern_prefix_lenurl.host; + host_len=strlen(host); + peer_cert=SSL_get_peer_certificate(_ssl_conn); + /*We set VERIFY_PEER, so we shouldn't get here without a certificate.*/ + if(OP_UNLIKELY(peer_cert==NULL))return 0; + ret=0; + OP_ASSERT(host_lenai_family){ + case AF_INET:{ + struct sockaddr_in *s; + s=(struct sockaddr_in *)addr->ai_addr; + OP_ASSERT(addr->ai_addrlen>=sizeof(*s)); + ip=(unsigned char *)&s->sin_addr; + ip_len=sizeof(s->sin_addr); + }break; + case AF_INET6:{ + struct sockaddr_in6 *s; + s=(struct sockaddr_in6 *)addr->ai_addr; + OP_ASSERT(addr->ai_addrlen>=sizeof(*s)); + ip=(unsigned char *)&s->sin6_addr; + ip_len=sizeof(s->sin6_addr); + }break; + } + } + /*We can only verify fully-qualified domain names. + To quote RFC 6125: "The extracted data MUST include only information that + can be securely parsed out of the inputs (e.g., parsing the fully + qualified DNS domain name out of the "host" component (or its + equivalent) of a URI or deriving the application service type from the + scheme of a URI) ..." + We don't have a way to check (without relying on DNS records, which might + be subverted), if this address is fully-qualified. + This is particularly problematic when using a CONNECT tunnel, as it is + the server that does DNS lookup, not us. + However, we are certain that if the hostname has no '.', it is definitely + not a fully-qualified domain name (with the exception of crazy TLDs that + actually resolve, like "uz", but I am willing to ignore those). + RFC 1535 says "...in any event where a '.' exists in a specified name it + should be assumed to be a fully qualified domain name (FQDN) and SHOULD + be tried as a rooted name first." + That doesn't give us any security guarantees, of course (a subverted DNS + could fail the original query and our resolver might still retry with a + local domain appended). + If we don't have a FQDN, just set the number of names to 0, so we'll fail + and clean up any resources we allocated.*/ + if(ip==NULL&&strchr(host,'.')==NULL)nsan_names=0; + /*RFC 2459 says there MUST be at least one, but we don't depend on it.*/ + else nsan_names=sk_GENERAL_NAME_num(san_names); + for(sni=0;snitype==GEN_DNS + &&op_http_hostname_match(host,host_len,name->d.dNSName)){ + ret=1; + break; + } + } + else if(name->type==GEN_IPADD){ + unsigned char *cert_ip; + /*If we do have an IP address, compare it directly. + RFC 6125: "When the reference identity is an IP address, the identity + MUST be converted to the 'network byte order' octet string + representation. + For IP Version 4, as specified in RFC 791, the octet string will + contain exactly four octets. + For IP Version 6, as specified in RFC 2460, the octet string will + contain exactly sixteen octets. + This octet string is then compared against subjectAltName values of + type iPAddress. + A match occurs if the reference identity octet string and the value + octet strings are identical."*/ + cert_ip=ASN1_STRING_data(name->d.iPAddress); + if(ip_len==ASN1_STRING_length(name->d.iPAddress) + &&memcmp(ip,cert_ip,ip_len)==0){ + ret=1; + break; + } + } + } + sk_GENERAL_NAME_pop_free(san_names,GENERAL_NAME_free); + if(addr!=NULL)freeaddrinfo(addr); + } + /*Do the same FQDN check we did above. + We don't do this once in advance for both cases, because in the + subjectAltName case we might have an IPv6 address without a dot.*/ + else if(strchr(host,'.')!=NULL){ + int last_cn_loc; + int cn_loc; + /*If there is no subjectAltName, match against commonName. + RFC 6125 says that at least one significant CA is known to issue certs + with multiple CNs, although it SHOULD NOT. + It also says: "The server's identity may also be verified by comparing + the reference identity to the Common Name (CN) value in the last + Relative Distinguished Name (RDN) of the subject field of the server's + certificate (where "last" refers to the DER-encoded order...)." + So find the last one and check it.*/ + cn_loc=-1; + do{ + last_cn_loc=cn_loc; + cn_loc=X509_NAME_get_index_by_NID(X509_get_subject_name(peer_cert), + NID_commonName,last_cn_loc); + } + while(cn_loc>=0); + ret=last_cn_loc>=0 + &&op_http_hostname_match(host,host_len, + X509_NAME_ENTRY_get_data( + X509_NAME_get_entry(X509_get_subject_name(peer_cert),last_cn_loc))); + } + X509_free(peer_cert); + return ret; +} + +/*Perform the TLS handshake on a new connection.*/ +int op_http_conn_start_tls(OpusHTTPStream *_stream,OpusHTTPConn *_conn, + int _fd,SSL *_ssl_conn){ + SSL_SESSION *ssl_session; + BIO *ssl_bio; + int skip_certificate_check; + int ret; + ssl_bio=BIO_new_socket(_fd,BIO_NOCLOSE); + if(OP_LIKELY(ssl_bio==NULL))return OP_FALSE; +# if !defined(OPENSSL_NO_TLSEXT) + /*Support for RFC 6066 Server Name Indication.*/ + SSL_set_tlsext_host_name(_ssl_conn,_stream->url.host); +# endif + /*Resume a previous session if available.*/ + if(_stream->ssl_session!=NULL){ + SSL_set_session(_ssl_conn,_stream->ssl_session); + } + /*If we're proxying, establish the CONNECT tunnel.*/ + if(_stream->proxy_connect.nbuf>0){ + ret=op_http_conn_establish_tunnel(_stream,_conn, + _fd,_ssl_conn,ssl_bio); + if(OP_UNLIKELY(ret<0))return ret; + } + else{ + /*Otherwise, just use this socket directly.*/ + op_sock_set_tcp_nodelay(_fd,1); + SSL_set_bio(_ssl_conn,ssl_bio,ssl_bio); + SSL_set_connect_state(_ssl_conn); + } + ret=op_do_ssl_step(_ssl_conn,_fd,SSL_connect); + if(OP_UNLIKELY(ret<=0))return OP_FALSE; + ssl_session=_stream->ssl_session; + skip_certificate_check=_stream->skip_certificate_check; + if(ssl_session==NULL||!skip_certificate_check){ + ret=op_do_ssl_step(_ssl_conn,_fd,SSL_do_handshake); + if(OP_UNLIKELY(ret<=0))return OP_FALSE; + /*OpenSSL does not do hostname verification, despite the fact that we just + passed it the hostname above in the call to SSL_set_tlsext_host_name(), + because they are morons. + Do it for them.*/ + if(!skip_certificate_check&&!op_http_verify_hostname(_stream,_ssl_conn)){ + return OP_FALSE; + } + if(ssl_session==NULL){ + /*Save the session for later resumption.*/ + _stream->ssl_session=SSL_get1_session(_ssl_conn); + } + } + _conn->ssl_conn=_ssl_conn; + _conn->fd=_fd; + _conn->nrequests_left=OP_PIPELINE_MAX_REQUESTS; + return 0; +} + +/*Try to start a connection to the next address in the given list of a given + type. + _fd: The socket to connect with. + [inout] _addr: A pointer to the list of addresses. + This will be advanced to the first one that matches the given + address family (possibly the current one). + _ai_family: The address family to connect to. + Return: 1 If the connection was successful. + 0 If the connection is in progress. + OP_FALSE If the connection failed and there were no more addresses + left to try. + *_addr will be set to NULL in this case.*/ +static int op_sock_connect_next(int _fd, + struct addrinfo **_addr,int _ai_family){ + struct addrinfo *addr; + addr=*_addr; + for(;;){ + /*Move to the next address of the requested type.*/ + for(;addr!=NULL&&addr->ai_family!=_ai_family;addr=addr->ai_next); + *_addr=addr; + /*No more: failure.*/ + if(addr==NULL)return OP_FALSE; + if(connect(_fd,addr->ai_addr,addr->ai_addrlen)>=0)return 1; + if(OP_LIKELY(errno==EINPROGRESS))return 0; + addr=addr->ai_next; + } +} + +/*The number of address families to try connecting to simultaneously.*/ +# define OP_NPROTOS (2) + +static int op_http_connect(OpusHTTPStream *_stream,OpusHTTPConn *_conn, + struct addrinfo *_addrs,struct timeb *_start_time){ + struct addrinfo *addr; + struct addrinfo *addrs[OP_NPROTOS]; + struct pollfd fds[OP_NPROTOS]; + int ai_family; + int nprotos; + int ret; + int pi; + int pj; + for(pi=0;piai_next){ + /*Give IPv6 a slight edge by putting it first in the list.*/ + if(addr->ai_family==AF_INET6){ + OP_ASSERT(addr->ai_addrlen<=sizeof(struct sockaddr_in6)); + if(addrs[0]==NULL)addrs[0]=addr; + } + else if(addr->ai_family==AF_INET){ + OP_ASSERT(addr->ai_addrlen<=sizeof(struct sockaddr_in)); + if(addrs[1]==NULL)addrs[1]=addr; + } + } + /*Consolidate the list of addresses.*/ + for(pi=nprotos=0;pifree_head==_conn); + _stream->free_head=_conn->next; + _conn->next=_stream->lru_head; + _stream->lru_head=_conn; + OP_ALWAYS_TRUE(!ftime(_start_time)); + *&_conn->read_time=*_start_time; + _conn->read_bytes=0; + _conn->read_rate=0; + /*Try to start a connection to each protocol.*/ + for(pi=0;piai_family; + fds[pi].fd=socket(ai_family,SOCK_STREAM,addrs[pi]->ai_protocol); + fds[pi].events=POLLOUT; + if(OP_LIKELY(fds[pi].fd>=0)){ + if(OP_LIKELY(op_sock_set_nonblocking(fds[pi].fd,1)>=0)){ + ret=op_sock_connect_next(fds[pi].fd,addrs+pi,ai_family); + if(OP_UNLIKELY(ret>0)){ + /*It succeeded right away (technically possible), so stop.*/ + nprotos=pi+1; + break; + } + /*Otherwise go on to the next protocol, and skip the clean-up below.*/ + else if(ret==0)continue; + /*Tried all the addresses for this protocol.*/ + } + /*Clean up the socket.*/ + close(fds[pi].fd); + } + /*Remove this protocol from the list.*/ + memmove(addrs+pi,addrs+pi+1,sizeof(*addrs)*(nprotos-pi-1)); + nprotos--; + pi--; + } + /*Wait for one of the connections to finish.*/ + while(pi>=nprotos&&nprotos>0&&poll(fds,nprotos,OP_POLL_TIMEOUT_MS)>0){ + for(pi=0;piai_family; + addrs[pi]=addrs[pi]->ai_next; + ret=op_sock_connect_next(fds[pi].fd,addrs+pi,ai_family); + /*It succeeded right away, so stop.*/ + if(ret>0)break; + /*Otherwise go on to the next protocol, and skip the clean-up below.*/ + else if(ret==0)continue; + /*Tried all the addresses for this protocol. + Remove it from the list.*/ + close(fds[pi].fd); + memmove(fds+pi,fds+pi+1,sizeof(*fds)*(nprotos-pi-1)); + memmove(addrs+pi,addrs+pi+1,sizeof(*addrs)*(nprotos-pi-1)); + nprotos--; + pi--; + } + } + /*Close all the other sockets.*/ + for(pj=0;pj=nprotos)return OP_FALSE; + /*Save this address for future connection attempts.*/ + if(addrs[pi]!=&_stream->addr_info){ + memcpy(&_stream->addr_info,addrs[pi],sizeof(_stream->addr_info)); + _stream->addr_info.ai_addr=&_stream->addr.s; + _stream->addr_info.ai_next=NULL; + memcpy(&_stream->addr,addrs[pi]->ai_addr,addrs[pi]->ai_addrlen); + } + if(OP_URL_IS_SSL(&_stream->url)){ + SSL *ssl_conn; + /*Start the SSL connection.*/ + OP_ASSERT(_stream->ssl_ctx!=NULL); + ssl_conn=SSL_new(_stream->ssl_ctx); + if(OP_LIKELY(ssl_conn!=NULL)){ + ret=op_http_conn_start_tls(_stream,_conn,fds[pi].fd,ssl_conn); + if(OP_LIKELY(ret>=0))return ret; + SSL_free(ssl_conn); + } + close(fds[pi].fd); + _conn->fd=-1; + return OP_FALSE; + } + /*Just a normal non-SSL connection.*/ + _conn->ssl_conn=NULL; + _conn->fd=fds[pi].fd; + _conn->nrequests_left=OP_PIPELINE_MAX_REQUESTS; + /*Disable write coalescing. + We always send whole requests at once and always parse the response headers + before sending another one.*/ + op_sock_set_tcp_nodelay(fds[pi].fd,1); + return 0; +} + +# define OP_BASE64_LENGTH(_len) (((_len)+2)/3*4) + +static const char BASE64_TABLE[64]={ + 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', + 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', + 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v', + 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/' +}; + +static char *op_base64_encode(char *_dst,const char *_src,int _len){ + unsigned s0; + unsigned s1; + unsigned s2; + int ngroups; + int i; + ngroups=_len/3; + for(i=0;i>2]; + _dst[4*i+1]=BASE64_TABLE[s0&3<<4|s1>>4]; + _dst[4*i+2]=BASE64_TABLE[s1&15<<2|s2>>6]; + _dst[4*i+3]=BASE64_TABLE[s2&63]; + } + _len-=3*i; + if(_len==1){ + s0=_src[3*i+0]; + _dst[4*i+0]=BASE64_TABLE[s0>>2]; + _dst[4*i+1]=BASE64_TABLE[s0&3<<4]; + _dst[4*i+2]='='; + _dst[4*i+3]='='; + i++; + } + else if(_len==2){ + s0=_src[3*i+0]; + s1=_src[3*i+1]; + _dst[4*i+0]=BASE64_TABLE[s0>>2]; + _dst[4*i+1]=BASE64_TABLE[s0&3<<4|s1>>4]; + _dst[4*i+2]=BASE64_TABLE[s1&15<<2]; + _dst[4*i+3]='='; + i++; + } + _dst[4*i]='\0'; + return _dst+4*i; +} + +/*Construct an HTTP authorization header using RFC 2617's Basic Authentication + Scheme and append it to the given string buffer.*/ +static int op_sb_append_basic_auth_header(OpusStringBuf *_sb, + const char *_header,const char *_user,const char *_pass){ + int user_len; + int pass_len; + int user_pass_len; + int base64_len; + int nbuf_total; + int ret; + ret=op_sb_append_string(_sb,_header); + ret|=op_sb_append(_sb,": Basic ",8); + user_len=strlen(_user); + pass_len=strlen(_pass); + if(OP_UNLIKELY(pass_len>INT_MAX-user_len))return OP_EFAULT; + if(OP_UNLIKELY(user_len+pass_len>(INT_MAX>>2)*3-3))return OP_EFAULT; + user_pass_len=user_len+1+pass_len; + base64_len=OP_BASE64_LENGTH(user_pass_len); + /*Stick "user:pass" at the end of the buffer so we can Base64 encode it + in-place.*/ + nbuf_total=_sb->nbuf; + if(OP_UNLIKELY(base64_len>INT_MAX-nbuf_total))return OP_EFAULT; + nbuf_total+=base64_len; + ret|=op_sb_ensure_capacity(_sb,nbuf_total); + if(OP_UNLIKELY(ret<0))return ret; + _sb->nbuf=nbuf_total-user_pass_len; + OP_ALWAYS_TRUE(!op_sb_append(_sb,_user,user_len)); + OP_ALWAYS_TRUE(!op_sb_append(_sb,":",1)); + OP_ALWAYS_TRUE(!op_sb_append(_sb,_pass,pass_len)); + op_base64_encode(_sb->buf+nbuf_total-base64_len, + _sb->buf+nbuf_total-user_pass_len,user_pass_len); + return op_sb_append(_sb,"\r\n",2); +} + +static int op_http_allow_pipelining(const char *_server){ + /*Servers known to do bad things with pipelined requests. + This list is taken from Gecko's nsHttpConnection::SupportsPipelining() (in + netwerk/protocol/http/nsHttpConnection.cpp).*/ + static const char *BAD_SERVERS[]={ + "EFAServer/", + "Microsoft-IIS/4.", + "Microsoft-IIS/5.", + "Netscape-Enterprise/3.", + "Netscape-Enterprise/4.", + "Netscape-Enterprise/5.", + "Netscape-Enterprise/6.", + "WebLogic 3.", + "WebLogic 4.", + "WebLogic 5.", + "WebLogic 6.", + "Winstone Servlet Engine v0." + }; +# define NBAD_SERVERS ((int)(sizeof(BAD_SERVERS)/sizeof(*BAD_SERVERS))) + if(*_server>='E'&&*_server<='W'){ + int si; + for(si=0;si65535U))return OP_EINVAL; + last_host=NULL; + /*We shouldn't have to initialize last_port, but gcc is too dumb to figure + out that last_host!=NULL implies we've already taken one trip through the + loop.*/ + last_port=0; + ret=op_parse_url(&_stream->url,_url); + if(OP_UNLIKELY(ret<0))return ret; + for(nredirs=0;nredirsurl.host; + port=_stream->url.port; + } + else{ + host=_proxy_host; + port=_proxy_port; + } + /*If connecting to the same place as last time, don't re-resolve it.*/ + addrs=NULL; + if(last_host!=NULL){ + if(strcmp(last_host,host)==0&&last_port==port)addrs=&_stream->addr_info; + else if(_stream->ssl_session!=NULL){ + /*Forget any cached SSL session from the last host.*/ + SSL_SESSION_free(_stream->ssl_session); + _stream->ssl_session=NULL; + } + if(last_host!=_proxy_host)_ogg_free((void *)last_host); + } + last_host=host; + last_port=port; + /*Initialize the SSL library if necessary.*/ + if(OP_URL_IS_SSL(&_stream->url)&&_stream->ssl_ctx==NULL){ + SSL_CTX *ssl_ctx; +# if !defined(OPENSSL_NO_LOCKING) + /*The documentation says SSL_library_init() is not reentrant. + We don't want to add our own depenencies on a threading library, and it + appears that it's safe to call OpenSSL's locking functions before the + library is initialized, so that's what we'll do (really OpenSSL should + do this for us). + This doesn't guarantee that _other_ threads in the application aren't + calling SSL_library_init() at the same time, but there's not much we + can do about that.*/ + CRYPTO_w_lock(CRYPTO_LOCK_SSL); +# endif + SSL_library_init(); + /*Needed to get SHA2 algorithms with old OpenSSL versions.*/ + OpenSSL_add_ssl_algorithms(); +# if !defined(OPENSSL_NO_LOCKING) + CRYPTO_w_unlock(CRYPTO_LOCK_SSL); +# endif + ssl_ctx=SSL_CTX_new(SSLv23_client_method()); + if(ssl_ctx==NULL)return OP_EFAULT; + if(!_skip_certificate_check){ + /*We don't do anything if this fails, since it just means we won't load + any certificates (and thus all checks will fail). + However, as that is probably the result of a system + mis-configuration, assert here to make it easier to identify.*/ + OP_ALWAYS_TRUE(SSL_CTX_set_default_verify_paths(ssl_ctx)); + SSL_CTX_set_verify(ssl_ctx,SSL_VERIFY_PEER,NULL); + } + _stream->ssl_ctx=ssl_ctx; + _stream->skip_certificate_check=_skip_certificate_check; + if(_proxy_host!=NULL){ + /*We need to establish a CONNECT tunnel to handle https proxying. + Build the request we'll send to do so.*/ + ret=op_sb_append(&_stream->proxy_connect,"CONNECT ",8); + ret|=op_sb_append_string(&_stream->proxy_connect,_stream->url.host); + ret|=op_sb_append_port(&_stream->proxy_connect,_stream->url.port); + /*CONNECT requires at least HTTP 1.1.*/ + ret|=op_sb_append(&_stream->proxy_connect," HTTP/1.1\r\n",11); + ret|=op_sb_append(&_stream->proxy_connect,"Host: ",6); + ret|=op_sb_append_string(&_stream->proxy_connect,_stream->url.host); + /*The example in RFC 2817 Section 5.2 specifies an explicit port even + when connecting to the default port. + Given that the proxy doesn't know whether we're trying to connect to + an http or an https URL except by the port number, this seems like a + good idea.*/ + ret|=op_sb_append_port(&_stream->proxy_connect,_stream->url.port); + ret|=op_sb_append(&_stream->proxy_connect,"\r\n",2); + ret|=op_sb_append(&_stream->proxy_connect,"User-Agent: .\r\n",15); + if(_proxy_user!=NULL&&_proxy_pass!=NULL){ + ret|=op_sb_append_basic_auth_header(&_stream->proxy_connect, + "Proxy-Authorization",_proxy_user,_proxy_pass); + } + /*For backwards compatibility.*/ + ret|=op_sb_append(&_stream->proxy_connect, + "Proxy-Connection: keep-alive\r\n",30); + ret|=op_sb_append(&_stream->proxy_connect,"\r\n",2); + if(OP_UNLIKELY(ret<0))return ret; + } + } + /*Actually make the connection.*/ + if(addrs!=&_stream->addr_info){ + addrs=op_resolve(host,port); + if(OP_UNLIKELY(addrs==NULL))return OP_FALSE; + } + ret=op_http_connect(_stream,_stream->conns+0,addrs,&start_time); + if(addrs!=&_stream->addr_info)freeaddrinfo(addrs); + if(OP_UNLIKELY(ret<0))return ret; + /*Build the request to send.*/ + _stream->request.nbuf=0; + ret=op_sb_append(&_stream->request,"GET ",4); + ret|=op_sb_append_string(&_stream->request, + _proxy_host!=NULL?_url:_stream->url.path); + /*Send HTTP/1.0 by default for maximum compatibility (so we don't have to + re-try if HTTP/1.1 fails, though it shouldn't, even for a 1.0 server). + This means we aren't conditionally compliant with RFC 2145, because we + violate the requirement that "An HTTP client SHOULD send a request + version equal to the highest version for which the client is at least + conditionally compliant...". + According to RFC 2145, that means we can't claim any compliance with any + IETF HTTP specification.*/ + ret|=op_sb_append(&_stream->request," HTTP/1.0\r\n",11); + /*Remember where this is so we can upgrade to HTTP/1.1 if the server + supports it.*/ + minor_version_pos=_stream->request.nbuf-3; + ret|=op_sb_append(&_stream->request,"Host: ",6); + ret|=op_sb_append_string(&_stream->request,_stream->url.host); + if(!OP_URL_IS_DEFAULT_PORT(&_stream->url)){ + ret|=op_sb_append_port(&_stream->request,_stream->url.port); + } + ret|=op_sb_append(&_stream->request,"\r\n",2); + /*User-Agents have been a bad idea, so send as little as possible. + RFC 2616 requires at least one token in the User-Agent, which must have + at least one character.*/ + ret|=op_sb_append(&_stream->request,"User-Agent: .\r\n",15); + if(_proxy_host!=NULL&&!OP_URL_IS_SSL(&_stream->url) + &&_proxy_user!=NULL&&_proxy_pass!=NULL){ + ret|=op_sb_append_basic_auth_header(&_stream->request, + "Proxy-Authorization",_proxy_user,_proxy_pass); + } + if(_stream->url.user!=NULL&&_stream->url.pass!=NULL){ + ret|=op_sb_append_basic_auth_header(&_stream->request, + "Authorization",_stream->url.user,_stream->url.pass); + } + /*Always send a Referer [sic] header. + It's common to refuse to serve a resource unless one is present. + We just use the relative "/" URI to suggest we came from the same domain, + as this is the most common check. + This might violate RFC 2616's mandate that the field "MUST NOT be sent if + the Request-URI was obtained from a source that does not have its own + URI, such as input from the user keyboard," but we don't really have any + way to know.*/ + /*TODO: Should we update this on redirects?*/ + ret|=op_sb_append(&_stream->request,"Referer: /\r\n",12); + /*Always send a Range request header to find out if we're seekable. + This requires an HTTP/1.1 server to succeed, but we'll still get what we + want with an HTTP/1.0 server that ignores this request header.*/ + ret|=op_sb_append(&_stream->request,"Range: bytes=0-\r\n",17); + /*Remember where this is so we can append offsets to it later.*/ + _stream->request_tail=_stream->request.nbuf-4; + ret|=op_sb_append(&_stream->request,"\r\n",2); + if(OP_UNLIKELY(ret<0))return ret; + ret=op_http_conn_write_fully(_stream->conns+0, + _stream->request.buf,_stream->request.nbuf); + if(OP_UNLIKELY(ret<0))return ret; + ret=op_http_conn_read_response(_stream->conns+0,&_stream->response); + if(OP_UNLIKELY(ret<0))return ret; + OP_ALWAYS_TRUE(!ftime(&end_time)); + next=op_http_parse_status_line(&v1_1_compat,&status_code, + _stream->response.buf); + if(OP_UNLIKELY(next==NULL))return OP_FALSE; + if(status_code[0]=='2'){ + opus_int64 content_length; + opus_int64 range_length; + int pipeline; + /*We only understand 20x codes.*/ + if(status_code[1]!='0')return OP_FALSE; + content_length=-1; + range_length=-1; + /*Pipelining is disabled by default.*/ + pipeline=0; + for(;;){ + char *header; + char *cdr; + ret=op_http_get_next_header(&header,&cdr,&next); + if(OP_UNLIKELY(ret<0))return ret; + if(header==NULL)break; + if(strcmp(header,"content-length")==0){ + /*Two Content-Length headers?*/ + if(OP_UNLIKELY(content_length>=0))return OP_FALSE; + content_length=op_http_parse_content_length(cdr); + if(OP_UNLIKELY(content_length<0))return (int)content_length; + /*Make sure the Content-Length and Content-Range headers match.*/ + if(range_length>=0&&OP_UNLIKELY(content_length!=range_length)){ + return OP_FALSE; + } + } + else if(strcmp(header,"content-range")==0){ + opus_int64 range_first; + opus_int64 range_last; + /*Two Content-Range headers?*/ + if(OP_UNLIKELY(range_length>=0))return OP_FALSE; + ret=op_http_parse_content_range(&range_first,&range_last, + &range_length,cdr); + if(OP_UNLIKELY(ret<0))return ret; + /*"A response with satus code 206 (Partial Content) MUST NOTE + include a Content-Range field with a byte-range-resp-spec of + '*'."*/ + if(status_code[2]=='6' + &&(OP_UNLIKELY(range_first<0)||OP_UNLIKELY(range_last<0))){ + return OP_FALSE; + } + /*We asked for the entire resource.*/ + if(range_length>=0){ + /*Quit if we didn't get it.*/ + if(range_last>=0&&OP_UNLIKELY(range_last!=range_length-1)){ + return OP_FALSE; + } + } + /*If there was no length, use the end of the range.*/ + else if(range_last>=0)range_length=range_last+1; + /*Make sure the Content-Length and Content-Range headers match.*/ + if(content_length>=0&&OP_UNLIKELY(content_length!=range_length)){ + return OP_FALSE; + } + } + else if(strcmp(header,"connection")==0){ + /*According to RFC 2616, if an HTTP/1.1 application does not support + pipelining, it "MUST include the 'close' connection option in + every message." + Therefore, if we receive one in the initial response, disable + pipelining entirely. + The server still might support it (e.g., we might just have hit the + request limit for a temporary child process), but if it doesn't + and we assume it does, every time we cross a chunk boundary we'll + error out and reconnect, adding lots of latency.*/ + ret=op_http_parse_connection(cdr); + if(OP_UNLIKELY(ret<0))return ret; + pipeline-=ret; + } + else if(strcmp(header,"server")){ + /*If we got a Server response header, and it wasn't from a known-bad + server, enable pipelining, as long as it's at least HTTP/1.1. + According to RFC 2145, the server is supposed to respond with the + highest minor version number it supports unless it is known or + suspected that we incorrectly implement the HTTP specification. + So it should send back at least HTTP/1.1, despite our HTTP/1.0 + request.*/ + pipeline+=v1_1_compat&&op_http_allow_pipelining(cdr); + } + } + switch(status_code[2]){ + /*200 OK*/ + case '0':break; + /*203 Non-Authoritative Information*/ + case '3':break; + /*204 No Content*/ + case '4':{ + if(content_length>=0&&OP_UNLIKELY(content_length!=0)){ + return OP_FALSE; + } + }break; + /*206 Partial Content*/ + case '6':{ + /*No Content-Range header.*/ + if(OP_UNLIKELY(range_length<0))return OP_FALSE; + content_length=range_length; + /*The server supports range requests for this resource. + We can seek.*/ + _stream->seekable=1; + }break; + /*201 Created: the response "SHOULD include an entity containing a list + of resource characteristics and location(s)," but not an Opus file. + 202 Accepted: the response "SHOULD include an indication of request's + current status and either a pointer to a status monitor or some + estimate of when the user can expect the request to be fulfilled," + but not an Opus file. + 205 Reset Content: this "MUST NOT include an entity," meaning no Opus + file. + 207...209 are not yet defined, so we don't know how to handle them.*/ + default:return OP_FALSE; + } + _stream->content_length=content_length; + _stream->pipeline=pipeline>0; + /*Pipelining requires HTTP/1.1 persistent connections.*/ + if(pipeline)_stream->request.buf[minor_version_pos]='1'; + _stream->conns[0].pos=0; + _stream->conns[0].end_pos=_stream->seekable?content_length:-1; + _stream->conns[0].chunk_size=-1; + _stream->cur_conni=0; + _stream->connect_rate=op_time_diff_ms(&end_time,&start_time); + _stream->connect_rate=OP_MAX(_stream->connect_rate,1); + /*The URL has been successfully opened.*/ + return 0; + } + /*Shouldn't get 1xx; 4xx and 5xx are both failures (and we don't retry). + Everything else is undefined.*/ + else if(status_code[0]!='3')return OP_FALSE; + /*We have some form of redirect request.*/ + /*We only understand 30x codes.*/ + if(status_code[1]!='0')return OP_FALSE; + switch(status_code[2]){ + /*300 Multiple Choices: "If the server has a preferred choice of + representation, it SHOULD include the specific URI for that + representation in the Location field," otherwise we'll fail.*/ + case '0': + /*301 Moved Permanently*/ + case '1': + /*302 Found*/ + case '2': + /*307 Temporary Redirect*/ + case '7':break; + /*305 Use Proxy: "The Location field gives the URI of the proxy." + TODO: This shouldn't actually be that hard to do.*/ + case '5':return OP_EIMPL; + /*303 See Other: "The new URI is not a substitute reference for the + originally requested resource." + 304 Not Modified: "The 304 response MUST NOT contain a message-body." + 306 (Unused) + 308...309 are not yet defined, so we don't know how to handle them.*/ + default:return OP_FALSE; + } + _url=NULL; + for(;;){ + char *header; + char *cdr; + ret=op_http_get_next_header(&header,&cdr,&next); + if(OP_UNLIKELY(ret<0))return ret; + if(header==NULL)break; + if(strcmp(header,"location")==0&&OP_LIKELY(_url==NULL))_url=cdr; + } + if(OP_UNLIKELY(_url==NULL))return OP_FALSE; + /*Don't free last_host if it came from the last URL.*/ + if(last_host!=_proxy_host)_stream->url.host=NULL; + op_parsed_url_clear(&_stream->url); + ret=op_parse_url(&_stream->url,_url); + if(OP_UNLIKELY(ret<0)){ + if(ret==OP_EINVAL)ret=OP_FALSE; + if(last_host!=_proxy_host)_ogg_free((void *)last_host); + return ret; + } + op_http_conn_close(_stream,_stream->conns+0,&_stream->lru_head,1); + } + /*Redirection limit reached.*/ + return OP_FALSE; +} + +static int op_http_conn_send_request(OpusHTTPStream *_stream, + OpusHTTPConn *_conn,opus_int64 _pos,opus_int32 _chunk_size, + int _try_not_to_block){ + opus_int64 next_end; + int ret; + /*We shouldn't have another request outstanding.*/ + OP_ASSERT(_conn->next_pos<0); + /*Build the request to send.*/ + OP_ASSERT(_stream->request.nbuf>=_stream->request_tail); + _stream->request.nbuf=_stream->request_tail; + ret=op_sb_append_nonnegative_int64(&_stream->request,_pos); + ret|=op_sb_append(&_stream->request,"-",1); + if(_chunk_size>0&&OP_ADV_OFFSET(_pos,2*_chunk_size)<_stream->content_length){ + /*We shouldn't be pipelining requests with non-HTTP/1.1 servers.*/ + OP_ASSERT(_stream->pipeline); + next_end=_pos+_chunk_size; + ret|=op_sb_append_nonnegative_int64(&_stream->request,next_end-1); + /*Use a larger chunk size for our next request.*/ + _chunk_size<<=1; + /*But after a while, just request the rest of the resource.*/ + if(_chunk_size>OP_PIPELINE_CHUNK_SIZE_MAX)_chunk_size=-1; + } + else{ + /*Either this was a non-pipelined request or we were close enough to the + end to just ask for the rest.*/ + next_end=-1; + _chunk_size=-1; + } + ret|=op_sb_append(&_stream->request,"\r\n\r\n",4); + if(OP_UNLIKELY(ret<0))return ret; + /*If we don't want to block, check to see if there's enough space in the send + queue. + There's still a chance we might block, even if there is enough space, but + it's a much slimmer one. + Blocking at all is pretty unlikely, as we won't have any requests queued + when _try_not_to_block is set, so if FIONSPACE isn't available (e.g., on + Linux), just skip the test.*/ + if(_try_not_to_block){ +# if defined(FIONSPACE) + int available; + ret=ioctl(_conn->fd,FIONSPACE,&available); + if(ret<0||available<_stream->request.nbuf)return 1; +# endif + } + ret=op_http_conn_write_fully(_conn, + _stream->request.buf,_stream->request.nbuf); + if(OP_UNLIKELY(ret<0))return ret; + _conn->next_pos=_pos; + _conn->next_end=next_end; + /*Save the chunk size to use for the next request.*/ + _conn->chunk_size=_chunk_size; + _conn->nrequests_left--; + return ret; +} + +/*Handles the response to all requests after the first one. + Return: 1 if the connection was closed or timed out, 0 on success, or a + negative value on any other error.*/ +static int op_http_conn_handle_response(OpusHTTPStream *_stream, + OpusHTTPConn *_conn){ + char *next; + char *status_code; + opus_int64 range_length; + opus_int64 next_pos; + opus_int64 next_end; + int ret; + ret=op_http_conn_read_response(_conn,&_stream->response); + /*If the server just closed the connection on us, we may have just hit a + connection re-use limit, so we might want to retry.*/ + if(OP_UNLIKELY(ret<0))return ret==OP_EREAD?1:ret; + next=op_http_parse_status_line(NULL,&status_code,_stream->response.buf); + if(OP_UNLIKELY(next==NULL))return OP_FALSE; + /*We _need_ a 206 Partial Content response. + Nothing else will do.*/ + if(strncmp(status_code,"206",3)!=0){ + /*But on a 408 Request Timeout, we might want to re-try.*/ + return strncmp(status_code,"408",3)==0?1:OP_FALSE; + } + next_pos=_conn->next_pos; + next_end=_conn->next_end; + range_length=-1; + for(;;){ + char *header; + char *cdr; + ret=op_http_get_next_header(&header,&cdr,&next); + if(OP_UNLIKELY(ret<0))return ret; + if(header==NULL)break; + if(strcmp(header,"content-range")==0){ + opus_int64 range_first; + opus_int64 range_last; + /*Two Content-Range headers?*/ + if(OP_UNLIKELY(range_length>=0))return OP_FALSE; + ret=op_http_parse_content_range(&range_first,&range_last, + &range_length,cdr); + if(OP_UNLIKELY(ret<0))return ret; + /*"A response with satus code 206 (Partial Content) MUST NOT + include a Content-Range field with a byte-range-resp-spec of + '*'."*/ + if(OP_UNLIKELY(range_first<0)||OP_UNLIKELY(range_last<0))return OP_FALSE; + /*We also don't want range_last to overflow.*/ + if(OP_UNLIKELY(range_last>=OP_INT64_MAX))return OP_FALSE; + range_last++; + /*Quit if we didn't get the offset we asked for.*/ + if(range_first!=next_pos)return OP_FALSE; + if(next_end<0){ + /*We asked for the rest of the resource.*/ + if(range_length>=0){ + /*Quit if we didn't get it.*/ + if(OP_UNLIKELY(range_last!=range_length))return OP_FALSE; + } + /*If there was no length, use the end of the range.*/ + else range_length=range_last; + next_end=range_last; + } + else{ + if(range_last!=next_end)return OP_FALSE; + /*If there was no length, use the larger of the content length or the + end of this chunk.*/ + if(range_length<0){ + range_length=OP_MAX(range_last,_stream->content_length); + } + } + } + else if(strcmp(header,"content-length")==0){ + opus_int64 content_length; + /*Validate the Content-Length header, if present, against the request we + made.*/ + content_length=op_http_parse_content_length(cdr); + if(OP_UNLIKELY(content_length<0))return (int)content_length; + if(next_end<0){ + /*If we haven't seen the Content-Range header yet and we asked for the + rest of the resource, set next_end, so we can make sure they match + when we do find the Content-Range header.*/ + if(OP_UNLIKELY(next_pos>OP_INT64_MAX-content_length))return OP_FALSE; + next_end=next_pos+content_length; + } + /*Otherwise, make sure they match now.*/ + else if(OP_UNLIKELY(next_end-next_pos!=content_length))return OP_FALSE; + } + else if(strcmp(header,"connection")==0){ + ret=op_http_parse_connection(cdr); + if(OP_UNLIKELY(ret<0))return ret; + /*If the server told us it was going to close the connection, don't make + any more requests.*/ + if(OP_UNLIKELY(ret>0))_conn->nrequests_left=0; + } + } + /*No Content-Range header.*/ + if(OP_UNLIKELY(range_length<0))return OP_FALSE; + /*Update the content_length if necessary.*/ + _stream->content_length=range_length; + _conn->pos=next_pos; + _conn->end_pos=next_end; + _conn->next_pos=-1; + return 0; +} + +/*Open a new connection that will start reading at byte offset _pos. + _pos: The byte offset to start readiny from. + _chunk_size: The number of bytes to ask for in the initial request, or -1 to + request the rest of the resource. + This may be more bytes than remain, in which case it will be + converted into a request for the rest.*/ +static int op_http_conn_open_pos(OpusHTTPStream *_stream, + OpusHTTPConn *_conn,opus_int64 _pos,opus_int32 _chunk_size){ + struct timeb start_time; + struct timeb end_time; + opus_int32 connect_rate; + opus_int32 connect_time; + int ret; + ret=op_http_connect(_stream,_conn,&_stream->addr_info,&start_time); + if(OP_UNLIKELY(ret<0))return ret; + ret=op_http_conn_send_request(_stream,_conn,_pos,_chunk_size,0); + if(OP_UNLIKELY(ret<0))return ret; + ret=op_http_conn_handle_response(_stream,_conn); + if(OP_UNLIKELY(ret!=0))return OP_FALSE; + OP_ALWAYS_TRUE(!ftime(&end_time)); + _stream->cur_conni=_conn-_stream->conns; + OP_ASSERT(_stream->cur_conni>=0&&_stream->cur_conniconnect_rate; + connect_rate+=OP_MAX(connect_time,1)-connect_rate+8>>4; + _stream->connect_rate=connect_rate; + return 0; +} + +/*Read data from the current response body. + If we're pipelining and we get close to the end of this response, queue + another request. + If we've reached the end of this response body, parse the next response and + keep going. + [out] _buf: Returns the data read. + _buf_size: The size of the buffer. + Return: A positive number of bytes read on success. + 0: The connection was closed. + OP_EREAD: There was a fatal read error.*/ +static int op_http_conn_read_body(OpusHTTPStream *_stream, + OpusHTTPConn *_conn,unsigned char *_buf,int _buf_size){ + opus_int64 pos; + opus_int64 end_pos; + opus_int64 next_pos; + opus_int64 content_length; + int nread; + int pipeline; + int ret; + /*Currently this function can only be called on the LRU head. + Otherwise, we'd need a _pnext pointer if we needed to close the connection, + and re-opening it would re-organize the lists.*/ + OP_ASSERT(_stream->lru_head==_conn); + /*We should have filterd out empty reads by this point.*/ + OP_ASSERT(_buf_size>0); + pos=_conn->pos; + end_pos=_conn->end_pos; + next_pos=_conn->next_pos; + pipeline=_stream->pipeline; + content_length=_stream->content_length; + if(end_pos>=0){ + /*Have we reached the end of the current response body?*/ + if(pos>=end_pos){ + OP_ASSERT(content_length>=0); + /*If this was the end of the stream, we're done. + Also return early if a non-blocking read was requested (regardless of + whether we might be able to parse the next response without + blocking).*/ + if(content_length<=end_pos)return 0; + /*Otherwise, start on the next response.*/ + if(next_pos<0){ + /*We haven't issued another request yet.*/ + if(!pipeline||_conn->nrequests_left<=0){ + /*There are two ways to get here: either the server told us it was + going to close the connection after the last request, or we + thought we were reading the whole resource, but it grew while we + were reading it. + The only way the latter could have happened is if content_length + changed while seeking. + Open a new request to read the rest.*/ + OP_ASSERT(_stream->seekable); + /*Try to open a new connection to read another chunk.*/ + op_http_conn_close(_stream,_conn,&_stream->lru_head,1); + /*If we're not pipelining, we should be requesting the rest.*/ + OP_ASSERT(pipeline||_conn->chunk_size==-1); + ret=op_http_conn_open_pos(_stream,_conn,end_pos,_conn->chunk_size); + if(OP_UNLIKELY(ret<0))return OP_EREAD; + } + else{ + /*Issue the request now (better late than never).*/ + ret=op_http_conn_send_request(_stream,_conn,pos,_conn->chunk_size,0); + if(OP_UNLIKELY(ret<0))return OP_EREAD; + next_pos=_conn->next_pos; + OP_ASSERT(next_pos>=0); + } + } + if(next_pos>=0){ + /*We shouldn't be trying to read past the current request body if we're + seeking somewhere else.*/ + OP_ASSERT(next_pos==end_pos); + ret=op_http_conn_handle_response(_stream,_conn); + if(OP_UNLIKELY(ret<0))return OP_EREAD; + if(OP_UNLIKELY(ret>0)&&pipeline){ + opus_int64 next_end; + next_end=_conn->next_end; + /*Our request timed out or the server closed the connection. + Try re-connecting.*/ + op_http_conn_close(_stream,_conn,&_stream->lru_head,1); + /*Unless there's a bug, we should be able to convert + (next_pos,next_end) into valid (_pos,_chunk_size) parameters.*/ + OP_ASSERT(next_end<0 + ||next_end-next_pos>=0&&next_end-next_pos<=0x7FFFFFFF); + ret=op_http_conn_open_pos(_stream,_conn,next_pos, + next_end<0?-1:(opus_int32)(next_end-next_pos)); + if(OP_UNLIKELY(ret<0))return OP_EREAD; + } + else if(OP_UNLIKELY(ret!=0))return OP_EREAD; + } + pos=_conn->pos; + end_pos=_conn->end_pos; + content_length=_stream->content_length; + } + OP_ASSERT(end_pos>pos); + _buf_size=OP_MIN(_buf_size,end_pos-pos); + } + nread=op_http_conn_read(_conn,(char *)_buf,_buf_size,1); + if(OP_UNLIKELY(nread<0))return nread; + pos+=nread; + _conn->pos=pos; + OP_ASSERT(end_pos<0||content_length>=0); + /*TODO: If nrequests_left<=0, we can't make a new request, and there will be + a big pause after we hit the end of the chunk while we open a new + connection. + It would be nice to be able to start that process now, but we have no way + to do it in the background without blocking (even if we could start it, we + have no guarantee the application will return control to us in a + sufficiently timely manner to allow us to complete it, and this is + uncommon enough that it's not worth using threads just for this).*/ + if(end_pos>=0&&end_posnrequests_left>0)){ + opus_int64 request_thresh; + opus_int32 chunk_size; + /*Are we getting close to the end of the current response body? + If so, we should request more data.*/ + request_thresh=_stream->connect_rate*_conn->read_rate>>12; + /*But don't commit ourselves too quickly.*/ + chunk_size=_conn->chunk_size; + if(chunk_size>=0)request_thresh=OP_MIN(chunk_size>>2,request_thresh); + if(end_pos-poschunk_size,1); + if(OP_UNLIKELY(ret<0))return OP_EREAD; + } + } + return nread; +} + +static int op_http_stream_read(void *_stream, + unsigned char *_ptr,int _buf_size){ + OpusHTTPStream *stream; + ptrdiff_t nread; + opus_int64 size; + opus_int64 pos; + int ci; + stream=(OpusHTTPStream *)_stream; + /*Check for an empty read.*/ + if(_buf_size<=0)return 0; + ci=stream->cur_conni; + /*No current connection => EOF.*/ + if(ci<0)return 0; + pos=stream->conns[ci].pos; + size=stream->content_length; + /*Check for EOF.*/ + if(size>=0){ + if(pos>=size)return 0; + /*Check for a short read.*/ + if(_buf_size>size-pos)_buf_size=(int)(size-pos); + } + nread=op_http_conn_read_body(stream,stream->conns+ci,_ptr,_buf_size); + if(OP_UNLIKELY(nread<=0)){ + /*We hit an error or EOF. + Either way, we're done with this connection.*/ + op_http_conn_close(stream,stream->conns+ci,&stream->lru_head,1); + stream->cur_conni=-1; + stream->pos=pos; + } + return nread; +} + +/*Discard data until we reach the _target position. + This destroys the contents of _stream->response.buf, as we need somewhere to + read this data, and that is a convenient place. + _just_read_ahead: Whether or not this is a plain fast-forward. + If 0, we need to issue a new request for a chunk at _target + and discard all the data from our current request(s). + Otherwise, we should be able to reach _target without + issuing any new requests. + _target: The stream position to which to read ahead.*/ +static int op_http_conn_read_ahead(OpusHTTPStream *_stream, + OpusHTTPConn *_conn,int _just_read_ahead,opus_int64 _target){ + opus_int64 pos; + opus_int64 end_pos; + opus_int64 next_pos; + opus_int64 next_end; + ptrdiff_t nread; + int ret; + pos=_conn->pos; + end_pos=_conn->end_pos; + next_pos=_conn->next_pos; + next_end=_conn->next_end; + if(!_just_read_ahead){ + /*We need to issue a new pipelined request. + This is the only case where we allow more than one outstanding request + at a time, so we need to reset next_pos (we'll restore it below if we + did have an outstanding request).*/ + OP_ASSERT(_stream->pipeline); + _conn->next_pos=-1; + ret=op_http_conn_send_request(_stream,_conn,_target, + OP_PIPELINE_CHUNK_SIZE,0); + if(OP_UNLIKELY(ret<0))return ret; + } + /*We can reach the target position by reading forward in the current chunk.*/ + if(_just_read_ahead&&(end_pos<0||_target=0){ + opus_int64 next_next_pos; + opus_int64 next_next_end; + /*We already have a request outstanding. + Finish off the current chunk.*/ + while(posresponse.buf, + (int)OP_MIN(end_pos-pos,_stream->response.cbuf),1); + /*We failed to read ahead.*/ + if(nread<=0)return OP_FALSE; + pos+=nread; + } + OP_ASSERT(pos==end_pos); + if(_just_read_ahead){ + next_next_pos=next_next_end=-1; + end_pos=_target; + } + else{ + OP_ASSERT(_conn->next_pos==_target); + next_next_pos=_target; + next_next_end=_conn->next_end; + _conn->next_pos=next_pos; + _conn->next_end=next_end; + end_pos=next_end; + } + ret=op_http_conn_handle_response(_stream,_conn); + if(OP_UNLIKELY(ret!=0))return OP_FALSE; + _conn->next_pos=next_next_pos; + _conn->next_end=next_next_end; + } + while(posresponse.buf, + (int)OP_MIN(end_pos-pos,_stream->response.cbuf),1); + /*We failed to read ahead.*/ + if(nread<=0)return OP_FALSE; + pos+=nread; + } + OP_ASSERT(pos==end_pos); + if(!_just_read_ahead){ + ret=op_http_conn_handle_response(_stream,_conn); + if(OP_UNLIKELY(ret!=0))return OP_FALSE; + } + else _conn->pos=end_pos; + OP_ASSERT(_conn->pos==_target); + return 0; +} + +static int op_http_stream_seek(void *_stream,opus_int64 _offset,int _whence){ + struct timeb seek_time; + OpusHTTPStream *stream; + OpusHTTPConn *conn; + OpusHTTPConn **pnext; + OpusHTTPConn *close_conn; + OpusHTTPConn **close_pnext; + opus_int64 content_length; + opus_int64 pos; + int pipeline; + int ci; + int ret; + stream=(OpusHTTPStream *)_stream; + if(!stream->seekable)return -1; + content_length=stream->content_length; + /*If we're seekable, we should have gotten a Content-Length.*/ + OP_ASSERT(content_length>=0); + ci=stream->cur_conni; + pos=ci<0?content_length:stream->conns[ci].pos; + switch(_whence){ + case SEEK_SET:{ + /*Check for overflow:*/ + if(_offset<0)return -1; + pos=_offset; + }break; + case SEEK_CUR:{ + /*Check for overflow:*/ + if(_offset<-pos||_offset>OP_INT64_MAX-pos)return -1; + pos+=_offset; + }break; + case SEEK_END:{ + /*Check for overflow:*/ + if(_offset>content_length||_offset=0){ + op_http_conn_read_rate_update(stream->conns+ci); + *&seek_time=*&stream->conns[ci].read_time; + } + else OP_ALWAYS_TRUE(!ftime(&seek_time)); + /*If we seeked past the end of the stream, just disable the active + connection.*/ + if(pos>=content_length){ + stream->cur_conni=-1; + stream->pos=pos; + return 0; + } + /*First try to find a connection we can use without waiting.*/ + pnext=&stream->lru_head; + conn=stream->lru_head; + while(conn!=NULL){ + opus_int64 conn_pos; + opus_int64 end_pos; + int available; + /*If this connection has been dormant too long or has made too many + requests, close it. + This is to prevent us from hitting server limits/firewall timeouts.*/ + if(op_time_diff_ms(&seek_time,&conn->read_time)> + OP_CONNECTION_IDLE_TIMEOUT_MS + ||conn->nrequests_leftpos; + end_pos=conn->end_pos; + if(conn->next_pos>=0){ + OP_ASSERT(end_pos>=0); + OP_ASSERT(conn->next_pos==end_pos); + end_pos=conn->next_end; + } + OP_ASSERT(end_pos<0||conn_pos<=end_pos); + /*Can we quickly read ahead without issuing a new request or waiting for + any more data? + If we have an oustanding request, we'll over-estimate the amount of data + it has available (because we'll count the response headers, too), but + that probably doesn't matter.*/ + if(conn_pos<=pos&&pos-conn_pos<=available&&(end_pos<0||posnext; + conn->next=stream->lru_head; + stream->lru_head=conn; + stream->cur_conni=conn-stream->conns; + return 0; + } + pnext=&conn->next; + conn=conn->next; + } + /*Chances are that didn't work, so now try to find one we can use by reading + ahead a reasonable amount and/or by issuing a new request.*/ + close_pnext=NULL; + close_conn=NULL; + pnext=&stream->lru_head; + conn=stream->lru_head; + pipeline=stream->pipeline; + while(conn!=NULL){ + opus_int64 conn_pos; + opus_int64 end_pos; + opus_int64 read_ahead_thresh; + int available; + int just_read_ahead; + /*Dividing by 2048 instead of 1000 scales this by nearly 1/2, biasing away + from connection re-use (and roughly compensating for the lag required to + reopen the TCP window of a connection that's been idle). + There's no overflow checking here, because it's vanishingly unlikely, and + all it would do is cause us to make poor decisions.*/ + read_ahead_thresh=OP_MAX(OP_READAHEAD_THRESH_MIN, + stream->connect_rate*conn->read_rate>>11); + available=op_http_conn_estimate_available(conn); + conn_pos=conn->pos; + end_pos=conn->end_pos; + if(conn->next_pos>=0){ + OP_ASSERT(end_pos>=0); + OP_ASSERT(conn->next_pos==end_pos); + end_pos=conn->next_end; + } + OP_ASSERT(end_pos<0||conn_pos<=end_pos); + /*Can we quickly read ahead without issuing a new request?*/ + just_read_ahead=conn_pos<=pos&&pos-conn_pos-available<=read_ahead_thresh + &&(end_pos<0||pos=0 + &&end_pos-conn_pos-available<=read_ahead_thresh){ + /*Found a suitable connection to re-use.*/ + ret=op_http_conn_read_ahead(stream,conn,just_read_ahead,pos); + if(OP_UNLIKELY(ret<0)){ + /*The connection might have become stale, so close it and keep going.*/ + op_http_conn_close(stream,conn,pnext,1); + conn=*pnext; + continue; + } + /*Sucessfully resurrected this connection.*/ + *pnext=conn->next; + conn->next=stream->lru_head; + stream->lru_head=conn; + stream->cur_conni=conn-stream->conns; + return 0; + } + close_pnext=pnext; + close_conn=conn; + pnext=&conn->next; + conn=conn->next; + } + /*No suitable connections. + Open a new one.*/ + if(stream->free_head==NULL){ + /*All connections in use. + Expire one of them (we should have already picked which one when scanning + the list).*/ + OP_ASSERT(close_conn!=NULL); + OP_ASSERT(close_pnext!=NULL); + op_http_conn_close(stream,close_conn,close_pnext,1); + } + OP_ASSERT(stream->free_head!=NULL); + conn=stream->free_head; + /*If we can pipeline, only request a chunk of data. + If we're seeking now, there's a good chance we will want to seek again + soon, and this avoids committing this connection to reading the rest of + the stream. + Particularly with SSL or proxies, issuing a new request on the same + connection can be substantially faster than opening a new one. + This also limits the amount of data the server will blast at us on this + connection if we later seek elsewhere and start reading from a different + connection.*/ + ret=op_http_conn_open_pos(stream,conn,pos, + pipeline?OP_PIPELINE_CHUNK_SIZE:-1); + if(OP_UNLIKELY(ret<0)){ + op_http_conn_close(stream,conn,&stream->lru_head,1); + return -1; + } + return 0; +} + +static opus_int64 op_http_stream_tell(void *_stream){ + OpusHTTPStream *stream; + int ci; + stream=(OpusHTTPStream *)_stream; + ci=stream->cur_conni; + return ci<0?stream->pos:stream->conns[ci].pos; +} + +static int op_http_stream_close(void *_stream){ + OpusHTTPStream *stream; + stream=(OpusHTTPStream *)_stream; + if(OP_LIKELY(stream!=NULL)){ + op_http_stream_clear(stream); + _ogg_free(stream); + } + return 0; +} + +static const OpusFileCallbacks OP_HTTP_CALLBACKS={ + op_http_stream_read, + op_http_stream_seek, + op_http_stream_tell, + op_http_stream_close +}; +#endif + +/*The actual URL stream creation function. + This one isn't extensible like the application-level interface, but because + it isn't public, we're free to change it in the future.*/ +static void *op_url_stream_create_impl(OpusFileCallbacks *_cb,const char *_url, + int _skip_certificate_check,const char *_proxy_host,unsigned _proxy_port, + const char *_proxy_user,const char *_proxy_pass){ + const char *path; + /*Check to see if this is a valid file: URL.*/ + path=op_parse_file_url(_url); + if(path!=NULL){ + char *unescaped_path; + void *ret; + unescaped_path=op_string_dup(path); + if(OP_UNLIKELY(unescaped_path==NULL))return NULL; + ret=op_fopen(_cb,op_unescape_url_component(unescaped_path),"rb"); + _ogg_free(unescaped_path); + return ret; + } +#if defined(OP_ENABLE_HTTP) + /*If not, try http/https.*/ + else{ + OpusHTTPStream *stream; + int ret; + stream=(OpusHTTPStream *)_ogg_malloc(sizeof(*stream)); + if(OP_UNLIKELY(stream==NULL))return NULL; + op_http_stream_init(stream); + ret=op_http_stream_open(stream,_url,_skip_certificate_check, + _proxy_host,_proxy_port,_proxy_user,_proxy_pass); + if(OP_UNLIKELY(ret<0)){ + op_http_stream_clear(stream); + _ogg_free(stream); + return NULL; + } + *_cb=*&OP_HTTP_CALLBACKS; + return stream; + } +#else + (void)_skip_certificate_check; + (void)_proxy_host; + (void)_proxy_port; + (void)_proxy_user; + (void)_proxy_pass; + return NULL; +#endif +} + +void *op_url_stream_vcreate(OpusFileCallbacks *_cb, + const char *_url,va_list _ap){ + int skip_certificate_check; + const char *proxy_host; + opus_int32 proxy_port; + const char *proxy_user; + const char *proxy_pass; + skip_certificate_check=0; + proxy_host=NULL; + proxy_port=8080; + proxy_user=NULL; + proxy_pass=NULL; + for(;;){ + ptrdiff_t request; + request=va_arg(_ap,char *)-(char *)NULL; + /*If we hit NULL, we're done processing options.*/ + if(!request)break; + switch(request){ + case OP_SSL_SKIP_CERTIFICATE_CHECK_REQUEST:{ + skip_certificate_check=!!va_arg(_ap,opus_int32); + }break; + case OP_HTTP_PROXY_HOST_REQUEST:{ + proxy_host=va_arg(_ap,const char *); + }break; + case OP_HTTP_PROXY_PORT_REQUEST:{ + proxy_port=va_arg(_ap,opus_int32); + if(proxy_port<0||proxy_port>(opus_int32)65535)return NULL; + }break; + case OP_HTTP_PROXY_USER_REQUEST:{ + proxy_user=va_arg(_ap,const char *); + }break; + case OP_HTTP_PROXY_PASS_REQUEST:{ + proxy_pass=va_arg(_ap,const char *); + }break; + /*Some unknown option.*/ + default:return NULL; + } + } + return op_url_stream_create_impl(_cb,_url,skip_certificate_check, + proxy_host,proxy_port,proxy_user,proxy_pass); +} + +void *op_url_stream_create(OpusFileCallbacks *_cb, + const char *_url,...){ + va_list ap; + va_start(ap,_url); + return op_url_stream_vcreate(_cb,_url,ap); +} diff --git a/code/opusfile-0.2/src/info.c b/code/opusfile-0.2/src/info.c new file mode 100644 index 00000000..62edecdb --- /dev/null +++ b/code/opusfile-0.2/src/info.c @@ -0,0 +1,286 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 2012 * + * by the Xiph.Org Foundation and contributors http://www.xiph.org/ * + * * + ********************************************************************/ +#include "internal.h" +#include +#include + +static unsigned op_parse_uint16le(const unsigned char *_data){ + return _data[0]|_data[1]<<8; +} + +static int op_parse_int16le(const unsigned char *_data){ + int ret; + ret=_data[0]|_data[1]<<8; + return (ret^0x8000)-0x8000; +} + +static opus_uint32 op_parse_uint32le(const unsigned char *_data){ + return _data[0]|_data[1]<<8|_data[2]<<16|_data[3]<<24; +} + +int opus_head_parse(OpusHead *_head,const unsigned char *_data,size_t _len){ + OpusHead head; + if(_len<8)return OP_ENOTFORMAT; + if(memcmp(_data,"OpusHead",8)!=0)return OP_ENOTFORMAT; + if(_len<9)return OP_EBADHEADER; + head.version=_data[8]; + if(head.version>15)return OP_EVERSION; + if(_len<19)return OP_EBADHEADER; + head.channel_count=_data[9]; + head.pre_skip=op_parse_uint16le(_data+10); + head.input_sample_rate=op_parse_uint32le(_data+12); + head.output_gain=op_parse_int16le(_data+16); + head.mapping_family=_data[18]; + if(head.mapping_family==0){ + if(head.channel_count<1||head.channel_count>2)return OP_EBADHEADER; + if(head.version<=1&&_len>19)return OP_EBADHEADER; + head.stream_count=1; + head.coupled_count=head.channel_count-1; + if(_head!=NULL){ + _head->mapping[0]=0; + _head->mapping[1]=1; + } + } + else if(head.mapping_family==1){ + size_t size; + int ci; + if(head.channel_count<1||head.channel_count>8)return OP_EBADHEADER; + size=21+head.channel_count; + if(_lensize)return OP_EBADHEADER; + head.stream_count=_data[19]; + if(head.stream_count<1)return OP_EBADHEADER; + head.coupled_count=_data[20]; + if(head.coupled_count>head.stream_count)return OP_EBADHEADER; + for(ci=0;ci=head.stream_count+head.coupled_count + &&_data[21+ci]!=255){ + return OP_EBADHEADER; + } + } + if(_head!=NULL)memcpy(_head->mapping,_data+21,head.channel_count); + } + /*General purpose players should not attempt to play back content with + channel mapping family 255.*/ + else if(head.mapping_family==255)return OP_EIMPL; + /*No other channel mapping families are currently defined.*/ + else return OP_EBADHEADER; + if(_head!=NULL)memcpy(_head,&head,head.mapping-(unsigned char *)&head); + return 0; +} + +void opus_tags_init(OpusTags *_tags){ + memset(_tags,0,sizeof(*_tags)); +} + +void opus_tags_clear(OpusTags *_tags){ + int i; + for(i=_tags->comments;i-->0;)_ogg_free(_tags->user_comments[i]); + _ogg_free(_tags->user_comments); + _ogg_free(_tags->comment_lengths); + _ogg_free(_tags->vendor); +} + +/*The actual implementation of opus_tags_parse(). + Unlike the public API, this function requires _tags to already be + initialized, modifies its contents before success is guaranteed, and assumes + the caller will clear it on error.*/ +int opus_tags_parse_impl(OpusTags *_tags, + const unsigned char *_data,size_t _len){ + opus_uint32 count; + size_t size; + size_t len; + int ncomments; + int i; + len=_len; + if(len<8)return OP_ENOTFORMAT; + if(memcmp(_data,"OpusTags",8)!=0)return OP_ENOTFORMAT; + if(len<16)return OP_EBADHEADER; + _data+=8; + len-=8; + count=op_parse_uint32le(_data); + _data+=4; + len-=4; + if(count>len)return OP_EBADHEADER; + if(_tags!=NULL){ + char *vendor; + size=count+1; + if(sizevendor=vendor; + } + _data+=count; + len-=count; + if(len<4)return OP_EBADHEADER; + count=op_parse_uint32le(_data); + _data+=4; + len-=4; + /*Check to make sure there's minimally sufficient data left in the packet.*/ + if(count>len>>2)return OP_EBADHEADER; + /*Check for overflow (the API limits this to an int).*/ + if(count>(opus_uint32)INT_MAX-1)return OP_EFAULT; + if(_tags!=NULL){ + size=sizeof(*_tags->comment_lengths)*(count+1); + if(size/sizeof(*_tags->comment_lengths)!=count+1)return OP_EFAULT; + _tags->comment_lengths=(int *)_ogg_malloc(size); + size=sizeof(*_tags->user_comments)*(count+1); + if(size/sizeof(*_tags->user_comments)!=count+1)return OP_EFAULT; + _tags->user_comments=(char **)_ogg_malloc(size); + if(_tags->comment_lengths==NULL||_tags->user_comments==NULL){ + return OP_EFAULT; + } + } + ncomments=(int)count; + for(i=0;ilen>>2)return OP_EBADHEADER; + count=op_parse_uint32le(_data); + _data+=4; + len-=4; + if(count>len)return OP_EBADHEADER; + /*Check for overflow (the API limits this to an int).*/ + if(count>(opus_uint32)INT_MAX)return OP_EFAULT; + if(_tags!=NULL){ + _tags->comment_lengths[i]=(int)count; + size=count+1; + if(sizeuser_comments[i]=(char *)_ogg_malloc(size); + if(_tags->user_comments[i]==NULL)return OP_EFAULT; + _tags->comments=i+1; + memcpy(_tags->user_comments[i],_data,count); + _tags->user_comments[i][count]='\0'; + } + _data+=count; + len-=count; + } + if(_tags!=NULL){ + _tags->user_comments[ncomments]=NULL; + _tags->comment_lengths[ncomments]=0; + } + return 0; +} + +int opus_tags_parse(OpusTags *_tags,const unsigned char *_data,size_t _len){ + if(_tags!=NULL){ + OpusTags tags; + int ret; + opus_tags_init(&tags); + ret=opus_tags_parse_impl(&tags,_data,_len); + if(ret<0)opus_tags_clear(&tags); + else *_tags=*&tags; + return ret; + } + else return opus_tags_parse_impl(NULL,_data,_len); +} + +/*Add room for a new comment.*/ +static int op_tags_add_prepare(OpusTags *_tags){ + char **user_comments; + int *comment_lengths; + int ncomments; + ncomments=_tags->comments; + user_comments=_ogg_realloc(_tags->user_comments, + sizeof(*_tags->user_comments)*(ncomments+2)); + if(OP_UNLIKELY(user_comments==NULL))return OP_EFAULT; + _tags->user_comments=user_comments; + comment_lengths=_ogg_realloc(_tags->comment_lengths, + sizeof(*_tags->comment_lengths)*(ncomments+2)); + if(OP_UNLIKELY(comment_lengths==NULL))return OP_EFAULT; + _tags->comment_lengths=comment_lengths; + comment_lengths[ncomments]=comment_lengths[ncomments+1]=0; + /*Our caller will always set user_comments[ncomments].*/ + user_comments[ncomments+1]=NULL; + return 0; +} + +int opus_tags_add(OpusTags *_tags,const char *_tag,const char *_value){ + char *comment; + int tag_len; + int value_len; + int ncomments; + int ret; + ret=op_tags_add_prepare(_tags); + if(OP_UNLIKELY(ret<0))return ret; + tag_len=strlen(_tag); + value_len=strlen(_value); + ncomments=_tags->comments; + /*+2 for '=' and '\0'.*/ + _tags->user_comments[ncomments]=comment= + (char *)_ogg_malloc(sizeof(*comment)*(tag_len+value_len+2)); + if(OP_UNLIKELY(comment==NULL))return OP_EFAULT; + _tags->comment_lengths[ncomments]=tag_len+value_len+1; + memcpy(comment,_tag,sizeof(*comment)*tag_len); + comment[tag_len]='='; + memcpy(comment+tag_len+1,_value,sizeof(*comment)*(value_len+1)); + return 0; +} + +int opus_tags_add_comment(OpusTags *_tags,const char *_comment){ + char *comment; + int ncomments; + int comment_len; + int ret; + ret=op_tags_add_prepare(_tags); + if(OP_UNLIKELY(ret<0))return ret; + comment_len=strlen(_comment); + ncomments=_tags->comments; + _tags->user_comments[ncomments]=comment=(char *) + _ogg_malloc(sizeof(*_tags->user_comments[ncomments])*(comment_len+1)); + if(OP_UNLIKELY(comment==NULL))return OP_EFAULT; + _tags->comment_lengths[ncomments]=comment_len; + memcpy(comment,_comment,sizeof(*comment)*(comment_len+1)); + return 0; +} + +/*Is _a a "tag=value" comment whose tag matches _b? + 0 if it is, a non-zero value otherwise.*/ +static int op_tagcompare(const char *_a,const char *_b,int _n){ + return op_strncasecmp(_a,_b,_n)||_a[_n]!='='; +} + +const char *opus_tags_query(const OpusTags *_tags,const char *_tag,int _count){ + char **user_comments; + int tag_len; + int found; + int ncomments; + int ci; + tag_len=strlen(_tag); + ncomments=_tags->comments; + user_comments=_tags->user_comments; + found=0; + for(ci=0;cicomments; + user_comments=_tags->user_comments; + found=0; + for(ci=0;ci='a'&&a<='z')a-='a'-'A'; + if(b>='a'&&b<='z')b-='a'-'A'; + d=a-b; + if(d)return d; + } + return 0; +} diff --git a/code/opusfile-0.2/src/internal.h b/code/opusfile-0.2/src/internal.h new file mode 100644 index 00000000..79416ae3 --- /dev/null +++ b/code/opusfile-0.2/src/internal.h @@ -0,0 +1,217 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 2012 * + * by the Xiph.Org Foundation and contributors http://www.xiph.org/ * + * * + ********************************************************************/ +#if !defined(_opusfile_internal_h) +# define _opusfile_internal_h (1) + +# if !defined(_REENTRANT) +# define _REENTRANT +# endif +# if !defined(_GNU_SOURCE) +# define _GNU_SOURCE +# endif +# if !defined(_LARGEFILE_SOURCE) +# define _LARGEFILE_SOURCE +# endif +# if !defined(_LARGEFILE64_SOURCE) +# define _LARGEFILE64_SOURCE +# endif +# if !defined(_FILE_OFFSET_BITS) +# define _FILE_OFFSET_BITS 64 +# endif + +# include +# include + +typedef struct OggOpusLink OggOpusLink; +# if defined(OP_FIXED_POINT) +typedef opus_int16 op_sample; +# else +typedef float op_sample; +# endif + +# if OP_GNUC_PREREQ(4,2) +/*Disable excessive warnings about the order of operations.*/ +# pragma GCC diagnostic ignored "-Wparentheses" +# elif defined(_MSC_VER) +/*Disable excessive warnings about the order of operations.*/ +# pragma warning(disable:4554) +/*Disable warnings about "deprecated" POSIX functions.*/ +# pragma warning(disable:4996) +# endif + +# if OP_GNUC_PREREQ(3,0) +/*Another alternative is + (__builtin_constant_p(_x)?!!(_x):__builtin_expect(!!(_x),1)) + but that evaluates _x multiple times, which may be bad.*/ +# define OP_LIKELY(_x) (__builtin_expect(!!(_x),1)) +# define OP_UNLIKELY(_x) (__builtin_expect(!!(_x),0)) +# else +# define OP_LIKELY(_x) (!!(_x)) +# define OP_UNLIKELY(_x) (!!(_x)) +# endif + +# if defined(OP_ENABLE_ASSERTIONS) +# if OP_GNUC_PREREQ(2,5)||__SUNPRO_C>=0x590 +__attribute__((noreturn)) +# endif +void op_fatal_impl(const char *_str,const char *_file,int _line); + +# define OP_FATAL(_str) (op_fatal_impl(_str,__FILE__,__LINE__)) + +# define OP_ASSERT(_cond) \ + do{ \ + if(OP_UNLIKELY(!(_cond)))OP_FATAL("assertion failed: " #_cond); \ + } \ + while(0) +# define OP_ALWAYS_TRUE(_cond) OP_ASSERT(_cond) + +# else +# define OP_FATAL(_str) abort() +# define OP_ASSERT(_cond) +# define OP_ALWAYS_TRUE(_cond) ((void)(_cond)) +# endif + +# define OP_INT64_MAX ((ogg_int64_t)0x7FFFFFFFFFFFFFFFLL) +# define OP_INT64_MIN (-OP_INT64_MAX-1) + +# define OP_MIN(_a,_b) ((_a)<(_b)?(_a):(_b)) +# define OP_MAX(_a,_b) ((_a)>(_b)?(_a):(_b)) +# define OP_CLAMP(_lo,_x,_hi) (OP_MAX(_lo,OP_MIN(_x,_hi))) + +/*Advance a file offset by the given amount, clamping against OP_INT64_MAX. + This is used to advance a known offset by things like OP_CHUNK_SIZE or + OP_PAGE_SIZE_MAX, while making sure to avoid signed overflow. + It assumes that both _offset and _amount are positive.*/ +#define OP_ADV_OFFSET(_offset,_amount) \ + (OP_MIN(_offset,OP_INT64_MAX-(_amount))+(_amount)) + +/*The maximum channel count for any mapping we'll actually decode.*/ +# define OP_NCHANNELS_MAX (8) + +/*Initial state.*/ +# define OP_NOTOPEN (0) +/*We've found the first Opus stream in the first link.*/ +# define OP_PARTOPEN (1) +# define OP_OPENED (2) +/*We've found the first Opus stream in the current link.*/ +# define OP_STREAMSET (3) +/*We've initialized the decoder for the chosen Opus stream in the current + link.*/ +# define OP_INITSET (4) + +/*Information cached for a single link in a chained Ogg Opus file. + We choose the first Opus stream encountered in each link to play back (and + require at least one).*/ +struct OggOpusLink{ + /*The byte offset of the first header page in this link.*/ + opus_int64 offset; + /*The byte offset of the first data page from the chosen Opus stream in this + link (after the headers).*/ + opus_int64 data_offset; + /*The byte offset of the last page from the chosen Opus stream in this link. + This is used when seeking to ensure we find a page before the last one, so + that end-trimming calculations work properly. + This is only valid for seekable sources.*/ + opus_int64 end_offset; + /*The granule position of the last sample. + This is only valid for seekable sources.*/ + ogg_int64_t pcm_end; + /*The granule position before the first sample.*/ + ogg_int64_t pcm_start; + /*The serial number.*/ + ogg_uint32_t serialno; + /*The contents of the info header.*/ + OpusHead head; + /*The contents of the comment header.*/ + OpusTags tags; +}; + +struct OggOpusFile{ + /*The callbacks used to access the data source.*/ + OpusFileCallbacks callbacks; + /*A FILE *, memory bufer, etc.*/ + void *source; + /*Whether or not we can seek with this data source.*/ + int seekable; + /*The number of links in this chained Ogg Opus file.*/ + int nlinks; + /*The cached information from each link in a chained Ogg Opus file. + If source isn't seekable (e.g., it's a pipe), only the current link + appears.*/ + OggOpusLink *links; + /*The number of serial numbers from a single link.*/ + int nserialnos; + /*The capacity of the list of serial numbers from a single link.*/ + int cserialnos; + /*Storage for the list of serial numbers from a single link.*/ + ogg_uint32_t *serialnos; + /*This is the current offset of the data processed by the ogg_sync_state. + After a seek, this should be set to the target offset so that we can track + the byte offsets of subsequent pages. + After a call to op_get_next_page(), this will point to the first byte after + that page.*/ + opus_int64 offset; + /*The total size of this data source, or -1 if it's unseekable.*/ + opus_int64 end; + /*Used to locate pages in the data source.*/ + ogg_sync_state oy; + /*One of OP_NOTOPEN, OP_PARTOPEN, OP_OPENED, OP_STREAMSET, OP_INITSET.*/ + int ready_state; + /*The current link being played back.*/ + int cur_link; + /*The number of decoded samples to discard from the start of decoding.*/ + opus_int32 cur_discard_count; + /*The granule position of the previous packet (current packet start time).*/ + ogg_int64_t prev_packet_gp; + /*The number of bytes read since the last bitrate query, including framing.*/ + opus_int64 bytes_tracked; + /*The number of samples decoded since the last bitrate query.*/ + ogg_int64_t samples_tracked; + /*Takes physical pages and welds them into a logical stream of packets.*/ + ogg_stream_state os; + /*Re-timestamped packets from a single page. + Buffering these relies on the undocumented libogg behavior that ogg_packet + pointers remain valid until the next page is submitted to the + ogg_stream_state they came from.*/ + ogg_packet op[255]; + /*The index of the next packet to return.*/ + int op_pos; + /*The total number of packets available.*/ + int op_count; + /*Central working state for the packet-to-PCM decoder.*/ + OpusMSDecoder *od; + /*The stream count used to initialize the decoder.*/ + int od_stream_count; + /*The coupled stream count used to initialize the decoder.*/ + int od_coupled_count; + /*The channel count used to initialize the decoder.*/ + int od_channel_count; + /*The channel mapping used to initialize the decoder.*/ + unsigned char od_mapping[OP_NCHANNELS_MAX]; + /*The buffered data for one decoded packet.*/ + op_sample *od_buffer; + /*The current position in the decoded buffer.*/ + int od_buffer_pos; + /*The number of valid samples in the decoded buffer.*/ + int od_buffer_size; + /*Internal state for dithering float->short output.*/ +#if !defined(OP_FIXED_POINT) + float dither_a[OP_NCHANNELS_MAX*4]; + float dither_b[OP_NCHANNELS_MAX*4]; + int dither_mute; + opus_uint32 dither_seed; +#endif +}; + +int op_strncasecmp(const char *_a,const char *_b,int _n); + +#endif diff --git a/code/opusfile-0.2/src/opusfile.c b/code/opusfile-0.2/src/opusfile.c new file mode 100644 index 00000000..812c2c45 --- /dev/null +++ b/code/opusfile-0.2/src/opusfile.c @@ -0,0 +1,2994 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 1994-2012 * + * by the Xiph.Org Foundation and contributors http://www.xiph.org/ * + * * + ******************************************************************** + + function: stdio-based convenience library for opening/seeking/decoding + last mod: $Id: vorbisfile.c 17573 2010-10-27 14:53:59Z xiphmont $ + + ********************************************************************/ +#include "internal.h" +#include +#include +#include +#include +#include +#include + +#include "opusfile.h" + +/*This implementation is largely based off of libvorbisfile. + All of the Ogg bits work roughly the same, though I have made some + "improvements" that have not been folded back there, yet.*/ + +/*A 'chained bitstream' is an Ogg Opus bitstream that contains more than one + logical bitstream arranged end to end (the only form of Ogg multiplexing + supported by this library. + Grouping (parallel multiplexing) is not supported, except to the extent that + if there are multiple logical Ogg streams in a single link of the chain, we + will ignore all but the first Opus stream we find.*/ + +/*An Ogg Opus file can be played beginning to end (streamed) without worrying + ahead of time about chaining (see opusdec from the opus-tools package). + If we have the whole file, however, and want random access + (seeking/scrubbing) or desire to know the total length/time of a file, we + need to account for the possibility of chaining.*/ + +/*We can handle things a number of ways. + We can determine the entire bitstream structure right off the bat, or find + pieces on demand. + This library determines and caches structure for the entire bitstream, but + builds a virtual decoder on the fly when moving between links in the chain.*/ + +/*There are also different ways to implement seeking. + Enough information exists in an Ogg bitstream to seek to sample-granularity + positions in the output. + Or, one can seek by picking some portion of the stream roughly in the desired + area if we only want coarse navigation through the stream. + We implement and expose both strategies.*/ + +/*The maximum number of bytes in a page (including the page headers).*/ +#define OP_PAGE_SIZE_MAX (65307) +/*The default amount to seek backwards per step when trying to find the + previous page. + This must be at least as large as the maximum size of a page.*/ +#define OP_CHUNK_SIZE (65536) +/*The maximum amount to seek backwards per step when trying to find the + previous page.*/ +#define OP_CHUNK_SIZE_MAX (1024*(opus_int32)1024) +/*A smaller read size is needed for low-rate streaming.*/ +#define OP_READ_SIZE (2048) + +int op_test(OpusHead *_head, + const unsigned char *_initial_data,size_t _initial_bytes){ + ogg_sync_state oy; + char *data; + int err; + /*The first page of a normal Opus file will be at most 57 bytes (27 Ogg + page header bytes + 1 lacing value + 21 Opus header bytes + 8 channel + mapping bytes). + It will be at least 47 bytes (27 Ogg page header bytes + 1 lacing value + + 19 Opus header bytes using channel mapping family 0). + If we don't have at least that much data, give up now.*/ + if(_initial_bytes<47)return OP_FALSE; + /*Only proceed if we start with the magic OggS string. + This is to prevent us spending a lot of time allocating memory and looking + for Ogg pages in non-Ogg files.*/ + if(memcmp(_initial_data,"OggS",4)!=0)return OP_ENOTFORMAT; + ogg_sync_init(&oy); + data=ogg_sync_buffer(&oy,_initial_bytes); + if(data!=NULL){ + ogg_stream_state os; + ogg_page og; + int ret; + memcpy(data,_initial_data,_initial_bytes); + ogg_sync_wrote(&oy,_initial_bytes); + ogg_stream_init(&os,-1); + err=OP_FALSE; + do{ + ogg_packet op; + ret=ogg_sync_pageout(&oy,&og); + /*Ignore holes.*/ + if(ret<0)continue; + /*Stop if we run out of data.*/ + if(!ret)break; + ogg_stream_reset_serialno(&os,ogg_page_serialno(&og)); + ogg_stream_pagein(&os,&og); + /*Only process the first packet on this page (if it's a BOS packet, + it's required to be the only one).*/ + if(ogg_stream_packetout(&os,&op)==1){ + if(op.b_o_s){ + ret=opus_head_parse(_head,op.packet,op.bytes); + /*If this didn't look like Opus, keep going.*/ + if(ret==OP_ENOTFORMAT)continue; + /*Otherwise we're done, one way or another.*/ + err=ret; + } + /*We finished parsing the headers. + There is no Opus to be found.*/ + else err=OP_ENOTFORMAT; + } + } + while(err==OP_FALSE); + ogg_stream_clear(&os); + } + else err=OP_EFAULT; + ogg_sync_clear(&oy); + return err; +} + +/*Many, many internal helpers. + The intention is not to be confusing. + Rampant duplication and monolithic function implementation (though we do have + some large, omnibus functions still) would be harder to understand anyway. + The high level functions are last. + Begin grokking near the end of the file if you prefer to read things + top-down.*/ + +/*The read/seek functions track absolute position within the stream.*/ + +/*Read a little more data from the file/pipe into the ogg_sync framer. + _nbytes: The maximum number of bytes to read. + Return: A positive number of bytes read on success, 0 on end-of-file, or a + negative value on failure.*/ +static int op_get_data(OggOpusFile *_of,int _nbytes){ + unsigned char *buffer; + int nbytes; + OP_ASSERT(_nbytes>0); + buffer=(unsigned char *)ogg_sync_buffer(&_of->oy,_nbytes); + nbytes=(int)(*_of->callbacks.read)(_of->source,buffer,_nbytes); + OP_ASSERT(nbytes<=_nbytes); + if(OP_LIKELY(nbytes>0))ogg_sync_wrote(&_of->oy,nbytes); + return nbytes; +} + +/*Save a tiny smidge of verbosity to make the code more readable.*/ +static int op_seek_helper(OggOpusFile *_of,opus_int64 _offset){ + if(_offset==_of->offset)return 0; + if(_of->callbacks.seek==NULL|| + (*_of->callbacks.seek)(_of->source,_offset,SEEK_SET)){ + return OP_EREAD; + } + _of->offset=_offset; + ogg_sync_reset(&_of->oy); + return 0; +} + +/*Get the current position indicator of the underlying source. + This should be the same as the value reported by tell().*/ +static opus_int64 op_position(OggOpusFile *_of){ + /*The current position indicator is _not_ simply offset. + We may also have unprocessed, buffered data in the sync state.*/ + return _of->offset+_of->oy.fill-_of->oy.returned; +} + +/*From the head of the stream, get the next page. + _boundary specifies if the function is allowed to fetch more data from the + stream (and how much) or only use internally buffered data. + _boundary: -1: Unbounded search. + 0: Read no additional data. + Use only cached data. + n: Search for the start of a new page up to file position n. + Return: n>=0: Found a page at absolute offset n. + OP_FALSE: Hit the _boundary limit. + OP_EREAD: An underlying read operation failed. + OP_BADLINK: We hit end-of-file before reaching _boundary.*/ +static opus_int64 op_get_next_page(OggOpusFile *_of,ogg_page *_og, + opus_int64 _boundary){ + for(;;){ + int more; + if(_boundary>0&&_of->offset>=_boundary)return OP_FALSE; + more=ogg_sync_pageseek(&_of->oy,_og); + /*Skipped (-more) bytes.*/ + if(OP_UNLIKELY(more<0))_of->offset-=more; + else if(more==0){ + int read_nbytes; + int ret; + /*Send more paramedics.*/ + if(!_boundary)return OP_FALSE; + if(_boundary<0)read_nbytes=OP_READ_SIZE; + else{ + opus_int64 position; + position=op_position(_of); + if(position>=_boundary)return OP_FALSE; + read_nbytes=(int)OP_MIN(_boundary-position,OP_READ_SIZE); + } + ret=op_get_data(_of,read_nbytes); + if(OP_UNLIKELY(ret<0))return OP_EREAD; + if(OP_UNLIKELY(ret==0)){ + /*Only fail cleanly on EOF if we didn't have a known boundary. + Otherwise, we should have been able to reach that boundary, and this + is a fatal error.*/ + return OP_UNLIKELY(_boundary<0)?OP_FALSE:OP_EBADLINK; + } + } + else{ + /*Got a page. + Return the offset at the page beginning, advance the internal offset + past the page end.*/ + opus_int64 page_offset; + page_offset=_of->offset; + _of->offset+=more; + return page_offset; + } + } +} + +static int op_add_serialno(ogg_page *_og, + ogg_uint32_t **_serialnos,int *_nserialnos,int *_cserialnos){ + ogg_uint32_t *serialnos; + int nserialnos; + int cserialnos; + ogg_uint32_t s; + s=ogg_page_serialno(_og); + serialnos=*_serialnos; + nserialnos=*_nserialnos; + cserialnos=*_cserialnos; + if(OP_UNLIKELY(nserialnos>=cserialnos)){ + if(OP_UNLIKELY(cserialnos>INT_MAX-1>>1))return OP_EFAULT; + cserialnos=2*cserialnos+1; + OP_ASSERT(nserialnos=OP_PAGE_SIZE_MAX); + begin=OP_MAX(begin-chunk_size,0); + ret=op_seek_helper(_of,begin); + if(OP_UNLIKELY(ret<0))return ret; + search_start=begin; + while(_of->offsetsearch_start=search_start; + _sr->offset=_offset=llret; + _sr->serialno=serialno; + OP_ASSERT(_of->offset-_offset>=0); + OP_ASSERT(_of->offset-_offset<=OP_PAGE_SIZE_MAX); + _sr->size=(opus_int32)(_of->offset-_offset); + _sr->gp=ogg_page_granulepos(&og); + /*If this page is from the stream we're looking for, remember it.*/ + if(serialno==_serialno){ + preferred_found=1; + *&preferred_sr=*_sr; + } + if(!op_lookup_serialno(serialno,_serialnos,_nserialnos)){ + /*We fell off the end of the link, which means we seeked back too far + and shouldn't have been looking in that link to begin with. + If we found the preferred serial number, forget that we saw it.*/ + preferred_found=0; + } + search_start=llret+1; + } + /*We started from the beginning of the stream and found nothing. + This should be impossible unless the contents of the source changed out + from under us after we read from it.*/ + if(OP_UNLIKELY(!begin)&&OP_UNLIKELY(_offset<0))return OP_EBADLINK; + /*Bump up the chunk size. + This is mildly helpful when seeks are very expensive (http).*/ + chunk_size=OP_MIN(2*chunk_size,OP_CHUNK_SIZE_MAX); + /*Avoid quadratic complexity if we hit an invalid patch of the file.*/ + end=OP_MIN(begin+OP_PAGE_SIZE_MAX-1,original_end); + } + while(_offset<0); + if(preferred_found)*_sr=*&preferred_sr; + return 0; +} + +/*Find the last page beginning before _offset with the given serial number and + a valid granule position. + Unlike the above search, this continues until it finds such a page, but does + not stray outside the current link. + We could implement it (inefficiently) by calling op_get_prev_page_serial() + repeatedly until it returned a page that had both our preferred serial + number and a valid granule position, but doing it with a separate function + allows us to avoid repeatedly re-scanning valid pages from other streams as + we seek-back-and-read-forward. + [out] _gp: Returns the granule position of the page that was found on + success. + _offset: The _offset before which to find a page. + Any page returned will consist of data entirely before _offset. + _serialno: The target serial number. + _serialnos: The list of serial numbers in the link that contains the + preferred serial number. + _nserialnos: The number of serial numbers in the current link. + Return: The offset of the page on success, or a negative value on failure. + OP_EREAD: Failed to read more data (error or EOF). + OP_EBADLINK: We couldn't find a page even after seeking back past the + beginning of the link.*/ +static opus_int64 op_get_last_page(OggOpusFile *_of,ogg_int64_t *_gp, + opus_int64 _offset,ogg_uint32_t _serialno, + const ogg_uint32_t *_serialnos,int _nserialnos){ + ogg_page og; + ogg_int64_t gp; + opus_int64 begin; + opus_int64 end; + opus_int64 original_end; + opus_int32 chunk_size; + /*The target serial number must belong to the current link.*/ + OP_ASSERT(op_lookup_serialno(_serialno,_serialnos,_nserialnos)); + original_end=end=begin=_offset; + _offset=-1; + chunk_size=OP_CHUNK_SIZE; + do{ + int left_link; + int ret; + OP_ASSERT(chunk_size>=OP_PAGE_SIZE_MAX); + begin=OP_MAX(begin-chunk_size,0); + ret=op_seek_helper(_of,begin); + if(OP_UNLIKELY(ret<0))return ret; + left_link=0; + while(_of->offsetready_stateos,ogg_page_serialno(_og)); + ogg_stream_pagein(&_of->os,_og); + if(OP_LIKELY(ogg_stream_packetout(&_of->os,&op)>0)){ + ret=opus_head_parse(_head,op.packet,op.bytes); + /*If it's just a stream type we don't recognize, ignore it.*/ + if(ret==OP_ENOTFORMAT)continue; + /*Everything else is fatal.*/ + if(OP_UNLIKELY(ret<0))return ret; + /*Found a valid Opus header. + Continue setup.*/ + _of->ready_state=OP_STREAMSET; + } + } + /*Get the next page. + No need to clamp the boundary offset against _of->end, as all errors + become OP_ENOTFORMAT.*/ + if(OP_UNLIKELY(op_get_next_page(_of,_og, + OP_ADV_OFFSET(_of->offset,OP_CHUNK_SIZE))<0)){ + return OP_ENOTFORMAT; + } + /*If this page also belongs to our Opus stream, submit it and break.*/ + if(_of->ready_state==OP_STREAMSET + &&_of->os.serialno==ogg_page_serialno(_og)){ + ogg_stream_pagein(&_of->os,_og); + break; + } + } + if(OP_UNLIKELY(_of->ready_state!=OP_STREAMSET))return OP_ENOTFORMAT; + /*Loop getting packets.*/ + for(;;){ + switch(ogg_stream_packetout(&_of->os,&op)){ + case 0:{ + /*Loop getting pages.*/ + for(;;){ + /*No need to clamp the boundary offset against _of->end, as all + errors become OP_EBADHEADER.*/ + if(OP_UNLIKELY(op_get_next_page(_of,_og, + OP_ADV_OFFSET(_of->offset,OP_CHUNK_SIZE))<0)){ + return OP_EBADHEADER; + } + /*If this page belongs to the correct stream, go parse it.*/ + if(_of->os.serialno==ogg_page_serialno(_og)){ + ogg_stream_pagein(&_of->os,_og); + break; + } + /*If the link ends before we see the Opus comment header, abort.*/ + if(OP_UNLIKELY(ogg_page_bos(_og)))return OP_EBADHEADER; + /*Otherwise, keep looking.*/ + } + }break; + /*We shouldn't get a hole in the headers!*/ + case -1:return OP_EBADHEADER; + default:{ + /*Got a packet. + It should be the comment header.*/ + ret=opus_tags_parse(_tags,op.packet,op.bytes); + if(OP_UNLIKELY(ret<0))return ret; + /*Make sure the page terminated at the end of the comment header. + If there is another packet on the page, or part of a packet, then + reject the stream. + Otherwise seekable sources won't be able to seek back to the start + properly.*/ + ret=ogg_stream_packetout(&_of->os,&op); + if(OP_UNLIKELY(ret!=0) + ||OP_UNLIKELY(_og->header[_og->header_len-1]==255)){ + /*If we fail, the caller assumes our tags are uninitialized.*/ + opus_tags_clear(_tags); + return OP_EBADHEADER; + } + return 0; + } + } + } +} + +static int op_fetch_headers(OggOpusFile *_of,OpusHead *_head, + OpusTags *_tags,ogg_uint32_t **_serialnos,int *_nserialnos, + int *_cserialnos,ogg_page *_og){ + ogg_page og; + int ret; + if(!_og){ + /*No need to clamp the boundary offset against _of->end, as all errors + become OP_ENOTFORMAT.*/ + if(OP_UNLIKELY(op_get_next_page(_of,&og, + OP_ADV_OFFSET(_of->offset,OP_CHUNK_SIZE))<0)){ + return OP_ENOTFORMAT; + } + _og=&og; + } + _of->ready_state=OP_OPENED; + ret=op_fetch_headers_impl(_of,_head,_tags,_serialnos,_nserialnos, + _cserialnos,_og); + /*Revert back from OP_STREAMSET to OP_OPENED on failure, to prevent + double-free of the tags in an unseekable stream.*/ + if(OP_UNLIKELY(ret<0))_of->ready_state=OP_OPENED; + return ret; +} + +/*Granule position manipulation routines. + A granule position is defined to be an unsigned 64-bit integer, with the + special value -1 in two's complement indicating an unset or invalid granule + position. + We are not guaranteed to have an unsigned 64-bit type, so we construct the + following routines that + a) Properly order negative numbers as larger than positive numbers, and + b) Check for underflow or overflow past the special -1 value. + This lets us operate on the full, valid range of granule positions in a + consistent and safe manner. + This full range is organized into distinct regions: + [ -1 (invalid) ][ 0 ... OP_INT64_MAX ][ OP_INT64_MIN ... -2 ][-1 (invalid) ] + + No one should actually use granule positions so large that they're negative, + even if they are technically valid, as very little software handles them + correctly (including most of Xiph.Org's). + This library also refuses to support durations so large they won't fit in a + signed 64-bit integer (to avoid exposing this mess to the application, and + to simplify a good deal of internal arithmetic), so the only way to use them + successfully is if pcm_start is very large. + This means there isn't anything you can do with negative granule positions + that you couldn't have done with purely non-negative ones. + The main purpose of these routines is to allow us to think very explicitly + about the possible failure cases of all granule position manipulations.*/ + +/*Safely adds a small signed integer to a valid (not -1) granule position. + The result can use the full 64-bit range of values (both positive and + negative), but will fail on overflow (wrapping past -1; wrapping past + OP_INT64_MAX is explicitly okay). + [out] _dst_gp: The resulting granule position. + Only modified on success. + _src_gp: The granule position to add to. + This must not be -1. + _delta: The amount to add. + This is allowed to be up to 32 bits to support the maximum + duration of a single Ogg page (255 packets * 120 ms per + packet == 1,468,800 samples at 48 kHz). + Return: 0 on success, or OP_EINVAL if the result would wrap around past -1.*/ +static int op_granpos_add(ogg_int64_t *_dst_gp,ogg_int64_t _src_gp, + opus_int32 _delta){ + /*The code below handles this case correctly, but there's no reason we + should ever be called with these values, so make sure we aren't.*/ + OP_ASSERT(_src_gp!=-1); + if(_delta>0){ + /*Adding this amount to the granule position would overflow its 64-bit + range.*/ + if(OP_UNLIKELY(_src_gp<0)&&OP_UNLIKELY(_src_gp>=-1-_delta))return OP_EINVAL; + if(OP_UNLIKELY(_src_gp>OP_INT64_MAX-_delta)){ + /*Adding this amount to the granule position would overflow the positive + half of its 64-bit range. + Since signed overflow is undefined in C, do it in a way the compiler + isn't allowed to screw up.*/ + _delta-=(opus_int32)(OP_INT64_MAX-_src_gp)+1; + _src_gp=OP_INT64_MIN; + } + } + else if(_delta<0){ + /*Subtracting this amount from the granule position would underflow its + 64-bit range.*/ + if(_src_gp>=0&&OP_UNLIKELY(_src_gp<-_delta))return OP_EINVAL; + if(OP_UNLIKELY(_src_gp da < 0.*/ + da=(OP_INT64_MIN-_gp_a)-1; + /*_gp_b >= 0 => db >= 0.*/ + db=OP_INT64_MAX-_gp_b; + /*Step 2: Check for overflow.*/ + if(OP_UNLIKELY(OP_INT64_MAX+da= 0 => da <= 0*/ + da=_gp_a+OP_INT64_MIN; + /*_gp_b < 0 => db <= 0*/ + db=OP_INT64_MIN-_gp_b; + /*Step 2: Check for overflow.*/ + if(OP_UNLIKELY(da=0)return 1; + /*Else fall through.*/ + } + else if(OP_UNLIKELY(_gp_b<0))return -1; + /*No wrapping case.*/ + return (_gp_a>_gp_b)-(_gp_b>_gp_a); +} + +/*Returns the duration of the packet (in samples at 48 kHz), or a negative + value on error.*/ +static int op_get_packet_duration(const unsigned char *_data,int _len){ + int nframes; + int frame_size; + int nsamples; + nframes=opus_packet_get_nb_frames(_data,_len); + if(OP_UNLIKELY(nframes<0))return OP_EBADPACKET; + frame_size=opus_packet_get_samples_per_frame(_data,48000); + nsamples=nframes*frame_size; + if(OP_UNLIKELY(nsamples>120*48))return OP_EBADPACKET; + return nsamples; +} + +/*This function more properly belongs in info.c, but we define it here to allow + the static granule position manipulation functions to remain static.*/ +ogg_int64_t opus_granule_sample(const OpusHead *_head,ogg_int64_t _gp){ + opus_int32 pre_skip; + pre_skip=_head->pre_skip; + if(_gp!=-1&&op_granpos_add(&_gp,_gp,-pre_skip))_gp=-1; + return _gp; +} + +/*Grab all the packets currently in the stream state, and compute their + durations. + _of->op_count is set to the number of packets collected. + [out] _durations: Returns the durations of the individual packets. + Return: The total duration of all packets, or OP_HOLE if there was a hole.*/ +static opus_int32 op_collect_audio_packets(OggOpusFile *_of, + int _durations[255]){ + opus_int32 total_duration; + int op_count; + /*Count the durations of all packets in the page.*/ + op_count=0; + total_duration=0; + for(;;){ + int ret; + /*Unless libogg is broken, we can't get more than 255 packets from a + single page.*/ + OP_ASSERT(op_count<255); + /*This takes advantage of undocumented libogg behavior that returned + ogg_packet buffers are valid at least until the next page is + submitted. + Relying on this is not too terrible, as _none_ of the Ogg memory + ownership/lifetime rules are well-documented. + But I can read its code and know this will work.*/ + ret=ogg_stream_packetout(&_of->os,_of->op+op_count); + if(!ret)break; + if(OP_UNLIKELY(ret<0)){ + /*We shouldn't get holes in the middle of pages.*/ + OP_ASSERT(op_count==0); + return OP_HOLE; + } + _durations[op_count]=op_get_packet_duration(_of->op[op_count].packet, + _of->op[op_count].bytes); + if(OP_LIKELY(_durations[op_count]>0)){ + /*With at most 255 packets on a page, this can't overflow.*/ + total_duration+=_durations[op_count++]; + } + /*Ignore packets with an invalid TOC sequence.*/ + else if(op_count>0){ + /*But save the granule position, if there was one.*/ + _of->op[op_count-1].granulepos=_of->op[op_count].granulepos; + } + } + _of->op_pos=0; + _of->op_count=op_count; + return total_duration; +} + +/*Starting from current cursor position, get the initial PCM offset of the next + page. + This also validates the granule position on the first page with a completed + audio data packet, as required by the spec. + If this link is completely empty (no pages with completed packets), then this + function sets pcm_start=pcm_end=0 and returns the BOS page of the next link + (if any). + In the seekable case, we initialize pcm_end=-1 before calling this function, + so that later we can detect that the link was empty before calling + op_find_final_pcm_offset(). + [inout] _link: The link for which to find pcm_start. + [out] _og: Returns the BOS page of the next link if this link was empty. + In the unseekable case, we can then feed this to + op_fetch_headers() to start the next link. + The caller may pass NULL (e.g., for seekable streams), in + which case this page will be discarded. + Return: 0 on success, 1 if there is a buffered BOS page available, or a + negative value on unrecoverable error.*/ +static int op_find_initial_pcm_offset(OggOpusFile *_of, + OggOpusLink *_link,ogg_page *_og){ + ogg_page og; + ogg_int64_t pcm_start; + ogg_int64_t prev_packet_gp; + ogg_int64_t cur_page_gp; + ogg_uint32_t serialno; + opus_int32 total_duration; + int durations[255]; + int cur_page_eos; + int op_count; + int pi; + if(_og==NULL)_og=&og; + serialno=_of->os.serialno; + op_count=0; + /*We shouldn't have to initialize total_duration, but gcc is too dumb to + figure out that op_count>0 implies we've been through the whole loop at + least once.*/ + total_duration=0; + do{ + opus_int64 llret; + llret=op_get_next_page(_of,_og,_of->end); + /*We should get a page unless the file is truncated or mangled. + Otherwise there are no audio data packets in the whole logical stream.*/ + if(OP_UNLIKELY(llret<0)){ + /*Fail if there was a read error.*/ + if(llrethead.pre_skip>0)return OP_EBADTIMESTAMP; + /*Set pcm_end and end_offset so we can skip the call to + op_find_final_pcm_offset().*/ + _link->pcm_start=_link->pcm_end=0; + _link->end_offset=_link->data_offset; + return 0; + } + /*Similarly, if we hit the next link in the chain, we've gone too far.*/ + if(OP_UNLIKELY(ogg_page_bos(_og))){ + if(_link->head.pre_skip>0)return OP_EBADTIMESTAMP; + /*Set pcm_end and end_offset so we can skip the call to + op_find_final_pcm_offset().*/ + _link->pcm_end=_link->pcm_start=0; + _link->end_offset=_link->data_offset; + /*Tell the caller we've got a buffered page for them.*/ + return 1; + } + /*Ignore pages from other streams (not strictly necessary, because of the + checks in ogg_stream_pagein(), but saves some work).*/ + if(serialno!=(ogg_uint32_t)ogg_page_serialno(_og))continue; + ogg_stream_pagein(&_of->os,_og); + /*Bitrate tracking: add the header's bytes here. + The body bytes are counted when we consume the packets.*/ + _of->bytes_tracked+=_og->header_len; + /*Count the durations of all packets in the page.*/ + do total_duration=op_collect_audio_packets(_of,durations); + /*Ignore holes.*/ + while(OP_UNLIKELY(total_duration<0)); + op_count=_of->op_count; + } + while(op_count<=0); + /*We found the first page with a completed audio data packet: actually look + at the granule position. + RFC 3533 says, "A special value of -1 (in two's complement) indicates that + no packets finish on this page," which does not say that a granule + position that is NOT -1 indicates that some packets DO finish on that page + (even though this was the intention, libogg itself violated this intention + for years before we fixed it). + The Ogg Opus specification only imposes its start-time requirements + on the granule position of the first page with completed packets, + so we ignore any set granule positions until then.*/ + cur_page_gp=_of->op[op_count-1].granulepos; + /*But getting a packet without a valid granule position on the page is not + okay.*/ + if(cur_page_gp==-1)return OP_EBADTIMESTAMP; + cur_page_eos=_of->op[op_count-1].e_o_s; + if(OP_LIKELY(!cur_page_eos)){ + /*The EOS flag wasn't set. + Work backwards from the provided granule position to get the starting PCM + offset.*/ + if(OP_UNLIKELY(op_granpos_add(&pcm_start,cur_page_gp,-total_duration)<0)){ + /*The starting granule position MUST not be smaller than the amount of + audio on the first page with completed packets.*/ + return OP_EBADTIMESTAMP; + } + } + else{ + /*The first page with completed packets was also the last.*/ + if(OP_LIKELY(op_granpos_add(&pcm_start,cur_page_gp,-total_duration)<0)){ + /*If there's less audio on the page than indicated by the granule + position, then we're doing end-trimming, and the starting PCM offset + is zero by spec mandate.*/ + pcm_start=0; + /*However, the end-trimming MUST not ask us to trim more samples than + exist after applying the pre-skip.*/ + if(OP_UNLIKELY(op_granpos_cmp(cur_page_gp,_link->head.pre_skip)<0)){ + return OP_EBADTIMESTAMP; + } + } + } + /*Timestamp the individual packets.*/ + prev_packet_gp=pcm_start; + for(pi=0;pi0){ + /*If we trimmed the entire packet, stop (the spec says encoders + shouldn't do this, but we support it anyway).*/ + if(OP_UNLIKELY(diff>durations[pi]))break; + _of->op[pi].granulepos=prev_packet_gp=cur_page_gp; + /*Move the EOS flag to this packet, if necessary, so we'll trim the + samples.*/ + _of->op[pi].e_o_s=1; + continue; + } + } + /*Update the granule position as normal.*/ + OP_ALWAYS_TRUE(!op_granpos_add(&_of->op[pi].granulepos, + prev_packet_gp,durations[pi])); + prev_packet_gp=_of->op[pi].granulepos; + } + /*Update the packet count after end-trimming.*/ + _of->op_count=pi; + _of->cur_discard_count=_link->head.pre_skip; + _of->prev_packet_gp=_link->pcm_start=pcm_start; + return 0; +} + +/*Starting from current cursor position, get the final PCM offset of the + previous page. + This also validates the duration of the link, which, while not strictly + required by the spec, we need to ensure duration calculations don't + overflow. + This is only done for seekable sources. + We must validate that op_find_initial_pcm_offset() succeeded for this link + before calling this function, otherwise it will scan the entire stream + backwards until it reaches the start, and then fail.*/ +static int op_find_final_pcm_offset(OggOpusFile *_of, + const ogg_uint32_t *_serialnos,int _nserialnos,OggOpusLink *_link, + opus_int64 _offset,ogg_uint32_t _end_serialno,ogg_int64_t _end_gp, + ogg_int64_t *_total_duration){ + ogg_int64_t total_duration; + ogg_int64_t duration; + ogg_uint32_t cur_serialno; + /*For the time being, fetch end PCM offset the simple way.*/ + cur_serialno=_link->serialno; + if(_end_serialno!=cur_serialno||_end_gp==-1){ + _offset=op_get_last_page(_of,&_end_gp,_offset, + cur_serialno,_serialnos,_nserialnos); + if(OP_UNLIKELY(_offset<0))return (int)_offset; + } + /*At worst we should have found the first page with completed packets.*/ + if(OP_UNLIKELY(_offset<_link->data_offset))return OP_EBADLINK; + /*This implementation requires that the difference between the first and last + granule positions in each link be representable in a signed, 64-bit + number, and that each link also have at least as many samples as the + pre-skip requires.*/ + if(OP_UNLIKELY(op_granpos_diff(&duration,_end_gp,_link->pcm_start)<0) + ||OP_UNLIKELY(duration<_link->head.pre_skip)){ + return OP_EBADTIMESTAMP; + } + /*We also require that the total duration be representable in a signed, + 64-bit number.*/ + duration-=_link->head.pre_skip; + total_duration=*_total_duration; + if(OP_UNLIKELY(OP_INT64_MAX-durationpcm_end=_end_gp; + _link->end_offset=_offset; + return 0; +} + +/*Rescale the number _x from the range [0,_from] to [0,_to]. + _from and _to must be positive.*/ +opus_int64 op_rescale64(opus_int64 _x,opus_int64 _from,opus_int64 _to){ + opus_int64 frac; + opus_int64 ret; + int i; + if(_x>=_from)return _to; + if(_x<=0)return 0; + frac=0; + for(i=0;i<63;i++){ + frac<<=1; + OP_ASSERT(_x<=_from); + if(_x>=_from>>1){ + _x-=_from-_x; + frac|=1; + } + else _x<<=1; + } + ret=0; + for(i=0;i<63;i++){ + if(frac&1)ret=(ret&_to&1)+(ret>>1)+(_to>>1); + else ret>>=1; + frac>>=1; + } + return ret; +} + +/*The minimum granule position spacing allowed for making predictions. + This corresponds to about 1 second of audio at 48 kHz for both Opus and + Vorbis, or one keyframe interval in Theora with the default keyframe spacing + of 256.*/ +#define OP_GP_SPACING_MIN (48000) + +/*Try to estimate the location of the next link using the current seek + records, assuming the initial granule position of any streams we've found is + 0.*/ +static opus_int64 op_predict_link_start(const OpusSeekRecord *_sr,int _nsr, + opus_int64 _searched,opus_int64 _end_searched,opus_int32 _bias){ + opus_int64 bisect; + int sri; + int srj; + /*Require that we be at least OP_CHUNK_SIZE from the end. + We don't require that we be at least OP_CHUNK_SIZE from the beginning, + because if we are we'll just scan forward without seeking.*/ + _end_searched-=OP_CHUNK_SIZE; + if(_searched>=_end_searched)return -1; + bisect=_end_searched; + for(sri=0;sri<_nsr;sri++){ + ogg_int64_t gp1; + ogg_int64_t gp2_min; + ogg_uint32_t serialno1; + opus_int64 offset1; + /*If the granule position is negative, either it's invalid or we'd cause + overflow.*/ + gp1=_sr[sri].gp; + if(gp1<0)continue; + /*We require some minimum distance between granule positions to make an + estimate. + We don't actually know what granule position scheme is being used, + because we have no idea what kind of stream these came from. + Therefore we require a minimum spacing between them, with the + expectation that while bitrates and granule position increments might + vary locally in quite complex ways, they are globally smooth.*/ + if(OP_UNLIKELY(op_granpos_add(&gp2_min,gp1,OP_GP_SPACING_MIN)<0)){ + /*No granule position would satisfy us.*/ + continue; + } + offset1=_sr[sri].offset; + serialno1=_sr[sri].serialno; + for(srj=sri;srj-->0;){ + ogg_int64_t gp2; + opus_int64 offset2; + opus_int64 num; + ogg_int64_t den; + ogg_int64_t ipart; + gp2=_sr[srj].gp; + if(gp20); + if(ipart>0&&(offset2-_searched)/ipart=_end_searched?-1:bisect; +} + +/*Finds each bitstream link, one at a time, using a bisection search. + This has to begin by knowing the offset of the first link's initial page.*/ +static int op_bisect_forward_serialno(OggOpusFile *_of, + opus_int64 _searched,OpusSeekRecord *_sr,int _csr, + ogg_uint32_t **_serialnos,int *_nserialnos,int *_cserialnos){ + ogg_page og; + OggOpusLink *links; + int nlinks; + int clinks; + ogg_uint32_t *serialnos; + int nserialnos; + ogg_int64_t total_duration; + int nsr; + int ret; + links=_of->links; + nlinks=clinks=_of->nlinks; + total_duration=0; + /*We start with one seek record, for the last page in the file. + We build up a list of records for places we seek to during link + enumeration. + This list is kept sorted in reverse order. + We only care about seek locations that were _not_ in the current link, + therefore we can add them one at a time to the end of the list as we + improve the lower bound on the location where the next link starts.*/ + nsr=1; + for(;;){ + opus_int64 end_searched; + opus_int64 bisect; + opus_int64 next; + opus_int64 last; + ogg_int64_t end_offset; + ogg_int64_t end_gp; + int sri; + serialnos=*_serialnos; + nserialnos=*_nserialnos; + if(OP_UNLIKELY(nlinks>=clinks)){ + if(OP_UNLIKELY(clinks>INT_MAX-1>>1))return OP_EFAULT; + clinks=2*clinks+1; + OP_ASSERT(nlinkslinks=links; + } + /*Invariants: + We have the headers and serial numbers for the link beginning at 'begin'. + We have the offset and granule position of the last page in the file + (potentially not a page we care about).*/ + /*Scan the seek records we already have to save us some bisection.*/ + for(sri=0;sri1){ + opus_int64 last_offset; + opus_int64 avg_link_size; + opus_int64 upper_limit; + last_offset=links[nlinks-1].offset; + avg_link_size=last_offset/(nlinks-1); + upper_limit=end_searched-OP_CHUNK_SIZE-avg_link_size; + if(OP_LIKELY(last_offset>_searched-avg_link_size) + &&OP_LIKELY(last_offset>1); + /*If we're within OP_CHUNK_SIZE of the start, scan forward.*/ + if(bisect-_searchedoffset-last>=0); + OP_ASSERT(_of->offset-last<=OP_PAGE_SIZE_MAX); + _sr[nsr].size=(opus_int32)(_of->offset-last); + _sr[nsr].serialno=serialno; + _sr[nsr].gp=gp; + nsr++; + } + } + else{ + _searched=_of->offset; + next_bias=OP_CHUNK_SIZE; + if(serialno==links[nlinks-1].serialno){ + /*This page was from the stream we want, remember it. + If it's the last such page in the link, we won't have to go back + looking for it later.*/ + end_gp=gp; + end_offset=last; + } + } + } + bisect=op_predict_link_start(_sr,nsr,_searched,end_searched,next_bias); + } + /*Bisection point found. + Get the final granule position of the previous link, assuming + op_find_initial_pcm_offset() didn't already determine the link was + empty.*/ + if(OP_LIKELY(links[nlinks-1].pcm_end==-1)){ + if(end_gp==-1){ + /*If we don't know where the end page is, we'll have to seek back and + look for it, starting from the end of the link.*/ + end_offset=next; + /*Also forget the last page we read. + It won't be available after the seek.*/ + last=-1; + } + ret=op_find_final_pcm_offset(_of,serialnos,nserialnos, + links+nlinks-1,end_offset,links[nlinks-1].serialno,end_gp, + &total_duration); + if(OP_UNLIKELY(ret<0))return ret; + } + if(last!=next){ + /*The last page we read was not the first page the next link. + Move the cursor position to the offset of that first page. + This only performs an actual seek if the first page of the next link + does not start at the end of the last page from the current Opus + stream with a valid granule position.*/ + ret=op_seek_helper(_of,next); + if(OP_UNLIKELY(ret<0))return ret; + } + ret=op_fetch_headers(_of,&links[nlinks].head,&links[nlinks].tags, + _serialnos,_nserialnos,_cserialnos,last!=next?NULL:&og); + if(OP_UNLIKELY(ret<0))return ret; + links[nlinks].offset=next; + links[nlinks].data_offset=_of->offset; + links[nlinks].serialno=_of->os.serialno; + links[nlinks].pcm_end=-1; + /*This might consume a page from the next link, however the next bisection + always starts with a seek.*/ + ret=op_find_initial_pcm_offset(_of,links+nlinks,NULL); + if(OP_UNLIKELY(ret<0))return ret; + _searched=_of->offset; + /*Mark the current link count so it can be cleaned up on error.*/ + _of->nlinks=++nlinks; + } + /*Last page is in the starting serialno list, so we've reached the last link. + Now find the last granule position for it (if we didn't the first time we + looked at the end of the stream, and if op_find_initial_pcm_offset() + didn't already determine the link was empty).*/ + if(OP_LIKELY(links[nlinks-1].pcm_end==-1)){ + ret=op_find_final_pcm_offset(_of,serialnos,nserialnos, + links+nlinks-1,_sr[0].offset,_sr[0].serialno,_sr[0].gp,&total_duration); + if(OP_UNLIKELY(ret<0))return ret; + } + /*Trim back the links array if necessary.*/ + links=_ogg_realloc(links,sizeof(*links)*nlinks); + if(OP_LIKELY(links!=NULL))_of->links=links; + /*We also don't need these anymore.*/ + _ogg_free(*_serialnos); + *_serialnos=NULL; + *_cserialnos=*_nserialnos=0; + return 0; +} + +static int op_make_decode_ready(OggOpusFile *_of){ + OpusHead *head; + int li; + int stream_count; + int coupled_count; + int channel_count; + if(_of->ready_state>OP_STREAMSET)return 0; + if(OP_UNLIKELY(_of->ready_stateseekable?_of->cur_link:0; + head=&_of->links[li].head; + stream_count=head->stream_count; + coupled_count=head->coupled_count; + channel_count=head->channel_count; + /*Check to see if the current decoder is compatible with the current link.*/ + if(_of->od!=NULL&&_of->od_stream_count==stream_count + &&_of->od_coupled_count==coupled_count&&_of->od_channel_count==channel_count + &&memcmp(_of->od_mapping,head->mapping, + sizeof(*head->mapping)*channel_count)==0){ + opus_multistream_decoder_ctl(_of->od,OPUS_RESET_STATE); + } + else{ + int err; + opus_multistream_decoder_destroy(_of->od); + _of->od=opus_multistream_decoder_create(48000,channel_count, + stream_count,coupled_count,head->mapping,&err); + if(_of->od==NULL)return OP_EFAULT; + _of->od_stream_count=stream_count; + _of->od_coupled_count=coupled_count; + _of->od_channel_count=channel_count; + memcpy(_of->od_mapping,head->mapping,sizeof(*head->mapping)*channel_count); + } +#if defined(OPUS_SET_GAIN) + opus_multistream_decoder_ctl(_of->od,OPUS_SET_GAIN(head->output_gain)); +#else +/*A fallback that works with both float and fixed-point is a bunch of work, + so just force people to use a sufficiently new version. + This is deployed well enough at this point that this shouldn't be a burden.*/ +# error "libopus 1.0.1 or later required" +#endif + _of->ready_state=OP_INITSET; + _of->bytes_tracked=0; + _of->samples_tracked=0; +#if !defined(OP_FIXED_POINT) + _of->dither_mute=65; + /*Use the serial number for the PRNG seed to get repeatable output for + straight play-throughs.*/ + _of->dither_seed=_of->links[li].serialno; +#endif + return 0; +} + +static int op_open_seekable2_impl(OggOpusFile *_of){ + /*64 seek records should be enough for anybody. + Actually, with a bisection search in a 63-bit range down to OP_CHUNK_SIZE + granularity, much more than enough.*/ + OpusSeekRecord sr[64]; + opus_int64 data_offset; + int ret; + /*We can seek, so set out learning all about this file.*/ + (*_of->callbacks.seek)(_of->source,0,SEEK_END); + _of->offset=_of->end=(*_of->callbacks.tell)(_of->source); + if(OP_UNLIKELY(_of->end<0))return OP_EREAD; + data_offset=_of->links[0].data_offset; + if(OP_UNLIKELY(_of->endend, + _of->links[0].serialno,_of->serialnos,_of->nserialnos); + if(OP_UNLIKELY(ret<0))return ret; + /*If there's any trailing junk, forget about it.*/ + _of->end=sr[0].offset+sr[0].size; + if(OP_UNLIKELY(_of->endserialnos,&_of->nserialnos,&_of->cserialnos); +} + +static int op_open_seekable2(OggOpusFile *_of){ + ogg_sync_state oy_start; + ogg_stream_state os_start; + ogg_packet *op_start; + opus_int64 start_offset; + int start_op_count; + int ret; + /*We're partially open and have a first link header state in storage in _of. + Save off that stream state so we can come back to it.*/ + start_op_count=_of->op_count; + /*This is a bit too large to put on the stack unconditionally.*/ + op_start=(ogg_packet *)_ogg_malloc(sizeof(*op_start)*start_op_count); + if(op_start==NULL)return OP_EFAULT; + *&oy_start=_of->oy; + *&os_start=_of->os; + start_offset=_of->offset; + memcpy(op_start,_of->op,sizeof(*op_start)*start_op_count); + OP_ASSERT((*_of->callbacks.tell)(_of->source)==op_position(_of)); + ogg_sync_init(&_of->oy); + ogg_stream_init(&_of->os,-1); + ret=op_open_seekable2_impl(_of); + /*Restore the old stream state.*/ + ogg_stream_clear(&_of->os); + ogg_sync_clear(&_of->oy); + *&_of->oy=*&oy_start; + *&_of->os=*&os_start; + _of->offset=start_offset; + _of->op_count=start_op_count; + memcpy(_of->op,op_start,sizeof(*_of->op)*start_op_count); + _ogg_free(op_start); + _of->prev_packet_gp=_of->links[0].pcm_start; + _of->cur_discard_count=_of->links[0].head.pre_skip; + if(OP_UNLIKELY(ret<0))return ret; + /*And restore the position indicator.*/ + ret=(*_of->callbacks.seek)(_of->source,op_position(_of),SEEK_SET); + return OP_UNLIKELY(ret<0)?OP_EREAD:0; +} + +/*Clear out the current logical bitstream decoder.*/ +static void op_decode_clear(OggOpusFile *_of){ + /*We don't actually free the decoder. + We might be able to re-use it for the next link.*/ + _of->op_count=0; + _of->od_buffer_size=0; + _of->prev_packet_gp=-1; + if(!_of->seekable){ + OP_ASSERT(_of->ready_state>=OP_INITSET); + opus_tags_clear(&_of->links[0].tags); + } + _of->ready_state=OP_OPENED; +} + +static void op_clear(OggOpusFile *_of){ + OggOpusLink *links; + _ogg_free(_of->od_buffer); + if(_of->od!=NULL)opus_multistream_decoder_destroy(_of->od); + links=_of->links; + if(!_of->seekable){ + if(_of->ready_state>OP_OPENED||_of->ready_state==OP_PARTOPEN){ + opus_tags_clear(&links[0].tags); + } + } + else if(OP_LIKELY(links!=NULL)){ + int nlinks; + int link; + nlinks=_of->nlinks; + for(link=0;linkserialnos); + ogg_stream_clear(&_of->os); + ogg_sync_clear(&_of->oy); + if(_of->callbacks.close!=NULL)(*_of->callbacks.close)(_of->source); +} + +static int op_open1(OggOpusFile *_of, + void *_source,const OpusFileCallbacks *_cb, + const unsigned char *_initial_data,size_t _initial_bytes){ + ogg_page og; + ogg_page *pog; + int seekable; + int ret; + memset(_of,0,sizeof(*_of)); + _of->end=-1; + _of->source=_source; + *&_of->callbacks=*_cb; + /*At a minimum, we need to be able to read data.*/ + if(OP_UNLIKELY(_of->callbacks.read==NULL))return OP_EREAD; + /*Initialize the framing state.*/ + ogg_sync_init(&_of->oy); + /*Perhaps some data was previously read into a buffer for testing against + other stream types. + Allow initialization from this previously read data (especially as we may + be reading from a non-seekable stream). + This requires copying it into a buffer allocated by ogg_sync_buffer() and + doesn't support seeking, so this is not a good mechanism to use for + decoding entire files from RAM.*/ + if(_initial_bytes>0){ + char *buffer; + buffer=ogg_sync_buffer(&_of->oy,_initial_bytes); + memcpy(buffer,_initial_data,_initial_bytes*sizeof(*buffer)); + ogg_sync_wrote(&_of->oy,_initial_bytes); + } + /*Can we seek? + Stevens suggests the seek test is portable.*/ + seekable=_cb->seek!=NULL&&(*_cb->seek)(_source,0,SEEK_CUR)!=-1; + /*If seek is implemented, tell must also be implemented.*/ + if(seekable){ + if(OP_UNLIKELY(_of->callbacks.tell==NULL))return OP_EINVAL; + else{ + opus_int64 pos; + pos=(*_of->callbacks.tell)(_of->source); + /*If the current position is not equal to the initial bytes consumed, + absolute seeking will not work.*/ + if(OP_UNLIKELY(pos!=(opus_int64)_initial_bytes))return OP_EINVAL; + } + } + _of->seekable=seekable; + /*Don't seek yet. + Set up a 'single' (current) logical bitstream entry for partial open.*/ + _of->links=(OggOpusLink *)_ogg_malloc(sizeof(*_of->links)); + /*The serialno gets filled in later by op_fetch_headers().*/ + ogg_stream_init(&_of->os,-1); + pog=NULL; + for(;;){ + /*Fetch all BOS pages, store the Opus header and all seen serial numbers, + and load subsequent Opus setup headers.*/ + ret=op_fetch_headers(_of,&_of->links[0].head,&_of->links[0].tags, + &_of->serialnos,&_of->nserialnos,&_of->cserialnos,pog); + if(OP_UNLIKELY(ret<0))break; + _of->nlinks=1; + _of->links[0].offset=0; + _of->links[0].data_offset=_of->offset; + _of->links[0].pcm_end=-1; + _of->links[0].serialno=_of->os.serialno; + /*Fetch the initial PCM offset.*/ + ret=op_find_initial_pcm_offset(_of,_of->links,&og); + if(seekable||OP_LIKELY(ret<=0))break; + /*This link was empty, but we already have the BOS page for the next one in + og. + We can't seek, so start processing the next link right now.*/ + opus_tags_clear(&_of->links[0].tags); + _of->nlinks=0; + if(!seekable)_of->cur_link++; + pog=&og; + } + if(OP_UNLIKELY(ret<0)){ + /*Don't auto-close the stream on failure.*/ + _of->callbacks.close=NULL; + op_clear(_of); + } + else _of->ready_state=OP_PARTOPEN; + return ret; +} + +static int op_open2(OggOpusFile *_of){ + int ret; + OP_ASSERT(_of->ready_state==OP_PARTOPEN); + if(_of->seekable){ + _of->ready_state=OP_OPENED; + ret=op_open_seekable2(_of); + } + else ret=0; + if(OP_LIKELY(ret>=0)){ + /*We have buffered packets from op_find_initial_pcm_offset(). + Move to OP_INITSET so we can use them.*/ + _of->ready_state=OP_STREAMSET; + ret=op_make_decode_ready(_of); + if(OP_LIKELY(ret>=0))return 0; + } + /*Don't auto-close the stream on failure.*/ + _of->callbacks.close=NULL; + op_clear(_of); + return ret; +} + +OggOpusFile *op_test_callbacks(void *_source,const OpusFileCallbacks *_cb, + const unsigned char *_initial_data,size_t _initial_bytes,int *_error){ + OggOpusFile *of; + int ret; + of=(OggOpusFile *)_ogg_malloc(sizeof(*of)); + ret=OP_EFAULT; + if(OP_LIKELY(of!=NULL)){ + ret=op_open1(of,_source,_cb,_initial_data,_initial_bytes); + if(OP_LIKELY(ret>=0)){ + if(_error!=NULL)*_error=0; + return of; + } + _ogg_free(of); + } + if(_error!=NULL)*_error=ret; + return NULL; +} + +OggOpusFile *op_open_callbacks(void *_source,const OpusFileCallbacks *_cb, + const unsigned char *_initial_data,size_t _initial_bytes,int *_error){ + OggOpusFile *of; + of=op_test_callbacks(_source,_cb,_initial_data,_initial_bytes,_error); + if(OP_LIKELY(of!=NULL)){ + int ret; + ret=op_open2(of); + if(OP_LIKELY(ret>=0))return of; + if(_error!=NULL)*_error=ret; + _ogg_free(of); + } + return NULL; +} + +/*Convenience routine to clean up from failure for the open functions that + create their own streams.*/ +static OggOpusFile *op_open_close_on_failure(void *_source, + const OpusFileCallbacks *_cb,int *_error){ + OggOpusFile *of; + if(OP_UNLIKELY(_source==NULL)){ + if(_error!=NULL)*_error=OP_EFAULT; + return NULL; + } + of=op_open_callbacks(_source,_cb,NULL,0,_error); + if(OP_UNLIKELY(of==NULL))(*_cb->close)(_source); + return of; +} + +OggOpusFile *op_open_file(const char *_path,int *_error){ + OpusFileCallbacks cb; + return op_open_close_on_failure(op_fopen(&cb,_path,"rb"),&cb,_error); +} + +OggOpusFile *op_open_memory(const unsigned char *_data,size_t _size, + int *_error){ + OpusFileCallbacks cb; + return op_open_close_on_failure(op_mem_stream_create(&cb,_data,_size),&cb, + _error); +} + +OggOpusFile *op_vopen_url(const char *_url,int *_error,va_list _ap){ + OpusFileCallbacks cb; + return op_open_close_on_failure(op_url_stream_vcreate(&cb,_url,_ap),&cb, + _error); +} + +OggOpusFile *op_open_url(const char *_url,int *_error,...){ + va_list ap; + va_start(ap,_error); + return op_vopen_url(_url,_error,ap); +} + +/*Convenience routine to clean up from failure for the open functions that + create their own streams.*/ +static OggOpusFile *op_test_close_on_failure(void *_source, + const OpusFileCallbacks *_cb,int *_error){ + OggOpusFile *of; + if(OP_UNLIKELY(_source==NULL)){ + if(_error!=NULL)*_error=OP_EFAULT; + return NULL; + } + of=op_test_callbacks(_source,_cb,NULL,0,_error); + if(OP_UNLIKELY(of==NULL))(*_cb->close)(_source); + return of; +} + +OggOpusFile *op_test_file(const char *_path,int *_error){ + OpusFileCallbacks cb; + return op_test_close_on_failure(op_fopen(&cb,_path,"rb"),&cb,_error); +} + +OggOpusFile *op_test_memory(const unsigned char *_data,size_t _size, + int *_error){ + OpusFileCallbacks cb; + return op_test_close_on_failure(op_mem_stream_create(&cb,_data,_size),&cb, + _error); +} + +OggOpusFile *op_vtest_url(const char *_url,int *_error,va_list _ap){ + OpusFileCallbacks cb; + return op_test_close_on_failure(op_url_stream_vcreate(&cb,_url,_ap),&cb, + _error); +} + +OggOpusFile *op_test_url(const char *_url,int *_error,...){ + va_list ap; + va_start(ap,_error); + return op_vtest_url(_url,_error,ap); +} + +int op_test_open(OggOpusFile *_of){ + int ret; + if(OP_UNLIKELY(_of->ready_state!=OP_PARTOPEN))return OP_EINVAL; + ret=op_open2(_of); + /*op_open2() will clear this structure on failure. + Reset its contents to prevent double-frees in op_free().*/ + if(OP_UNLIKELY(ret<0))memset(_of,0,sizeof(*_of)); + return ret; +} + +void op_free(OggOpusFile *_of){ + if(OP_LIKELY(_of!=NULL)){ + op_clear(_of); + _ogg_free(_of); + } +} + +int op_seekable(OggOpusFile *_of){ + return _of->seekable; +} + +int op_link_count(OggOpusFile *_of){ + return _of->nlinks; +} + +ogg_uint32_t op_serialno(OggOpusFile *_of,int _li){ + if(OP_UNLIKELY(_li>=_of->nlinks))_li=_of->nlinks-1; + if(!_of->seekable)_li=0; + return _of->links[_li<0?_of->cur_link:_li].serialno; +} + +int op_channel_count(OggOpusFile *_of,int _li){ + return op_head(_of,_li)->channel_count; +} + +opus_int64 op_raw_total(OggOpusFile *_of,int _li){ + if(OP_UNLIKELY(_of->ready_stateseekable) + ||OP_UNLIKELY(_li>=_of->nlinks)){ + return OP_EINVAL; + } + if(_li<0)return _of->end-_of->links[0].offset; + return (_li+1>=_of->nlinks?_of->end:_of->links[_li+1].offset) + -_of->links[_li].offset; +} + +ogg_int64_t op_pcm_total(OggOpusFile *_of,int _li){ + OggOpusLink *links; + ogg_int64_t diff; + int nlinks; + nlinks=_of->nlinks; + if(OP_UNLIKELY(_of->ready_stateseekable) + ||OP_UNLIKELY(_li>=nlinks)){ + return OP_EINVAL; + } + links=_of->links; + /*We verify that the granule position differences are larger than the + pre-skip and that the total duration does not overflow during link + enumeration, so we don't have to check here.*/ + if(_li<0){ + ogg_int64_t pcm_total; + int li; + pcm_total=0; + for(li=0;li=_of->nlinks))_li=_of->nlinks-1; + if(!_of->seekable)_li=0; + return &_of->links[_li<0?_of->cur_link:_li].head; +} + +const OpusTags *op_tags(OggOpusFile *_of,int _li){ + if(OP_UNLIKELY(_li>=_of->nlinks))_li=_of->nlinks-1; + if(!_of->seekable){ + if(_of->ready_stateready_state!=OP_PARTOPEN){ + return NULL; + } + _li=0; + } + else if(_li<0)_li=_of->ready_state>=OP_STREAMSET?_of->cur_link:0; + return &_of->links[_li].tags; +} + +int op_current_link(OggOpusFile *_of){ + if(OP_UNLIKELY(_of->ready_statecur_link; +} + +/*Compute an average bitrate given a byte and sample count. + Return: The bitrate in bits per second.*/ +static opus_int32 op_calc_bitrate(opus_int64 _bytes,ogg_int64_t _samples){ + /*These rates are absurd, but let's handle them anyway.*/ + if(OP_UNLIKELY(_bytes>(OP_INT64_MAX-(_samples>>1))/(48000*8))){ + ogg_int64_t den; + if(OP_UNLIKELY(_bytes/(0x7FFFFFFFF/(48000*8))>=_samples))return 0x7FFFFFFF; + den=_samples/(48000*8); + return (opus_int32)((_bytes+(den>>1))/den); + } + if(OP_UNLIKELY(_samples<=0))return 0x7FFFFFFF; + /*This can't actually overflow in normal operation: even with a pre-skip of + 545 2.5 ms frames with 8 streams running at 1282*8+1 bytes per packet + (1275 byte frames + Opus framing overhead + Ogg lacing values), that all + produce a single sample of decoded output, we still don't top 45 Mbps. + The only way to get bitrates larger than that is with excessive Opus + padding, more encoded streams than output channels, or lots and lots of + Ogg pages with no packets on them.*/ + return (opus_int32)OP_MIN((_bytes*48000*8+(_samples>>1))/_samples,0x7FFFFFFF); +} + +opus_int32 op_bitrate(OggOpusFile *_of,int _li){ + if(OP_UNLIKELY(_of->ready_stateseekable) + ||OP_UNLIKELY(_li>=_of->nlinks)){ + return OP_EINVAL; + } + return op_calc_bitrate(op_raw_total(_of,_li),op_pcm_total(_of,_li)); +} + +opus_int32 op_bitrate_instant(OggOpusFile *_of){ + ogg_int64_t samples_tracked; + opus_int32 ret; + if(OP_UNLIKELY(_of->ready_statesamples_tracked; + if(OP_UNLIKELY(samples_tracked==0))return OP_FALSE; + ret=op_calc_bitrate(_of->bytes_tracked,samples_tracked); + _of->bytes_tracked=0; + _of->samples_tracked=0; + return ret; +} + +/*Fetch and process a page. + This handles the case where we're at a bitstream boundary and dumps the + decoding machine. + If the decoding machine is unloaded, it loads it. + It also keeps prev_packet_gp up to date (seek and read both use this; seek + uses a special hack with _readp). + Return: <0) Error, OP_HOLE (lost packet), or OP_EOF. + 0) Need more data (only if _readp==0). + 1) Got at least one audio data packet.*/ +static int op_fetch_and_process_page(OggOpusFile *_of, + ogg_page *_og,opus_int64 _page_pos,int _readp,int _spanp,int _ignore_holes){ + OggOpusLink *links; + ogg_uint32_t cur_serialno; + int seekable; + int cur_link; + int ret; + if(OP_LIKELY(_of->ready_state>=OP_INITSET) + &&OP_LIKELY(_of->op_pos<_of->op_count)){ + /*We're ready to decode and have at least one packet available already.*/ + return 1; + } + if(!_readp)return 0; + seekable=_of->seekable; + links=_of->links; + cur_link=seekable?_of->cur_link:0; + cur_serialno=links[cur_link].serialno; + /*Handle one page.*/ + for(;;){ + ogg_page og; + OP_ASSERT(_of->ready_state>=OP_OPENED); + /*This loop is not strictly necessary, but there's no sense in doing the + extra checks of the larger loop for the common case in a multiplexed + bistream where the page is simply part of a different logical + bitstream.*/ + do{ + /*If we were given a page to use, use it.*/ + if(_og!=NULL){ + *&og=*_og; + _og=NULL; + } + /*Keep reading until we get a page with the correct serialno.*/ + else _page_pos=op_get_next_page(_of,&og,_of->end); + /*EOF: Leave uninitialized.*/ + if(_page_pos<0)return _page_posready_state>=OP_STREAMSET)){ + if(cur_serialno!=(ogg_uint32_t)ogg_page_serialno(&og)){ + /*Two possibilities: + 1) Another stream is multiplexed into this logical section, or*/ + if(OP_LIKELY(!ogg_page_bos(&og)))continue; + /* 2) Our decoding just traversed a bitstream boundary.*/ + if(!_spanp)return OP_EOF; + if(OP_LIKELY(_of->ready_state>=OP_INITSET))op_decode_clear(_of); + break; + } + } + /*Bitrate tracking: add the header's bytes here. + The body bytes are counted when we consume the packets.*/ + _of->bytes_tracked+=og.header_len; + } + while(0); + /*Do we need to load a new machine before submitting the page? + This is different in the seekable and non-seekable cases. + In the seekable case, we already have all the header information loaded + and cached. + We just initialize the machine with it and continue on our merry way. + In the non-seekable (streaming) case, we'll only be at a boundary if we + just left the previous logical bitstream, and we're now nominally at the + header of the next bitstream.*/ + if(OP_UNLIKELY(_of->ready_statenlinks; + for(li=0;li=nlinks)continue; + cur_serialno=serialno; + _of->cur_link=cur_link=li; + ogg_stream_reset_serialno(&_of->os,serialno); + _of->ready_state=OP_STREAMSET; + /*If we're at the start of this link, initialize the granule position + and pre-skip tracking.*/ + if(_page_pos<=links[cur_link].data_offset){ + _of->prev_packet_gp=links[cur_link].pcm_start; + _of->cur_discard_count=links[cur_link].head.pre_skip; + /*Ignore a hole at the start of a new link (this is common for + streams joined in the middle) or after seeking.*/ + _ignore_holes=1; + } + } + else{ + do{ + /*We're streaming. + Fetch the two header packets, build the info struct.*/ + ret=op_fetch_headers(_of,&links[0].head,&links[0].tags, + NULL,NULL,NULL,&og); + if(OP_UNLIKELY(ret<0))return ret; + /*op_find_initial_pcm_offset() will suppress any initial hole for us, + so no need to set _ignore_holes.*/ + ret=op_find_initial_pcm_offset(_of,links,&og); + if(OP_UNLIKELY(ret<0))return ret; + _of->links[0].serialno=cur_serialno=_of->os.serialno; + _of->cur_link++; + } + /*If the link was empty, keep going, because we already have the + BOS page of the next one in og.*/ + while(OP_UNLIKELY(ret>0)); + /*If we didn't get any packets out of op_find_initial_pcm_offset(), + keep going (this is possible if end-trimming trimmed them all).*/ + if(_of->op_count<=0)continue; + /*Otherwise, we're done.*/ + ret=op_make_decode_ready(_of); + if(OP_UNLIKELY(ret<0))return ret; + return 1; + } + } + /*The buffered page is the data we want, and we're ready for it. + Add it to the stream state.*/ + if(OP_UNLIKELY(_of->ready_state==OP_STREAMSET)){ + ret=op_make_decode_ready(_of); + if(OP_UNLIKELY(ret<0))return ret; + } + /*Extract all the packets from the current page.*/ + ogg_stream_pagein(&_of->os,&og); + if(OP_LIKELY(_of->ready_state>=OP_INITSET)){ + opus_int32 total_duration; + int durations[255]; + int op_count; + total_duration=op_collect_audio_packets(_of,durations); + if(OP_UNLIKELY(total_duration<0)){ + /*Drain the packets from the page anyway.*/ + total_duration=op_collect_audio_packets(_of,durations); + OP_ASSERT(total_duration>=0); + /*Report holes to the caller.*/ + if(!_ignore_holes)return OP_HOLE; + } + op_count=_of->op_count; + /*If we found at least one audio data packet, compute per-packet granule + positions for them.*/ + if(op_count>0){ + ogg_int64_t diff; + ogg_int64_t prev_packet_gp; + ogg_int64_t cur_packet_gp; + ogg_int64_t cur_page_gp; + int cur_page_eos; + int pi; + cur_page_gp=_of->op[op_count-1].granulepos; + cur_page_eos=_of->op[op_count-1].e_o_s; + prev_packet_gp=_of->prev_packet_gp; + if(OP_UNLIKELY(prev_packet_gp==-1)){ + opus_int32 cur_discard_count; + /*This is the first call after a raw seek. + Try to reconstruct prev_packet_gp from scratch.*/ + OP_ASSERT(seekable); + if(OP_UNLIKELY(cur_page_eos)){ + /*If the first page we hit after our seek was the EOS page, and + we didn't start from data_offset or before, we don't have + enough information to do end-trimming. + Proceed to the next link, rather than risk playing back some + samples that shouldn't have been played.*/ + _of->op_count=0; + continue; + } + /*By default discard 80 ms of data after a seek, unless we seek + into the pre-skip region.*/ + cur_discard_count=80*48; + cur_page_gp=_of->op[op_count-1].granulepos; + /*Try to initialize prev_packet_gp. + If the current page had packets but didn't have a granule + position, or the granule position it had was too small (both + illegal), just use the starting granule position for the link.*/ + prev_packet_gp=links[cur_link].pcm_start; + if(OP_LIKELY(cur_page_gp!=-1)){ + op_granpos_add(&prev_packet_gp,cur_page_gp,-total_duration); + } + if(OP_LIKELY(!op_granpos_diff(&diff, + prev_packet_gp,links[cur_link].pcm_start))){ + opus_int32 pre_skip; + /*If we start at the beginning of the pre-skip region, or we're + at least 80 ms from the end of the pre-skip region, we discard + to the end of the pre-skip region. + Otherwise, we still use the 80 ms default, which will discard + past the end of the pre-skip region.*/ + pre_skip=links[cur_link].head.pre_skip; + if(diff>=0&&diff<=OP_MAX(0,pre_skip-80*48)){ + cur_discard_count=pre_skip-(int)diff; + } + } + _of->cur_discard_count=cur_discard_count; + } + if(OP_UNLIKELY(cur_page_gp==-1)){ + /*This page had completed packets but didn't have a valid granule + position. + This is illegal, but we'll try to handle it by continuing to count + forwards from the previous page.*/ + if(op_granpos_add(&cur_page_gp,prev_packet_gp,total_duration)<0){ + /*The timestamp for this page overflowed.*/ + cur_page_gp=links[cur_link].pcm_end; + } + } + /*If we hit the last page, handle end-trimming.*/ + if(OP_UNLIKELY(cur_page_eos) + &&OP_LIKELY(!op_granpos_diff(&diff,cur_page_gp,prev_packet_gp)) + &&OP_LIKELY(diff0){ + /*If we trimmed the entire packet, stop (the spec says encoders + shouldn't do this, but we support it anyway).*/ + if(OP_UNLIKELY(diff>durations[pi]))break; + cur_packet_gp=cur_page_gp; + /*Move the EOS flag to this packet, if necessary, so we'll trim + the samples during decode.*/ + _of->op[pi].e_o_s=1; + } + else{ + /*Update the granule position as normal.*/ + OP_ALWAYS_TRUE(!op_granpos_add(&cur_packet_gp, + cur_packet_gp,durations[pi])); + } + _of->op[pi].granulepos=cur_packet_gp; + OP_ALWAYS_TRUE(!op_granpos_diff(&diff,cur_page_gp,cur_packet_gp)); + } + } + else{ + /*Propagate timestamps to earlier packets. + op_granpos_add(&prev_packet_gp,prev_packet_gp,total_duration) + should succeed and give prev_packet_gp==cur_page_gp. + But we don't bother to check that, as there isn't much we can do + if it's not true. + The only thing we guarantee is that the start and end granule + positions of the packets are valid, and that they are monotonic + within a page. + They might be completely out of range for this link (we'll check + that elsewhere), or non-monotonic between pages.*/ + if(OP_UNLIKELY(op_granpos_add(&prev_packet_gp, + cur_page_gp,-total_duration)<0)){ + /*The starting timestamp for the first packet on this page + underflowed. + This is illegal, but we ignore it.*/ + prev_packet_gp=0; + } + for(pi=0;pi=0); + OP_ALWAYS_TRUE(!op_granpos_add(&cur_packet_gp, + cur_packet_gp,durations[pi])); + _of->op[pi].granulepos=cur_packet_gp; + } + OP_ASSERT(total_duration==0); + } + _of->prev_packet_gp=prev_packet_gp; + _of->op_count=pi; + /*If end-trimming didn't trim all the packets, we're done.*/ + if(OP_LIKELY(pi>0))return 1; + } + } + } +} + +int op_raw_seek(OggOpusFile *_of,opus_int64 _pos){ + int ret; + if(OP_UNLIKELY(_of->ready_stateseekable))return OP_ENOSEEK; + if(OP_UNLIKELY(_pos<0)||OP_UNLIKELY(_pos>_of->end))return OP_EINVAL; + /*Clear out any buffered, decoded data.*/ + op_decode_clear(_of); + _of->bytes_tracked=0; + _of->samples_tracked=0; + ret=op_seek_helper(_of,_pos); + if(OP_UNLIKELY(ret<0))return OP_EREAD; + ret=op_fetch_and_process_page(_of,NULL,-1,1,1,1); + /*If we hit EOF, op_fetch_and_process_page() leaves us uninitialized. + Instead, jump to the end.*/ + if(ret==OP_EOF){ + int cur_link; + op_decode_clear(_of); + cur_link=_of->nlinks-1; + _of->cur_link=cur_link; + _of->prev_packet_gp=_of->links[cur_link].pcm_end; + _of->cur_discard_count=0; + ret=0; + } + else if(ret>0)ret=0; + return ret; +} + +/*Convert a PCM offset relative to the start of the whole stream to a granule + position in an individual link.*/ +static ogg_int64_t op_get_granulepos(const OggOpusFile *_of, + ogg_int64_t _pcm_offset,int *_li){ + OggOpusLink *links; + ogg_int64_t duration; + int nlinks; + int li; + OP_ASSERT(_pcm_offset>=0); + nlinks=_of->nlinks; + links=_of->links; + for(li=0;OP_LIKELY(liOP_INT64_MAX-_pcm_offset)){ + /*Adding this amount to the granule position would overflow the positive + half of its 64-bit range. + Since signed overflow is undefined in C, do it in a way the compiler + isn't allowed to screw up.*/ + _pcm_offset-=OP_INT64_MAX-pcm_start+1; + pcm_start=OP_INT64_MIN; + } + pcm_start+=_pcm_offset; + *_li=li; + return pcm_start; + } + _pcm_offset-=duration; + } + return -1; +} + +/*This controls how close the target has to be to use the current stream + position to subdivide the initial range. + Two minutes seems to be a good default.*/ +#define OP_CUR_TIME_THRESH (120*48*(opus_int32)1000) + +/*Search within link _li for the page with the highest granule position + preceding (or equal to) _target_gp. + There is a danger here: missing pages or incorrect frame number information + in the bitstream could make our task impossible. + Account for that (and report it as an error condition).*/ +static int op_pcm_seek_page(OggOpusFile *_of, + ogg_int64_t _target_gp,int _li){ + OggOpusLink *link; + ogg_page og; + ogg_int64_t pcm_pre_skip; + ogg_int64_t pcm_start; + ogg_int64_t pcm_end; + ogg_int64_t best_gp; + ogg_int64_t diff; + ogg_uint32_t serialno; + opus_int32 pre_skip; + opus_int32 cur_discard_count; + opus_int64 begin; + opus_int64 end; + opus_int64 boundary; + opus_int64 best; + opus_int64 page_offset; + opus_int64 d[3]; + int force_bisect; + int ret; + _of->bytes_tracked=0; + _of->samples_tracked=0; + /*New search algorithm by HB (Nicholas Vinen).*/ + link=_of->links+_li; + best_gp=pcm_start=link->pcm_start; + pcm_end=link->pcm_end; + serialno=link->serialno; + best=begin=link->data_offset; + page_offset=-1; + /*We discard the first 80 ms of data after a seek, so seek back that much + farther. + If we can't, simply seek to the beginning of the link.*/ + if(OP_UNLIKELY(op_granpos_add(&_target_gp,_target_gp,-80*48)<0)){ + _target_gp=pcm_start; + } + /*Special case seeking to the start of the link.*/ + pre_skip=link->head.pre_skip; + OP_ALWAYS_TRUE(!op_granpos_add(&pcm_pre_skip,pcm_start,pre_skip)); + if(op_granpos_cmp(_target_gp,pcm_pre_skip)<0)end=boundary=begin; + else{ + end=boundary=link->end_offset; + /*If we were decoding from this link, we can narrow the range a bit.*/ + if(_li==_of->cur_link&&_of->ready_state>=OP_INITSET){ + opus_int64 offset; + int op_count; + op_count=_of->op_count; + /*The only way the offset can be invalid _and_ we can fail the granule + position checks below is if someone changed the contents of the last + page since we read it. + We'd be within our rights to just return OP_EBADLINK in that case, but + we'll simply ignore the current position instead.*/ + offset=_of->offset; + if(op_count>0&&OP_LIKELY(offset<=end)){ + ogg_int64_t gp; + gp=_of->op[op_count-1].granulepos; + /*Make sure the timestamp is valid. + The granule position might be -1 if we collected the packets from a + page without a granule position after reporting a hole.*/ + if(OP_LIKELY(gp!=-1)&&OP_LIKELY(op_granpos_cmp(pcm_start,gp)<0) + &&OP_LIKELY(op_granpos_cmp(pcm_end,gp)>0)){ + OP_ALWAYS_TRUE(!op_granpos_diff(&diff,gp,_target_gp)); + /*We only actually use the current time if either + a) We can cut off more than half the range, or + b) We're seeking sufficiently close to the current position that + it's likely to be informative. + Otherwise it appears using the whole link range to estimate the + first seek location gives better results, on average.*/ + if(diff<0){ + OP_ASSERT(offset>=begin); + if(offset-begin>=end-begin>>1||diff>-OP_CUR_TIME_THRESH){ + best=begin=offset; + best_gp=pcm_start=gp; + } + } + else if(offset-begin<=end-begin>>1||diff>1; + d[1]=d[2]>>1; + d[2]=end-begin>>1; + if(force_bisect)bisect=begin+(end-begin>>1); + else{ + ogg_int64_t diff2; + OP_ALWAYS_TRUE(!op_granpos_diff(&diff,_target_gp,pcm_start)); + OP_ALWAYS_TRUE(!op_granpos_diff(&diff2,pcm_end,pcm_start)); + /*Take a (pretty decent) guess.*/ + bisect=begin+op_rescale64(diff,diff2,end-begin)-OP_CHUNK_SIZE; + } + if(bisect-OP_CHUNK_SIZEoffset){ + page_offset=-1; + ret=op_seek_helper(_of,bisect); + if(OP_UNLIKELY(ret<0))return ret; + } + chunk_size=OP_CHUNK_SIZE; + next_boundary=boundary; + while(beginoffset; + if(OP_UNLIKELY(op_granpos_cmp(pcm_start,gp)>0) + ||OP_UNLIKELY(op_granpos_cmp(pcm_end,gp)<0)){ + /*Don't let pcm_start get out of range! + That could happen with an invalid timestamp.*/ + break; + } + /*Save the byte offset of the end of the page with this granule + position.*/ + best=begin; + best_gp=pcm_start=gp; + OP_ALWAYS_TRUE(!op_granpos_diff(&diff,_target_gp,pcm_start)); + /*If we're more than a second away from our target, break out and + do another bisection.*/ + if(diff>48000)break; + /*Otherwise, keep scanning forward (do NOT use begin+1).*/ + bisect=begin; + } + else{ + /*We found a page that ends after our target.*/ + /*If we scanned the whole interval before we found it, we're done.*/ + if(bisect<=begin+1)end=begin; + else{ + end=bisect; + /*In later iterations, don't read past the first page we found.*/ + boundary=next_boundary; + /*If we're not making much progress shrinking the interval size, + start forcing straight bisection to limit the worst case.*/ + force_bisect=end-begin>d[0]*2; + /*Don't let pcm_end get out of range! + That could happen with an invalid timestamp.*/ + if(OP_LIKELY(op_granpos_cmp(pcm_end,gp)>0) + &&OP_LIKELY(op_granpos_cmp(pcm_start,gp)<=0)){ + pcm_end=gp; + } + break; + } + } + } + } + } + /*Found our page. + Seek right after it and update prev_packet_gp and cur_discard_count. + This is an easier case than op_raw_seek(), as we don't need to keep any + packets from the page we found.*/ + /*Seek, if necessary.*/ + if(best!=page_offset){ + page_offset=-1; + ret=op_seek_helper(_of,best); + if(OP_UNLIKELY(ret<0))return ret; + } + /*By default, discard 80 ms of data after a seek, unless we seek + into the pre-skip region.*/ + cur_discard_count=80*48; + OP_ALWAYS_TRUE(!op_granpos_diff(&diff,best_gp,pcm_start)); + OP_ASSERT(diff>=0); + /*If we start at the beginning of the pre-skip region, or we're at least + 80 ms from the end of the pre-skip region, we discard to the end of the + pre-skip region. + Otherwise, we still use the 80 ms default, which will discard past the end + of the pre-skip region.*/ + if(diff<=OP_MAX(0,pre_skip-80*48))cur_discard_count=pre_skip-(int)diff; + _of->cur_link=_li; + _of->ready_state=OP_STREAMSET; + _of->prev_packet_gp=best_gp; + _of->cur_discard_count=cur_discard_count; + ogg_stream_reset_serialno(&_of->os,serialno); + ret=op_fetch_and_process_page(_of,page_offset<0?NULL:&og,page_offset,1,0,1); + if(OP_UNLIKELY(ret<=0))return OP_EBADLINK; + /*Verify result.*/ + if(OP_UNLIKELY(op_granpos_cmp(_of->prev_packet_gp,_target_gp)>0)){ + return OP_EBADLINK; + } + return 0; +} + +int op_pcm_seek(OggOpusFile *_of,ogg_int64_t _pcm_offset){ + OggOpusLink *link; + ogg_int64_t pcm_start; + ogg_int64_t target_gp; + ogg_int64_t prev_packet_gp; + ogg_int64_t skip; + ogg_int64_t diff; + int op_count; + int op_pos; + int ret; + int li; + if(OP_UNLIKELY(_of->ready_stateseekable))return OP_ENOSEEK; + if(OP_UNLIKELY(_pcm_offset<0))return OP_EINVAL; + target_gp=op_get_granulepos(_of,_pcm_offset,&li); + if(OP_UNLIKELY(target_gp==-1))return OP_EINVAL; + ret=op_pcm_seek_page(_of,target_gp,li); + /*Now skip samples until we actually get to our target.*/ + link=_of->links+li; + pcm_start=link->pcm_start; + OP_ALWAYS_TRUE(!op_granpos_diff(&_pcm_offset,target_gp,pcm_start)); + /*Figure out where we should skip to.*/ + if(_pcm_offset<=link->head.pre_skip)skip=0; + else skip=OP_MAX(_pcm_offset-80*48,0); + OP_ASSERT(_pcm_offset-skip>=0); + OP_ASSERT(_pcm_offset-skip<0x7FFFFFFF-120*48); + /*Skip packets until we find one with samples past our skip target.*/ + for(;;){ + op_count=_of->op_count; + prev_packet_gp=_of->prev_packet_gp; + for(op_pos=_of->op_pos;op_posop[op_pos].granulepos; + if(OP_LIKELY(!op_granpos_diff(&diff,cur_packet_gp,pcm_start)) + &&diff>skip){ + break; + } + prev_packet_gp=cur_packet_gp; + } + _of->prev_packet_gp=prev_packet_gp; + _of->op_pos=op_pos; + if(op_posskip)return OP_EBADLINK; + OP_ASSERT(_pcm_offset-diff<0x7FFFFFFF); + /*TODO: If there are further holes/illegal timestamps, we still won't decode + to the correct sample. + However, at least op_pcm_tell() will report the correct value immediately + after returning.*/ + _of->cur_discard_count=(opus_int32)(_pcm_offset-diff); + return 0; +} + +opus_int64 op_raw_tell(OggOpusFile *_of){ + if(OP_UNLIKELY(_of->ready_stateoffset; +} + +/*Convert a granule position from a given link to a PCM offset relative to the + start of the whole stream. + For unseekable sources, this gets reset to 0 at the beginning of each link.*/ +static ogg_int64_t op_get_pcm_offset(const OggOpusFile *_of, + ogg_int64_t _gp,int _li){ + OggOpusLink *links; + ogg_int64_t pcm_offset; + ogg_int64_t delta; + int li; + links=_of->links; + pcm_offset=0; + OP_ASSERT(_li<_of->nlinks); + for(li=0;li<_li;li++){ + OP_ALWAYS_TRUE(!op_granpos_diff(&delta, + links[li].pcm_end,links[li].pcm_start)); + delta-=links[li].head.pre_skip; + pcm_offset+=delta; + } + OP_ASSERT(_li>=0); + if(_of->seekable&&OP_UNLIKELY(op_granpos_cmp(_gp,links[_li].pcm_end)>0)){ + _gp=links[_li].pcm_end; + } + if(OP_LIKELY(op_granpos_cmp(_gp,links[_li].pcm_start)>0)){ + OP_ALWAYS_TRUE(!op_granpos_diff(&delta,_gp,links[_li].pcm_start)); + if(deltaready_stateprev_packet_gp; + if(gp==-1)return 0; + nbuffered=OP_MAX(_of->od_buffer_size-_of->od_buffer_pos,0); + OP_ALWAYS_TRUE(!op_granpos_add(&gp,gp,-nbuffered)); + li=_of->seekable?_of->cur_link:0; + if(op_granpos_add(&gp,gp,_of->cur_discard_count)<0){ + gp=_of->links[li].pcm_end; + } + return op_get_pcm_offset(_of,gp,li); +} + +/*Allocate the decoder scratch buffer. + This is done lazily, since if the user provides large enough buffers, we'll + never need it.*/ +static int op_init_buffer(OggOpusFile *_of){ + int nchannels_max; + if(_of->seekable){ + OggOpusLink *links; + int nlinks; + int li; + links=_of->links; + nlinks=_of->nlinks; + nchannels_max=1; + for(li=0;liod_buffer=(op_sample *)_ogg_malloc( + sizeof(*_of->od_buffer)*nchannels_max*120*48); + if(_of->od_buffer==NULL)return OP_EFAULT; + return 0; +} + +/*Read more samples from the stream, using the same API as op_read() or + op_read_float().*/ +static int op_read_native(OggOpusFile *_of, + op_sample *_pcm,int _buf_size,int *_li){ + if(OP_UNLIKELY(_of->ready_stateready_state>=OP_INITSET)){ + int nchannels; + int od_buffer_pos; + int nsamples; + int op_pos; + nchannels=_of->links[_of->seekable?_of->cur_link:0].head.channel_count; + od_buffer_pos=_of->od_buffer_pos; + nsamples=_of->od_buffer_size-od_buffer_pos; + /*If we have buffered samples, return them.*/ + if(OP_UNLIKELY(nsamples>0)){ + if(OP_UNLIKELY(nsamples*nchannels>_buf_size)){ + nsamples=_buf_size/nchannels; + } + memcpy(_pcm,_of->od_buffer+nchannels*od_buffer_pos, + sizeof(*_pcm)*nchannels*nsamples); + od_buffer_pos+=nsamples; + _of->od_buffer_pos=od_buffer_pos; + if(_li!=NULL)*_li=_of->cur_link; + return nsamples; + } + /*If we have buffered packets, decode one.*/ + op_pos=_of->op_pos; + if(OP_LIKELY(op_pos<_of->op_count)){ + ogg_packet *pop; + ogg_int64_t diff; + opus_int32 cur_discard_count; + int duration; + int trimmed_duration; + pop=_of->op+op_pos++; + _of->op_pos=op_pos; + cur_discard_count=_of->cur_discard_count; + duration=op_get_packet_duration(pop->packet,pop->bytes); + /*We don't buffer packets with an invalid TOC sequence.*/ + OP_ASSERT(duration>0); + trimmed_duration=duration; + /*Perform end-trimming.*/ + if(OP_UNLIKELY(pop->e_o_s)){ + if(OP_UNLIKELY(op_granpos_cmp(pop->granulepos, + _of->prev_packet_gp)<=0)){ + trimmed_duration=0; + } + else if(OP_LIKELY(!op_granpos_diff(&diff, + pop->granulepos,_of->prev_packet_gp))){ + trimmed_duration=(int)OP_MIN(diff,trimmed_duration); + } + } + _of->prev_packet_gp=pop->granulepos; + if(OP_UNLIKELY(duration*nchannels>_buf_size)){ + op_sample *buf; + /*If the user's buffer is too small, decode into a scratch buffer.*/ + buf=_of->od_buffer; + if(OP_UNLIKELY(buf==NULL)){ + ret=op_init_buffer(_of); + if(OP_UNLIKELY(ret<0))return ret; + buf=_of->od_buffer; + } +#if defined(OP_FIXED_POINT) + ret=opus_multistream_decode(_of->od, + pop->packet,pop->bytes,buf,120*48,0); +#else + ret=opus_multistream_decode_float(_of->od, + pop->packet,pop->bytes,buf,120*48,0); +#endif + if(OP_UNLIKELY(ret<0))return OP_EBADPACKET; + OP_ASSERT(ret==duration); + /*Perform pre-skip/pre-roll.*/ + od_buffer_pos=(int)OP_MIN(trimmed_duration,cur_discard_count); + cur_discard_count-=od_buffer_pos; + _of->cur_discard_count=cur_discard_count; + _of->od_buffer_pos=od_buffer_pos; + _of->od_buffer_size=trimmed_duration; + /*Update bitrate tracking based on the actual samples we used from + what was decoded.*/ + _of->bytes_tracked+=pop->bytes; + _of->samples_tracked+=trimmed_duration-od_buffer_pos; + /*Don't grab another page yet.*/ + if(OP_LIKELY(od_buffer_posod,pop->packet,pop->bytes, + _pcm,_buf_size/nchannels,0); +#else + ret=opus_multistream_decode_float(_of->od,pop->packet,pop->bytes, + _pcm,_buf_size/nchannels,0); +#endif + if(OP_UNLIKELY(ret<0))return OP_EBADPACKET; + OP_ASSERT(ret==duration); + if(OP_LIKELY(trimmed_duration>0)){ + /*Perform pre-skip/pre-roll.*/ + od_buffer_pos=(int)OP_MIN(trimmed_duration,cur_discard_count); + cur_discard_count-=od_buffer_pos; + _of->cur_discard_count=cur_discard_count; + if(OP_UNLIKELY(od_buffer_pos>0) + &&OP_LIKELY(od_buffer_posbytes_tracked+=pop->bytes; + _of->samples_tracked+=trimmed_duration; + if(OP_LIKELY(trimmed_duration>0)){ + if(_li!=NULL)*_li=_of->cur_link; + return trimmed_duration; + } + } + } + } + } + /*Suck in another page.*/ + ret=op_fetch_and_process_page(_of,NULL,-1,1,1,0); + if(OP_UNLIKELY(ret==OP_EOF)){ + if(_li!=NULL)*_li=_of->cur_link; + return 0; + } + if(OP_UNLIKELY(ret<0))return ret; + } +} + +typedef int (*op_read_filter_func)(OggOpusFile *_of,void *_dst,int _dst_sz, + op_sample *_src,int _nsamples,int _nchannels); + +/*Decode some samples and then apply a custom filter to them. + This is used to convert to different output formats.*/ +static int op_read_native_filter(OggOpusFile *_of,void *_dst,int _dst_sz, + op_read_filter_func _filter,int *_li){ + int ret; + /*Ensure we have some decoded samples in our buffer.*/ + ret=op_read_native(_of,NULL,0,_li); + /*Now apply the filter to them.*/ + if(OP_LIKELY(ret>=0)&&OP_LIKELY(_of->ready_state>=OP_INITSET)){ + int od_buffer_pos; + od_buffer_pos=_of->od_buffer_pos; + ret=_of->od_buffer_size-od_buffer_pos; + if(OP_LIKELY(ret>0)){ + int nchannels; + nchannels=_of->links[_of->seekable?_of->cur_link:0].head.channel_count; + ret=(*_filter)(_of,_dst,_dst_sz, + _of->od_buffer+nchannels*od_buffer_pos,ret,nchannels); + OP_ASSERT(ret>=0); + OP_ASSERT(ret<=_of->od_buffer_size-od_buffer_pos); + od_buffer_pos+=ret; + _of->od_buffer_pos=od_buffer_pos; + } + } + return ret; +} + +#if defined(OP_FIXED_POINT) + +int op_read(OggOpusFile *_of,opus_int16 *_pcm,int _buf_size,int *_li){ + return op_read_native(_of,_pcm,_buf_size,_li); +} + +/*Matrices for downmixing from the supported channel counts to stereo. + The matrices with 5 or more channels are normalized to a total volume of 2.0, + since most mixes sound too quiet if normalized to 1.0 (as there is generally + little volume in the side/rear channels). + Hence we keep the coefficients in Q14, so the downmix values won't overflow a + 32-bit number.*/ +static const opus_int16 OP_STEREO_DOWNMIX_Q14 + [OP_NCHANNELS_MAX-2][OP_NCHANNELS_MAX][2]={ + /*3.0*/ + { + {9598,0},{6786,6786},{0,9598} + }, + /*quadrophonic*/ + { + {6924,0},{0,6924},{5996,3464},{3464,5996} + }, + /*5.0*/ + { + {10666,0},{7537,7537},{0,10666},{9234,5331},{5331,9234} + }, + /*5.1*/ + { + {8668,0},{6129,6129},{0,8668},{7507,4335},{4335,7507},{6129,6129} + }, + /*6.1*/ + { + {7459,0},{5275,5275},{0,7459},{6460,3731},{3731,6460},{4568,4568}, + {5275,5275} + }, + /*7.1*/ + { + {6368,0},{4502,4502},{0,6368},{5515,3183},{3183,5515},{5515,3183}, + {3183,5515},{4502,4502} + } +}; + +static int op_stereo_filter(OggOpusFile *_of,void *_dst,int _dst_sz, + op_sample *_src,int _nsamples,int _nchannels){ + _of=_of; + _nsamples=OP_MIN(_nsamples,_dst_sz>>1); + if(_nchannels==2)memcpy(_dst,_src,_nsamples*2*sizeof(*_src)); + else{ + opus_int16 *dst; + int i; + dst=(opus_int16 *)_dst; + if(_nchannels==1){ + for(i=0;i<_nsamples;i++)dst[2*i+0]=dst[2*i+1]=_src[i]; + } + else{ + for(i=0;i<_nsamples;i++){ + opus_int32 l; + opus_int32 r; + int ci; + l=r=0; + for(ci=0;ci<_nchannels;ci++){ + opus_int32 s; + s=_src[_nchannels*i+ci]; + l+=OP_STEREO_DOWNMIX_Q14[_nchannels-3][ci][0]*s; + r+=OP_STEREO_DOWNMIX_Q14[_nchannels-3][ci][1]*s; + } + dst[2*i+0]=(opus_int16)OP_CLAMP(-32768,l+8192>>14,32767); + dst[2*i+1]=(opus_int16)OP_CLAMP(-32768,r+8192>>14,32767); + } + } + } + return _nsamples; +} + +int op_read_stereo(OggOpusFile *_of,opus_int16 *_pcm,int _buf_size){ + return op_read_native_filter(_of,_pcm,_buf_size,op_stereo_filter,NULL); +} + +# if !defined(OP_DISABLE_FLOAT_API) + +static int op_short2float_filter(OggOpusFile *_of,void *_dst,int _dst_sz, + op_sample *_src,int _nsamples,int _nchannels){ + float *dst; + int i; + _of=_of; + dst=(float *)_dst; + if(OP_UNLIKELY(_nsamples*_nchannels>_dst_sz))_nsamples=_dst_sz/_nchannels; + _dst_sz=_nsamples*_nchannels; + for(i=0;i<_dst_sz;i++)dst[i]=(1.0F/32768)*_src[i]; + return _nsamples; +} + +int op_read_float(OggOpusFile *_of,float *_pcm,int _buf_size,int *_li){ + return op_read_native_filter(_of,_pcm,_buf_size,op_short2float_filter,_li); +} + +static int op_short2float_stereo_filter(OggOpusFile *_of, + void *_dst,int _dst_sz,op_sample *_src,int _nsamples,int _nchannels){ + float *dst; + dst=(float *)_dst; + _nsamples=OP_MIN(_nsamples,_dst_sz>>1); + if(_nchannels==1){ + int i; + _nsamples=op_short2float_filter(_of,dst,_nsamples,_src,_nsamples,1); + for(i=_nsamples;i-->0;)dst[2*i+0]=dst[2*i+1]=dst[i]; + return _nsamples; + } + /*It would be better to convert to floats and then downmix (so that we don't + risk clipping with more than 5 channels), but that would require a large + stack buffer, which is probably not a good idea if you're using the + fixed-point build.*/ + if(_nchannels>2){ + _nsamples=op_stereo_filter(_of,_src,_nsamples*2, + _src,_nsamples,_nchannels); + } + return op_short2float_filter(_of,dst,_dst_sz,_src,_nsamples,2); +} + +int op_read_float_stereo(OggOpusFile *_of,float *_pcm,int _buf_size){ + return op_read_native_filter(_of,_pcm,_buf_size, + op_short2float_stereo_filter,NULL); +} + +# endif + +#else + +# if defined(OP_HAVE_LRINTF) +# include +# define op_float2int(_x) (lrintf(_x)) +# else +# define op_float2int(_x) ((int)((_x)+((_x)<0?-0.5F:0.5F))) +# endif + +/*The dithering code here is adapted from opusdec, part of opus-tools. + It was originally written by Greg Maxwell.*/ + +static opus_uint32 op_rand(opus_uint32 _seed){ + return _seed*96314165+907633515&0xFFFFFFFFU; +} + +/*This implements 16-bit quantization with full triangular dither and IIR noise + shaping. + The noise shaping filters were designed by Sebastian Gesemann, and are based + on the LAME ATH curves with flattening to limit their peak gain to 20 dB. + Everyone else's noise shaping filters are mildly crazy. + The 48 kHz version of this filter is just a warped version of the 44.1 kHz + filter and probably could be improved by shifting the HF shelf up in + frequency a little bit, since 48 kHz has a bit more room and being more + conservative against bat-ears is probably more important than more noise + suppression. + This process can increase the peak level of the signal (in theory by the peak + error of 1.5 +20 dB, though that is unobservably rare). + To avoid clipping, the signal is attenuated by a couple thousands of a dB. + Initially, the approach taken here was to only attenuate by the 99.9th + percentile, making clipping rare but not impossible (like SoX), but the + limited gain of the filter means that the worst case was only two + thousandths of a dB more, so this just uses the worst case. + The attenuation is probably also helpful to prevent clipping in the DAC + reconstruction filters or downstream resampling, in any case.*/ + +#define OP_GAIN (32753.0F) + +#define OP_PRNG_GAIN (1.0F/0xFFFFFFFF) + +/*48 kHz noise shaping filter, sd=2.34.*/ + +static const float OP_FCOEF_B[4]={ + 2.2374F,-0.7339F,-0.1251F,-0.6033F +}; + +static const float OP_FCOEF_A[4]={ + 0.9030F,0.0116F,-0.5853F,-0.2571F +}; + +static void op_shaped_dither16(OggOpusFile *_of,opus_int16 *_dst, + const float *_src,int _nsamples,int _nchannels){ + opus_uint32 seed; + int mute; + int i; + mute=_of->dither_mute; + seed=_of->dither_seed; + /*In order to avoid replacing digital silence with quiet dither noise, we + mute if the output has been silent for a while.*/ + if(mute>64)memset(_of->dither_a,0,sizeof(*_of->dither_a)*4*_nchannels); + for(i=0;i<_nsamples;i++){ + int silent; + int ci; + silent=1; + for(ci=0;ci<_nchannels;ci++){ + float r; + float s; + float err; + int si; + int j; + s=_src[_nchannels*i+ci]; + silent&=s==0; + s*=OP_GAIN; + err=0; + for(j=0;j<4;j++){ + err+=OP_FCOEF_B[j]*_of->dither_b[ci*4+j] + -OP_FCOEF_A[j]*_of->dither_a[ci*4+j]; + } + for(j=3;j-->0;)_of->dither_a[ci*4+j+1]=_of->dither_a[ci*4+j]; + for(j=3;j-->0;)_of->dither_b[ci*4+j+1]=_of->dither_b[ci*4+j]; + _of->dither_a[ci*4]=err; + s-=err; + if(mute>16)r=0; + else{ + seed=op_rand(seed); + r=seed*OP_PRNG_GAIN; + seed=op_rand(seed); + r-=seed*OP_PRNG_GAIN; + } + /*Clamp in float out of paranoia that the input will be > 96 dBFS and + wrap if the integer is clamped.*/ + si=op_float2int(OP_CLAMP(-32768,s+r,32767)); + _dst[_nchannels*i+ci]=(opus_int16)si; + /*Including clipping in the noise shaping is generally disastrous: the + futile effort to restore the clipped energy results in more clipping. + However, small amounts---at the level which could normally be created + by dither and rounding---are harmless and can even reduce clipping + somewhat due to the clipping sometimes reducing the dither + rounding + error.*/ + _of->dither_b[ci*4]=mute>16?0:OP_CLAMP(-1.5F,si-s,1.5F); + } + mute++; + if(!silent)mute=0; + } + _of->dither_mute=OP_MIN(mute,65); + _of->dither_seed=seed; +} + +static int op_float2short_filter(OggOpusFile *_of,void *_dst,int _dst_sz, + op_sample *_src,int _nsamples,int _nchannels){ + opus_int16 *dst; + dst=(opus_int16 *)_dst; + if(OP_UNLIKELY(_nsamples*_nchannels>_dst_sz))_nsamples=_dst_sz/_nchannels; + op_shaped_dither16(_of,dst,_src,_nsamples,_nchannels); + return _nsamples; +} + +int op_read(OggOpusFile *_of,opus_int16 *_pcm,int _buf_size,int *_li){ + return op_read_native_filter(_of,_pcm,_buf_size,op_float2short_filter,_li); +} + +int op_read_float(OggOpusFile *_of,float *_pcm,int _buf_size,int *_li){ + return op_read_native(_of,_pcm,_buf_size,_li); +} + +/*Matrices for downmixing from the supported channel counts to stereo. + The matrices with 5 or more channels are normalized to a total volume of 2.0, + since most mixes sound too quiet if normalized to 1.0 (as there is generally + little volume in the side/rear channels).*/ +static const float OP_STEREO_DOWNMIX[OP_NCHANNELS_MAX-2][OP_NCHANNELS_MAX][2]={ + /*3.0*/ + { + {0.5858F,0.0F},{0.4142F,0.4142F},{0.0F,0.5858F} + }, + /*quadrophonic*/ + { + {0.4226F,0.0F},{0.0F,0.4226F},{0.366F,0.2114F},{0.2114F,0.336F} + }, + /*5.0*/ + { + {0.651F,0.0F},{0.46F,0.46F},{0.0F,0.651F},{0.5636F,0.3254F}, + {0.3254F,0.5636F} + }, + /*5.1*/ + { + {0.529F,0.0F},{0.3741F,0.3741F},{0.0F,0.529F},{0.4582F,0.2645F}, + {0.2645F,0.4582F},{0.3741F,0.3741F} + }, + /*6.1*/ + { + {0.4553F,0.0F},{0.322F,0.322F},{0.0F,0.4553F},{0.3943F,0.2277F}, + {0.2277F,0.3943F},{0.2788F,0.2788F},{0.322F,0.322F} + }, + /*7.1*/ + { + {0.3886F,0.0F},{0.2748F,0.2748F},{0.0F,0.3886F},{0.3366F,0.1943F}, + {0.1943F,0.3366F},{0.3366F,0.1943F},{0.1943F,0.3366F},{0.2748F,0.2748F} + } +}; + +static int op_stereo_filter(OggOpusFile *_of,void *_dst,int _dst_sz, + op_sample *_src,int _nsamples,int _nchannels){ + _nsamples=OP_MIN(_nsamples,_dst_sz>>1); + if(_nchannels==2)memcpy(_dst,_src,_nsamples*2*sizeof(*_src)); + else{ + float *dst; + int i; + dst=(float *)_dst; + if(_nchannels==1){ + for(i=0;i<_nsamples;i++)dst[2*i+0]=dst[2*i+1]=_src[i]; + } + else{ + for(i=0;i<_nsamples;i++){ + float l; + float r; + int ci; + l=r=0; + for(ci=0;ci<_nchannels;ci++){ + l+=OP_STEREO_DOWNMIX[_nchannels-3][ci][0]*_src[_nchannels*i+ci]; + r+=OP_STEREO_DOWNMIX[_nchannels-3][ci][1]*_src[_nchannels*i+ci]; + } + dst[2*i+0]=l; + dst[2*i+1]=r; + } + } + } + return _nsamples; +} + +static int op_float2short_stereo_filter(OggOpusFile *_of, + void *_dst,int _dst_sz,op_sample *_src,int _nsamples,int _nchannels){ + opus_int16 *dst; + dst=(opus_int16 *)_dst; + _nsamples=OP_MIN(_nsamples,_dst_sz>>1); + if(_nchannels==1){ + int i; + op_shaped_dither16(_of,dst,_src,_nsamples,1); + for(i=_nsamples;i-->0;)dst[2*i+0]=dst[2*i+1]=dst[i]; + } + else{ + if(_nchannels>2){ + _nsamples=op_stereo_filter(_of,_src,_nsamples*2, + _src,_nsamples,_nchannels); + } + op_shaped_dither16(_of,dst,_src,_nsamples,_nchannels); + } + return _nsamples; +} + +int op_read_stereo(OggOpusFile *_of,opus_int16 *_pcm,int _buf_size){ + return op_read_native_filter(_of,_pcm,_buf_size, + op_float2short_stereo_filter,NULL); +} + +int op_read_float_stereo(OggOpusFile *_of,float *_pcm,int _buf_size){ + return op_read_native_filter(_of,_pcm,_buf_size,op_stereo_filter,NULL); +} + +#endif diff --git a/code/opusfile-0.2/src/stream.c b/code/opusfile-0.2/src/stream.c new file mode 100644 index 00000000..868b2d51 --- /dev/null +++ b/code/opusfile-0.2/src/stream.c @@ -0,0 +1,184 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 1994-2012 * + * by the Xiph.Org Foundation and contributors http://www.xiph.org/ * + * * + ******************************************************************** + + function: stdio-based convenience library for opening/seeking/decoding + last mod: $Id: vorbisfile.c 17573 2010-10-27 14:53:59Z xiphmont $ + + ********************************************************************/ +#include "internal.h" +#include +#include +#include +#include + +typedef struct OpusMemStream OpusMemStream; + +#define OP_MEM_SIZE_MAX (~(size_t)0>>1) +#define OP_MEM_DIFF_MAX ((ptrdiff_t)OP_MEM_SIZE_MAX) + +/*The context information needed to read from a block of memory as if it were a + file.*/ +struct OpusMemStream{ + /*The block of memory to read from.*/ + const unsigned char *data; + /*The total size of the block. + This must be at most OP_MEM_SIZE_MAX to prevent signed overflow while + seeking.*/ + ptrdiff_t size; + /*The current file position. + This is allowed to be set arbitrarily greater than size (i.e., past the end + of the block, though we will not read data past the end of the block), but + is not allowed to be negative (i.e., before the beginning of the block).*/ + ptrdiff_t pos; +}; + +static int op_fread(void *_stream,unsigned char *_ptr,int _buf_size){ + FILE *stream; + size_t ret; + /*Check for empty read.*/ + if(_buf_size<=0)return 0; + stream=(FILE *)_stream; + ret=fread(_ptr,1,_buf_size,stream); + OP_ASSERT(ret<=(size_t)_buf_size); + /*If ret==0 and !feof(stream), there was a read error.*/ + return ret>0||feof(stream)?(int)ret:OP_EREAD; +} + +static int op_fseek(void *_stream,opus_int64 _offset,int _whence){ +#if defined(__MINGW32__) + return fseeko64((FILE *)_stream,_offset,_whence); +#elif defined(_MSC_VER) + return _fseeki64((FILE *)_stream,_offset,_whence); +#else + return fseeko((FILE *)_stream,(off_t)_offset,_whence); +#endif +} + +static opus_int64 op_ftell(void *_stream){ +#if defined(__MINGW32__) + return ftello64((FILE *)_stream); +#elif defined(_MSC_VER) + return _ftelli64((FILE *)_stream); +#else + return ftello((FILE *)_stream); +#endif +} + +static const OpusFileCallbacks OP_FILE_CALLBACKS={ + op_fread, + op_fseek, + op_ftell, + (op_close_func)fclose +}; + +void *op_fopen(OpusFileCallbacks *_cb,const char *_path,const char *_mode){ + FILE *fp; + fp=fopen(_path,_mode); + if(fp!=NULL)*_cb=*&OP_FILE_CALLBACKS; + return fp; +} + +void *op_fdopen(OpusFileCallbacks *_cb,int _fd,const char *_mode){ + FILE *fp; + fp=fdopen(_fd,_mode); + if(fp!=NULL)*_cb=*&OP_FILE_CALLBACKS; + return fp; +} + +void *op_freopen(OpusFileCallbacks *_cb,const char *_path,const char *_mode, + void *_stream){ + FILE *fp; + fp=freopen(_path,_mode,(FILE *)_stream); + if(fp!=NULL)*_cb=*&OP_FILE_CALLBACKS; + return fp; +} + +static int op_mem_read(void *_stream,unsigned char *_ptr,int _buf_size){ + OpusMemStream *stream; + ptrdiff_t size; + ptrdiff_t pos; + stream=(OpusMemStream *)_stream; + /*Check for empty read.*/ + if(_buf_size<=0)return 0; + size=stream->size; + pos=stream->pos; + /*Check for EOF.*/ + if(pos>=size)return 0; + /*Check for a short read.*/ + _buf_size=(int)OP_MAX(size-pos,_buf_size); + memcpy(_ptr,stream->data+pos,_buf_size); + pos+=_buf_size; + stream->pos=pos; + return _buf_size; +} + +static int op_mem_seek(void *_stream,opus_int64 _offset,int _whence){ + OpusMemStream *stream; + ptrdiff_t pos; + stream=(OpusMemStream *)_stream; + pos=stream->pos; + switch(_whence){ + case SEEK_SET:{ + /*Check for overflow:*/ + if(_offset<0||_offset>OP_MEM_DIFF_MAX)return -1; + pos=(ptrdiff_t)_offset; + }break; + case SEEK_CUR:{ + /*Check for overflow:*/ + if(_offset<-pos||_offset>OP_MEM_DIFF_MAX-pos)return -1; + pos=(ptrdiff_t)(pos+_offset); + }break; + case SEEK_END:{ + ptrdiff_t size; + size=stream->size; + OP_ASSERT(size>=0); + /*Check for overflow:*/ + if(_offset>size||_offsetpos=pos; + return 0; +} + +static opus_int64 op_mem_tell(void *_stream){ + OpusMemStream *stream; + stream=(OpusMemStream *)_stream; + return (ogg_int64_t)stream->pos; +} + +static int op_mem_close(void *_stream){ + _ogg_free(_stream); + return 0; +} + +static const OpusFileCallbacks OP_MEM_CALLBACKS={ + op_mem_read, + op_mem_seek, + op_mem_tell, + op_mem_close +}; + +void *op_mem_stream_create(OpusFileCallbacks *_cb, + const unsigned char *_data,size_t _size){ + OpusMemStream *stream; + if(_size>OP_MEM_SIZE_MAX)return NULL; + stream=(OpusMemStream *)_ogg_malloc(sizeof(*stream)); + if(stream!=NULL){ + *_cb=*&OP_MEM_CALLBACKS; + stream->data=_data; + stream->size=_size; + stream->pos=0; + } + return stream; +} diff --git a/code/q3_ui/ui_controls2.c b/code/q3_ui/ui_controls2.c index 907ad00f..55d33289 100644 --- a/code/q3_ui/ui_controls2.c +++ b/code/q3_ui/ui_controls2.c @@ -111,16 +111,17 @@ typedef struct #define ID_CHAT2 31 #define ID_CHAT3 32 #define ID_CHAT4 33 +#define ID_TOGGLEMENU 34 // all others -#define ID_FREELOOK 34 -#define ID_INVERTMOUSE 35 -#define ID_ALWAYSRUN 36 -#define ID_AUTOSWITCH 37 -#define ID_MOUSESPEED 38 -#define ID_JOYENABLE 39 -#define ID_JOYTHRESHOLD 40 -#define ID_SMOOTHMOUSE 41 +#define ID_FREELOOK 35 +#define ID_INVERTMOUSE 36 +#define ID_ALWAYSRUN 37 +#define ID_AUTOSWITCH 38 +#define ID_MOUSESPEED 39 +#define ID_JOYENABLE 40 +#define ID_JOYTHRESHOLD 41 +#define ID_SMOOTHMOUSE 42 #define ANIM_IDLE 0 #define ANIM_RUN 1 @@ -205,6 +206,7 @@ typedef struct menuaction_s chat2; menuaction_s chat3; menuaction_s chat4; + menuaction_s togglemenu; menuradiobutton_s joyenable; menuslider_s joythreshold; int section; @@ -261,6 +263,7 @@ static bind_t g_bindings[] = {"messagemode2", "chat - team", ID_CHAT2, ANIM_CHAT, -1, -1, -1, -1}, {"messagemode3", "chat - target", ID_CHAT3, ANIM_CHAT, -1, -1, -1, -1}, {"messagemode4", "chat - attacker", ID_CHAT4, ANIM_CHAT, -1, -1, -1, -1}, + {"togglemenu", "toggle menu", ID_TOGGLEMENU, ANIM_IDLE, K_ESCAPE, -1, -1, -1}, {(char*)NULL, (char*)NULL, 0, 0, -1, -1, -1, -1}, }; @@ -333,6 +336,7 @@ static menucommon_s *g_misc_controls[] = { (menucommon_s *)&s_controls.chat2, (menucommon_s *)&s_controls.chat3, (menucommon_s *)&s_controls.chat4, + (menucommon_s *)&s_controls.togglemenu, NULL, }; @@ -1532,6 +1536,12 @@ static void Controls_MenuInit( void ) s_controls.chat4.generic.ownerdraw = Controls_DrawKeyBinding; s_controls.chat4.generic.id = ID_CHAT4; + s_controls.togglemenu.generic.type = MTYPE_ACTION; + s_controls.togglemenu.generic.flags = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_GRAYED|QMF_HIDDEN; + s_controls.togglemenu.generic.callback = Controls_ActionEvent; + s_controls.togglemenu.generic.ownerdraw = Controls_DrawKeyBinding; + s_controls.togglemenu.generic.id = ID_TOGGLEMENU; + s_controls.joyenable.generic.type = MTYPE_RADIOBUTTON; s_controls.joyenable.generic.flags = QMF_SMALLFONT; s_controls.joyenable.generic.x = SCREEN_WIDTH/2; @@ -1614,6 +1624,7 @@ static void Controls_MenuInit( void ) Menu_AddItem( &s_controls.menu, &s_controls.chat2 ); Menu_AddItem( &s_controls.menu, &s_controls.chat3 ); Menu_AddItem( &s_controls.menu, &s_controls.chat4 ); + Menu_AddItem( &s_controls.menu, &s_controls.togglemenu ); Menu_AddItem( &s_controls.menu, &s_controls.back ); diff --git a/code/q3_ui/ui_local.h b/code/q3_ui/ui_local.h index 166a324a..72979a9e 100644 --- a/code/q3_ui/ui_local.h +++ b/code/q3_ui/ui_local.h @@ -24,7 +24,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define __UI_LOCAL_H__ #include "../qcommon/q_shared.h" -#include "../renderer/tr_types.h" +#include "../renderercommon/tr_types.h" //NOTE: include the ui_public.h from the new UI #include "../ui/ui_public.h" //redefine to old API version diff --git a/code/q3_ui/ui_players.c b/code/q3_ui/ui_players.c index 92257abf..40ee0c2c 100644 --- a/code/q3_ui/ui_players.c +++ b/code/q3_ui/ui_players.c @@ -708,10 +708,10 @@ void UI_DrawPlayer( float x, float y, float w, float h, playerInfo_t *pi, int ti dp_realtime = time; - if ( pi->pendingWeapon != -1 && dp_realtime > pi->weaponTimer ) { + if ( pi->pendingWeapon != WP_NUM_WEAPONS && dp_realtime > pi->weaponTimer ) { pi->weapon = pi->pendingWeapon; pi->lastWeapon = pi->pendingWeapon; - pi->pendingWeapon = -1; + pi->pendingWeapon = WP_NUM_WEAPONS; pi->weaponTimer = 0; if( pi->currentWeapon != pi->weapon ) { trap_S_StartLocalSound( weaponChangeSound, CHAN_LOCAL ); @@ -1136,7 +1136,7 @@ void UI_PlayerInfo_SetModel( playerInfo_t *pi, const char *model ) { pi->weapon = WP_MACHINEGUN; pi->currentWeapon = pi->weapon; pi->lastWeapon = pi->weapon; - pi->pendingWeapon = -1; + pi->pendingWeapon = WP_NUM_WEAPONS; pi->weaponTimer = 0; pi->chat = qfalse; pi->newModel = qtrue; @@ -1202,11 +1202,11 @@ void UI_PlayerInfo_SetInfo( playerInfo_t *pi, int legsAnim, int torsoAnim, vec3_ pi->torso.yawAngle = viewAngles[YAW]; pi->torso.yawing = qfalse; - if ( weaponNumber != -1 ) { + if ( weaponNumber != WP_NUM_WEAPONS ) { pi->weapon = weaponNumber; pi->currentWeapon = weaponNumber; pi->lastWeapon = weaponNumber; - pi->pendingWeapon = -1; + pi->pendingWeapon = WP_NUM_WEAPONS; pi->weaponTimer = 0; UI_PlayerInfo_SetWeapon( pi, pi->weapon ); } @@ -1215,8 +1215,8 @@ void UI_PlayerInfo_SetInfo( playerInfo_t *pi, int legsAnim, int torsoAnim, vec3_ } // weapon - if ( weaponNumber == -1 ) { - pi->pendingWeapon = -1; + if ( weaponNumber == WP_NUM_WEAPONS ) { + pi->pendingWeapon = WP_NUM_WEAPONS; pi->weaponTimer = 0; } else if ( weaponNumber != WP_NONE ) { diff --git a/code/q3_ui/ui_serverinfo.c b/code/q3_ui/ui_serverinfo.c index 8cde1ccc..3db69415 100644 --- a/code/q3_ui/ui_serverinfo.c +++ b/code/q3_ui/ui_serverinfo.c @@ -82,8 +82,8 @@ void Favorites_Add( void ) return; } - // use first empty or non-numeric available slot - if ((adrstr[0] < '0' || adrstr[0] > '9' ) && !best) + // use first empty available slot + if (!adrstr[0] && !best) best = i+1; } diff --git a/code/q3_ui/ui_servers2.c b/code/q3_ui/ui_servers2.c index 41cdd143..a9b249d3 100644 --- a/code/q3_ui/ui_servers2.c +++ b/code/q3_ui/ui_servers2.c @@ -762,11 +762,6 @@ void ArenaServers_LoadFavorites( void ) if (!adrstr[0]) continue; - // quick sanity check to avoid slow domain name resolving - // first character must be numeric - if (adrstr[0] < '0' || adrstr[0] > '9') - continue; - // favorite server addresses must be maintained outside refresh list // this mimics local and global netadr's stored in client // these can be fetched to fill ping list diff --git a/code/qcommon/cm_polylib.c b/code/qcommon/cm_polylib.c index 500b1df1..4fa97865 100644 --- a/code/qcommon/cm_polylib.c +++ b/code/qcommon/cm_polylib.c @@ -309,8 +309,8 @@ ClipWindingEpsilon void ClipWindingEpsilon (winding_t *in, vec3_t normal, vec_t dist, vec_t epsilon, winding_t **front, winding_t **back) { - vec_t dists[MAX_POINTS_ON_WINDING+4]; - int sides[MAX_POINTS_ON_WINDING+4]; + vec_t dists[MAX_POINTS_ON_WINDING+4] = { 0 }; + int sides[MAX_POINTS_ON_WINDING+4] = { 0 }; int counts[3]; static vec_t dot; // VC 4.2 optimizer bug if not static int i, j; @@ -421,8 +421,8 @@ ChopWindingInPlace void ChopWindingInPlace (winding_t **inout, vec3_t normal, vec_t dist, vec_t epsilon) { winding_t *in; - vec_t dists[MAX_POINTS_ON_WINDING+4]; - int sides[MAX_POINTS_ON_WINDING+4]; + vec_t dists[MAX_POINTS_ON_WINDING+4] = { 0 }; + int sides[MAX_POINTS_ON_WINDING+4] = { 0 }; int counts[3]; static vec_t dot; // VC 4.2 optimizer bug if not static int i, j; diff --git a/code/qcommon/cm_trace.c b/code/qcommon/cm_trace.c index ea71cf48..a4ac80a5 100644 --- a/code/qcommon/cm_trace.c +++ b/code/qcommon/cm_trace.c @@ -650,8 +650,12 @@ void CM_TraceThroughBrush( traceWork_t *tw, cbrush_t *brush ) { enterFrac = 0; } tw->trace.fraction = enterFrac; - tw->trace.plane = *clipplane; - tw->trace.surfaceFlags = leadside->surfaceFlags; + if (clipplane != NULL) { + tw->trace.plane = *clipplane; + } + if (leadside != NULL) { + tw->trace.surfaceFlags = leadside->surfaceFlags; + } tw->trace.contents = brush->contents; } } diff --git a/code/qcommon/cmd.c b/code/qcommon/cmd.c index 40f17861..717701db 100644 --- a/code/qcommon/cmd.c +++ b/code/qcommon/cmd.c @@ -24,7 +24,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "q_shared.h" #include "qcommon.h" -#define MAX_CMD_BUFFER 16384 +#define MAX_CMD_BUFFER 128*1024 #define MAX_CMD_LINE 1024 typedef struct { diff --git a/code/qcommon/common.c b/code/qcommon/common.c index 36fb80c5..c931d57a 100644 --- a/code/qcommon/common.c +++ b/code/qcommon/common.c @@ -887,9 +887,6 @@ void Z_Free( void *ptr ) { block->size += other->size; block->next = other->next; block->next->prev = block; - if (other == zone->rover) { - zone->rover = block; - } } } @@ -1414,8 +1411,6 @@ void Com_InitSmallZoneMemory( void ) { Com_Error( ERR_FATAL, "Small zone data failed to allocate %1.1f megs", (float)s_smallZoneTotal / (1024*1024) ); } Z_ClearZone( smallzone, s_smallZoneTotal ); - - return; } void Com_InitZoneMemory( void ) { @@ -2251,7 +2246,7 @@ Just throw a fatal error to test error shutdown procedures ============= */ -static void Com_Error_f (void) { +static void __attribute__((__noreturn__)) Com_Error_f (void) { if ( Cmd_Argc() > 1 ) { Com_Error( ERR_DROP, "Testing drop error" ); } else { @@ -2544,8 +2539,9 @@ static void Com_WriteCDKey( const char *filename, const char *ikey ) { out: #ifndef _WIN32 umask(savedumask); +#else + ; #endif - return; } #endif diff --git a/code/qcommon/cvar.c b/code/qcommon/cvar.c index 9321e9c7..53a36845 100644 --- a/code/qcommon/cvar.c +++ b/code/qcommon/cvar.c @@ -28,7 +28,7 @@ cvar_t *cvar_vars = NULL; cvar_t *cvar_cheats; int cvar_modifiedFlags; -#define MAX_CVARS 1024 +#define MAX_CVARS 2048 cvar_t cvar_indexes[MAX_CVARS]; int cvar_numIndexes; @@ -334,6 +334,18 @@ cvar_t *Cvar_Get( const char *var_name, const char *var_value, int flags ) { { var_value = Cvar_Validate(var, var_value, qfalse); + // Make sure the game code cannot mark engine-added variables as gamecode vars + if(var->flags & CVAR_VM_CREATED) + { + if(!(flags & CVAR_VM_CREATED)) + var->flags &= ~CVAR_VM_CREATED; + } + else if (!(var->flags & CVAR_USER_CREATED)) + { + if(flags & CVAR_VM_CREATED) + flags &= ~CVAR_VM_CREATED; + } + // if the C code is now specifying a variable that the user already // set a value for, take the new value as the reset value if(var->flags & CVAR_USER_CREATED) @@ -354,18 +366,6 @@ cvar_t *Cvar_Get( const char *var_name, const char *var_value, int flags ) { } } - // Make sure the game code cannot mark engine-added variables as gamecode vars - if(var->flags & CVAR_VM_CREATED) - { - if(!(flags & CVAR_VM_CREATED)) - var->flags &= ~CVAR_VM_CREATED; - } - else - { - if(flags & CVAR_VM_CREATED) - flags &= ~CVAR_VM_CREATED; - } - // Make sure servers cannot mark engine-added variables as SERVER_CREATED if(var->flags & CVAR_SERVER_CREATED) { diff --git a/code/qcommon/files.c b/code/qcommon/files.c index 281df157..2392fb81 100644 --- a/code/qcommon/files.c +++ b/code/qcommon/files.c @@ -309,8 +309,12 @@ FILE* missingFiles = NULL; #endif /* C99 defines __func__ */ -#ifndef __func__ -#define __func__ "(unknown)" +#if __STDC_VERSION__ < 199901L +# if __GNUC__ >= 2 || _MSC_VER >= 1300 +# define __func__ __FUNCTION__ +# else +# define __func__ "(unknown)" +# endif #endif /* @@ -450,9 +454,9 @@ long FS_filelength(fileHandle_t f) h = FS_FileForHandle(f); if(h == NULL) - return -1; - else - return FS_fplength(h); + return -1; + else + return FS_fplength(h); } /* @@ -548,19 +552,21 @@ qboolean FS_CreatePath (char *OSPath) { /* ================= -FS_CheckFilenameIsNotExecutable +FS_CheckFilenameIsMutable -ERR_FATAL if trying to maniuplate a file with the platform library extension +ERR_FATAL if trying to maniuplate a file with the platform library, QVM, or pk3 extension ================= */ -static void FS_CheckFilenameIsNotExecutable( const char *filename, +static void FS_CheckFilenameIsMutable( const char *filename, const char *function ) { - // Check if the filename ends with the library extension - if(COM_CompareExtension(filename, DLL_EXT)) + // Check if the filename ends with the library, QVM, or pk3 extension + if( COM_CompareExtension( filename, DLL_EXT ) + || COM_CompareExtension( filename, ".qvm" ) + || COM_CompareExtension( filename, ".pk3" ) ) { Com_Error( ERR_FATAL, "%s: Not allowed to manipulate '%s' due " - "to %s extension", function, filename, DLL_EXT ); + "to %s extension", function, filename, COM_GetExtension( filename ) ); } } @@ -571,7 +577,7 @@ FS_Remove =========== */ void FS_Remove( const char *osPath ) { - FS_CheckFilenameIsNotExecutable( osPath, __func__ ); + FS_CheckFilenameIsMutable( osPath, __func__ ); remove( osPath ); } @@ -583,7 +589,7 @@ FS_HomeRemove =========== */ void FS_HomeRemove( const char *homePath ) { - FS_CheckFilenameIsNotExecutable( homePath, __func__ ); + FS_CheckFilenameIsMutable( homePath, __func__ ); remove( FS_BuildOSPath( fs_homepath->string, fs_gamedir, homePath ) ); @@ -600,7 +606,7 @@ qboolean FS_FileInPathExists(const char *testpath) { FILE *filep; - filep = fopen(testpath, "rb"); + filep = Sys_FOpen(testpath, "rb"); if(filep) { @@ -668,14 +674,14 @@ fileHandle_t FS_SV_FOpenFileWrite( const char *filename ) { Com_Printf( "FS_SV_FOpenFileWrite: %s\n", ospath ); } - FS_CheckFilenameIsNotExecutable( ospath, __func__ ); + FS_CheckFilenameIsMutable( ospath, __func__ ); if( FS_CreatePath( ospath ) ) { return 0; } Com_DPrintf( "writing to: %s\n", ospath ); - fsh[f].handleFiles.file.o = fopen( ospath, "wb" ); + fsh[f].handleFiles.file.o = Sys_FOpen( ospath, "wb" ); Q_strncpyz( fsh[f].name, filename, sizeof( fsh[f].name ) ); @@ -720,7 +726,7 @@ long FS_SV_FOpenFileRead(const char *filename, fileHandle_t *fp) Com_Printf( "FS_SV_FOpenFileRead (fs_homepath): %s\n", ospath ); } - fsh[f].handleFiles.file.o = fopen( ospath, "rb" ); + fsh[f].handleFiles.file.o = Sys_FOpen( ospath, "rb" ); fsh[f].handleSync = qfalse; if (!fsh[f].handleFiles.file.o) { @@ -736,7 +742,7 @@ long FS_SV_FOpenFileRead(const char *filename, fileHandle_t *fp) Com_Printf( "FS_SV_FOpenFileRead (fs_basepath): %s\n", ospath ); } - fsh[f].handleFiles.file.o = fopen( ospath, "rb" ); + fsh[f].handleFiles.file.o = Sys_FOpen( ospath, "rb" ); fsh[f].handleSync = qfalse; } @@ -761,7 +767,7 @@ FS_SV_Rename =========== */ -void FS_SV_Rename( const char *from, const char *to ) { +void FS_SV_Rename( const char *from, const char *to, qboolean safe ) { char *from_ospath, *to_ospath; if ( !fs_searchpaths ) { @@ -780,7 +786,9 @@ void FS_SV_Rename( const char *from, const char *to ) { Com_Printf( "FS_SV_Rename: %s --> %s\n", from_ospath, to_ospath ); } - FS_CheckFilenameIsNotExecutable( to_ospath, __func__ ); + if ( safe ) { + FS_CheckFilenameIsMutable( to_ospath, __func__ ); + } rename(from_ospath, to_ospath); } @@ -810,7 +818,7 @@ void FS_Rename( const char *from, const char *to ) { Com_Printf( "FS_Rename: %s --> %s\n", from_ospath, to_ospath ); } - FS_CheckFilenameIsNotExecutable( to_ospath, __func__ ); + FS_CheckFilenameIsMutable( to_ospath, __func__ ); rename(from_ospath, to_ospath); } @@ -869,7 +877,7 @@ fileHandle_t FS_FOpenFileWrite( const char *filename ) { Com_Printf( "FS_FOpenFileWrite: %s\n", ospath ); } - FS_CheckFilenameIsNotExecutable( ospath, __func__ ); + FS_CheckFilenameIsMutable( ospath, __func__ ); if( FS_CreatePath( ospath ) ) { return 0; @@ -878,7 +886,7 @@ fileHandle_t FS_FOpenFileWrite( const char *filename ) { // enabling the following line causes a recursive function call loop // when running with +set logfile 1 +set developer 1 //Com_DPrintf( "writing to: %s\n", ospath ); - fsh[f].handleFiles.file.o = fopen( ospath, "wb" ); + fsh[f].handleFiles.file.o = Sys_FOpen( ospath, "wb" ); Q_strncpyz( fsh[f].name, filename, sizeof( fsh[f].name ) ); @@ -917,13 +925,13 @@ fileHandle_t FS_FOpenFileAppend( const char *filename ) { Com_Printf( "FS_FOpenFileAppend: %s\n", ospath ); } - FS_CheckFilenameIsNotExecutable( ospath, __func__ ); + FS_CheckFilenameIsMutable( ospath, __func__ ); if( FS_CreatePath( ospath ) ) { return 0; } - fsh[f].handleFiles.file.o = fopen( ospath, "ab" ); + fsh[f].handleFiles.file.o = Sys_FOpen( ospath, "ab" ); fsh[f].handleSync = qfalse; if (!fsh[f].handleFiles.file.o) { f = 0; @@ -960,7 +968,7 @@ fileHandle_t FS_FCreateOpenPipeFile( const char *filename ) { Com_Printf( "FS_FCreateOpenPipeFile: %s\n", ospath ); } - FS_CheckFilenameIsNotExecutable( ospath, __func__ ); + FS_CheckFilenameIsMutable( ospath, __func__ ); fifo = Sys_Mkfifo( ospath ); if( fifo ) { @@ -986,7 +994,7 @@ Ignore case and seprator char distinctions */ qboolean FS_FilenameCompare( const char *s1, const char *s2 ) { int c1, c2; - + do { c1 = *s1++; c2 = *s2++; @@ -1004,12 +1012,12 @@ qboolean FS_FilenameCompare( const char *s1, const char *s2 ) { if ( c2 == '\\' || c2 == ':' ) { c2 = '/'; } - + if (c1 != c2) { return qtrue; // strings not equal } } while (c1); - + return qfalse; // strings are equal } @@ -1057,8 +1065,8 @@ qboolean FS_IsDemoExt(const char *filename, int namelen) return qtrue; #ifdef LEGACY_PROTOCOL - if(protocol == com_legacyprotocol->integer) - return qtrue; + if(protocol == com_legacyprotocol->integer) + return qtrue; #endif for(index = 0; demo_protocols[index]; index++) @@ -1103,19 +1111,19 @@ long FS_FOpenFileReadDir(const char *filename, searchpath_t *search, fileHandle_ // be prepended, so we don't need to worry about "c:" or "//limbo" if(strstr(filename, ".." ) || strstr(filename, "::")) { - if(file == NULL) - return qfalse; - + if(file == NULL) + return qfalse; + *file = 0; return -1; } - + // make sure the q3key file is only readable by the quake3.exe at initialization // any other time the key should only be accessed in memory using the provided functions if(com_fullyInitialized && strstr(filename, "q3key")) { - if(file == NULL) - return qfalse; + if(file == NULL) + return qfalse; *file = 0; return -1; @@ -1129,9 +1137,9 @@ long FS_FOpenFileReadDir(const char *filename, searchpath_t *search, fileHandle_ if(search->pack) { hash = FS_HashFileName(filename, search->pack->hashSize); - - if(search->pack->hashTable[hash]) - { + + if(search->pack->hashTable[hash]) + { // look through all the pak file elements pak = search->pack; pakFile = pak->hashTable[hash]; @@ -1143,14 +1151,14 @@ long FS_FOpenFileReadDir(const char *filename, searchpath_t *search, fileHandle_ { // found it! if(pakFile->len) - return pakFile->len; - else - { - // It's not nice, but legacy code depends - // on positive value if file exists no matter - // what size - return 1; - } + return pakFile->len; + else + { + // It's not nice, but legacy code depends + // on positive value if file exists no matter + // what size + return 1; + } } pakFile = pakFile->next; @@ -1160,28 +1168,28 @@ long FS_FOpenFileReadDir(const char *filename, searchpath_t *search, fileHandle_ else if(search->dir) { dir = search->dir; - + netpath = FS_BuildOSPath(dir->path, dir->gamedir, filename); - filep = fopen (netpath, "rb"); + filep = Sys_FOpen(netpath, "rb"); if(filep) { - len = FS_fplength(filep); + len = FS_fplength(filep); fclose(filep); - + if(len) - return len; - else - return 1; + return len; + else + return 1; } } - + return 0; } *file = FS_HandleForFile(); fsh[*file].handleFiles.unique = uniqueFILE; - + // is the element a pak file? if(search->pack) { @@ -1199,7 +1207,7 @@ long FS_FOpenFileReadDir(const char *filename, searchpath_t *search, fileHandle_ // look through all the pak file elements pak = search->pack; pakFile = pak->hashTable[hash]; - + do { // case and separator insensitive comparisons @@ -1222,7 +1230,7 @@ long FS_FOpenFileReadDir(const char *filename, searchpath_t *search, fileHandle_ !FS_IsExt(filename, ".bot", len) && !FS_IsExt(filename, ".arena", len) && !FS_IsExt(filename, ".menu", len) && - Q_stricmp(filename, "qagame.qvm") != 0 && + Q_stricmp(filename, "vm/qagame.qvm") != 0 && !strstr(filename, "levelshots")) { pak->referenced |= FS_GENERAL_REF; @@ -1238,7 +1246,7 @@ long FS_FOpenFileReadDir(const char *filename, searchpath_t *search, fileHandle_ { // open a new file on the pakfile fsh[*file].handleFiles.file.z = unzOpen(pak->pakFilename); - + if(fsh[*file].handleFiles.file.z == NULL) Com_Error(ERR_FATAL, "Couldn't open %s", pak->pakFilename); } @@ -1247,7 +1255,7 @@ long FS_FOpenFileReadDir(const char *filename, searchpath_t *search, fileHandle_ Q_strncpyz(fsh[*file].name, filename, sizeof(fsh[*file].name)); fsh[*file].zipFile = qtrue; - + // set the file position in the zip file (also sets the current file info) unzSetOffset(fsh[*file].handleFiles.file.z, pakFile->pos); @@ -1258,12 +1266,12 @@ long FS_FOpenFileReadDir(const char *filename, searchpath_t *search, fileHandle_ if(fs_debug->integer) { Com_Printf("FS_FOpenFileRead: %s (found in '%s')\n", - filename, pak->pakFilename); + filename, pak->pakFilename); } - + return pakFile->len; } - + pakFile = pakFile->next; } while(pakFile != NULL); } @@ -1296,21 +1304,21 @@ long FS_FOpenFileReadDir(const char *filename, searchpath_t *search, fileHandle_ dir = search->dir; netpath = FS_BuildOSPath(dir->path, dir->gamedir, filename); - filep = fopen(netpath, "rb"); + filep = Sys_FOpen(netpath, "rb"); if (filep == NULL) { *file = 0; - return -1; + return -1; } Q_strncpyz(fsh[*file].name, filename, sizeof(fsh[*file].name)); fsh[*file].zipFile = qfalse; - + if(fs_debug->integer) { - Com_Printf("FS_FOpenFileRead: %s (found in '%s/%s')\n", filename, - dir->path, dir->gamedir); + Com_Printf("FS_FOpenFileRead: %s (found in '%s%c%s')\n", filename, + dir->path, PATH_SEP, dir->gamedir); } fsh[*file].handleFiles.file.o = filep; @@ -1340,19 +1348,19 @@ long FS_FOpenFileRead(const char *filename, fileHandle_t *file, qboolean uniqueF for(search = fs_searchpaths; search; search = search->next) { - len = FS_FOpenFileReadDir(filename, search, file, uniqueFILE, qfalse); - - if(file == NULL) - { - if(len > 0) - return len; - } - else - { - if(len >= 0 && *file) - return len; - } - + len = FS_FOpenFileReadDir(filename, search, file, uniqueFILE, qfalse); + + if(file == NULL) + { + if(len > 0) + return len; + } + else + { + if(len >= 0 && *file) + return len; + } + } #ifdef FS_MISSING @@ -1360,10 +1368,17 @@ long FS_FOpenFileRead(const char *filename, fileHandle_t *file, qboolean uniqueF fprintf(missingFiles, "%s\n", filename); #endif - if(file) - *file = 0; - - return -1; + if(file) + { + *file = 0; + return -1; + } + else + { + // When file is NULL, we're querying the existance of the file + // If we've got here, it doesn't exist + return 0; + } } /* @@ -1383,7 +1398,7 @@ Return the searchpath in "startSearch". ================= */ -vmInterpret_t FS_FindVM(void **startSearch, char *found, int foundlen, const char *name, int enableDll) +int FS_FindVM(void **startSearch, char *found, int foundlen, const char *name, int enableDll) { searchpath_t *search, *lastSearch; directory_t *dir; @@ -1396,7 +1411,7 @@ vmInterpret_t FS_FindVM(void **startSearch, char *found, int foundlen, const cha if(enableDll) Com_sprintf(dllName, sizeof(dllName), "%s" ARCH_STRING DLL_EXT, name); - + Com_sprintf(qvmName, sizeof(qvmName), "vm/%s.qvm", name); lastSearch = *startSearch; @@ -1404,7 +1419,7 @@ vmInterpret_t FS_FindVM(void **startSearch, char *found, int foundlen, const cha search = fs_searchpaths; else search = lastSearch->next; - + while(search) { if(search->dir && !fs_numServerPaks) @@ -1419,7 +1434,7 @@ vmInterpret_t FS_FindVM(void **startSearch, char *found, int foundlen, const cha { Q_strncpyz(found, netpath, foundlen); *startSearch = search; - + return VMI_NATIVE; } } @@ -1434,17 +1449,17 @@ vmInterpret_t FS_FindVM(void **startSearch, char *found, int foundlen, const cha { pack = search->pack; - if(lastSearch && lastSearch->pack) - { - // make sure we only try loading one VM file per game dir - // i.e. if VM from pak7.pk3 fails we won't try one from pak6.pk3 - - if(!FS_FilenameCompare(lastSearch->pack->pakPathname, pack->pakPathname)) - { - search = search->next; - continue; - } - } + if(lastSearch && lastSearch->pack) + { + // make sure we only try loading one VM file per game dir + // i.e. if VM from pak7.pk3 fails we won't try one from pak6.pk3 + + if(!FS_FilenameCompare(lastSearch->pack->pakPathname, pack->pakPathname)) + { + search = search->next; + continue; + } + } if(FS_FOpenFileReadDir(qvmName, search, NULL, qfalse, qfalse) > 0) { @@ -1453,7 +1468,7 @@ vmInterpret_t FS_FindVM(void **startSearch, char *found, int foundlen, const cha return VMI_COMPILED; } } - + search = search->next; } @@ -1614,7 +1629,7 @@ int FS_Seek( fileHandle_t f, long offset, int origin ) { if (fsh[f].streamed) { fsh[f].streamed = qfalse; - FS_Seek( f, offset, origin ); + FS_Seek( f, offset, origin ); fsh[f].streamed = qtrue; } @@ -1664,7 +1679,6 @@ int FS_Seek( fileHandle_t f, long offset, int origin ) { _origin = SEEK_SET; break; default: - _origin = SEEK_CUR; Com_Error( ERR_FATAL, "Bad origin in FS_Seek" ); break; } @@ -1820,7 +1834,7 @@ long FS_ReadFileDir(const char *qpath, void *searchPath, qboolean unpure, void * { // look for it in the filesystem or pack files len = FS_FOpenFileRead(qpath, &h, qfalse); - } + } else { // look for it in a specific search path only @@ -1840,7 +1854,7 @@ long FS_ReadFileDir(const char *qpath, void *searchPath, qboolean unpure, void * } return -1; } - + if ( !buffer ) { if ( isConfig && com_journal && com_journal->integer == 1 ) { Com_DPrintf( "Writing len for %s to journal file.\n", qpath ); @@ -2081,21 +2095,21 @@ qboolean FS_CompareZipChecksum(const char *zipfile) { pack_t *thepak; int index, checksum; - + thepak = FS_LoadZipFile(zipfile, ""); - + if(!thepak) return qfalse; - + checksum = thepak->checksum; FS_FreePak(thepak); - + for(index = 0; index < fs_numServerReferencedPaks; index++) { if(checksum == fs_serverReferencedPaks[index]) return qtrue; } - + return qfalse; } @@ -2246,7 +2260,7 @@ char **FS_ListFilteredFiles( const char *path, const char *extension, char *filt temp = pathLength; if (pathLength) { - temp++; // include the '/' + temp++; // include the '/' } nfiles = FS_AddFileToList( name + temp, list, nfiles ); } @@ -2259,8 +2273,8 @@ char **FS_ListFilteredFiles( const char *path, const char *extension, char *filt // don't scan directories for files if we are pure or restricted if ( fs_numServerPaks && !allowNonPureFilesOnDisk ) { - continue; - } else { + continue; + } else { netpath = FS_BuildOSPath( search->dir->path, search->dir->gamedir, path ); sysFiles = Sys_ListFiles( netpath, extension, filter, &numSysFiles, qfalse ); for ( i = 0 ; i < numSysFiles ; i++ ) { @@ -2270,7 +2284,7 @@ char **FS_ListFilteredFiles( const char *path, const char *extension, char *filt } Sys_FreeFileList( sysFiles ); } - } + } } // return a copy of the list @@ -2796,7 +2810,6 @@ void FS_Which_f( void ) { } Com_Printf("File not found: \"%s\"\n", filename); - return; } @@ -2822,12 +2835,20 @@ then loads the zip headers */ void FS_AddGameDirectory( const char *path, const char *dir ) { searchpath_t *sp; - int i; searchpath_t *search; pack_t *pak; char curpath[MAX_OSPATH + 1], *pakfile; int numfiles; char **pakfiles; + int pakfilesi; + char **pakfilestmp; + int numdirs; + char **pakdirs; + int pakdirsi; + char **pakdirstmp; + + int pakwhich; + int len; // Unique for ( sp = fs_searchpaths ; sp ; sp = sp->next ) { @@ -2835,36 +2856,102 @@ void FS_AddGameDirectory( const char *path, const char *dir ) { return; // we've already got this one } } - + Q_strncpyz( fs_gamedir, dir, sizeof( fs_gamedir ) ); // find all pak files in this directory Q_strncpyz(curpath, FS_BuildOSPath(path, dir, ""), sizeof(curpath)); curpath[strlen(curpath) - 1] = '\0'; // strip the trailing slash + // Get .pk3 files pakfiles = Sys_ListFiles(curpath, ".pk3", NULL, &numfiles, qfalse); qsort( pakfiles, numfiles, sizeof(char*), paksort ); - for ( i = 0 ; i < numfiles ; i++ ) { - pakfile = FS_BuildOSPath( path, dir, pakfiles[i] ); - if ( ( pak = FS_LoadZipFile( pakfile, pakfiles[i] ) ) == 0 ) - continue; + if ( fs_numServerPaks ) { + numdirs = 0; + pakdirs = NULL; + } else { + // Get top level directories (we'll filter them later since the Sys_ListFiles filtering is terrible) + pakdirs = Sys_ListFiles(curpath, "/", NULL, &numdirs, qfalse); - Q_strncpyz(pak->pakPathname, curpath, sizeof(pak->pakPathname)); - // store the game name for downloading - Q_strncpyz(pak->pakGamename, dir, sizeof(pak->pakGamename)); - - fs_packFiles += pak->numfiles; + qsort( pakdirs, numdirs, sizeof(char *), paksort ); + } - search = Z_Malloc (sizeof(searchpath_t)); - search->pack = pak; - search->next = fs_searchpaths; - fs_searchpaths = search; + pakfilesi = 0; + pakdirsi = 0; + + while((pakfilesi < numfiles) || (pakdirsi < numdirs)) + { + // Check if a pakfile or pakdir comes next + if (pakfilesi >= numfiles) { + // We've used all the pakfiles, it must be a pakdir. + pakwhich = 0; + } + else if (pakdirsi >= numdirs) { + // We've used all the pakdirs, it must be a pakfile. + pakwhich = 1; + } + else { + // Could be either, compare to see which name comes first + // Need tmp variables for appropriate indirection for paksort() + pakfilestmp = &pakfiles[pakfilesi]; + pakdirstmp = &pakdirs[pakdirsi]; + pakwhich = (paksort(pakfilestmp, pakdirstmp) < 0); + } + + if (pakwhich) { + // The next .pk3 file is before the next .pk3dir + pakfile = FS_BuildOSPath(path, dir, pakfiles[pakfilesi]); + if ((pak = FS_LoadZipFile(pakfile, pakfiles[pakfilesi])) == 0) { + // This isn't a .pk3! Next! + pakfilesi++; + continue; + } + + Q_strncpyz(pak->pakPathname, curpath, sizeof(pak->pakPathname)); + // store the game name for downloading + Q_strncpyz(pak->pakGamename, dir, sizeof(pak->pakGamename)); + + fs_packFiles += pak->numfiles; + + search = Z_Malloc(sizeof(searchpath_t)); + search->pack = pak; + search->next = fs_searchpaths; + fs_searchpaths = search; + + pakfilesi++; + } + else { + // The next .pk3dir is before the next .pk3 file + // But wait, this could be any directory, we're filtering to only ending with ".pk3dir" here. + len = strlen(pakdirs[pakdirsi]); + if (!FS_IsExt(pakdirs[pakdirsi], ".pk3dir", len)) { + // This isn't a .pk3dir! Next! + pakdirsi++; + continue; + } + + pakfile = FS_BuildOSPath(path, dir, pakdirs[pakdirsi]); + + // add the directory to the search path + search = Z_Malloc(sizeof(searchpath_t)); + search->dir = Z_Malloc(sizeof(*search->dir)); + + Q_strncpyz(search->dir->path, curpath, sizeof(search->dir->path)); // c:\quake3\baseq3 + Q_strncpyz(search->dir->fullpath, pakfile, sizeof(search->dir->fullpath)); // c:\quake3\baseq3\mypak.pk3dir + Q_strncpyz(search->dir->gamedir, pakdirs[pakdirsi], sizeof(search->dir->gamedir)); // mypak.pk3dir + + search->next = fs_searchpaths; + fs_searchpaths = search; + + pakdirsi++; + } } // done Sys_FreeFileList( pakfiles ); + Sys_FreeFileList( pakdirs ); // // add the directory to the search path @@ -2962,9 +3049,9 @@ qboolean FS_ComparePaks( char *neededpaks, int len, qboolean dlstring ) { // never autodownload any of the id paks if(FS_idPak(fs_serverReferencedPakNames[i], BASEGAME, NUM_ID_PAKS) #ifndef STANDALONE - || FS_idPak(fs_serverReferencedPakNames[i], BASETA, NUM_TA_PAKS) + || FS_idPak(fs_serverReferencedPakNames[i], BASETA, NUM_TA_PAKS) #endif - ) + ) { continue; } @@ -3164,14 +3251,14 @@ static void FS_Startup( const char *gameName ) FS_AddGameDirectory( fs_basepath->string, gameName ); } // fs_homepath is somewhat particular to *nix systems, only add if relevant - - #ifdef MACOS_X + +#ifdef MACOS_X fs_apppath = Cvar_Get ("fs_apppath", Sys_DefaultAppPath(), CVAR_INIT|CVAR_PROTECTED ); // Make MacOSX also include the base path included with the .app bundle if (fs_apppath->string[0]) FS_AddGameDirectory(fs_apppath->string, gameName); - #endif - +#endif + // NOTE: same filtering below for mods and basegame if (fs_homepath->string[0] && Q_stricmp(fs_homepath->string,fs_basepath->string)) { FS_CreatePath ( fs_homepath->string ); @@ -3231,7 +3318,7 @@ static void FS_Startup( const char *gameName ) #ifdef FS_MISSING if (missingFiles == NULL) { - missingFiles = fopen( "\\missing.txt", "ab" ); + missingFiles = Sys_FOpen( "\\missing.txt", "ab" ); } #endif Com_Printf( "%d files in pk3 files\n", fs_packFiles ); @@ -3263,80 +3350,80 @@ static void FS_CheckPak0( void ) if(!path->pack) continue; - + curpack = path->pack; if(!Q_stricmpn( curpack->pakGamename, "demoq3", MAX_OSPATH ) - && !Q_stricmpn( pakBasename, "pak0", MAX_OSPATH )) + && !Q_stricmpn( pakBasename, "pak0", MAX_OSPATH )) { if(curpack->checksum == DEMO_PAK0_CHECKSUM) founddemo = qtrue; } else if(!Q_stricmpn( curpack->pakGamename, BASEGAME, MAX_OSPATH ) - && strlen(pakBasename) == 4 && !Q_stricmpn( pakBasename, "pak", 3 ) - && pakBasename[3] >= '0' && pakBasename[3] <= '0' + NUM_ID_PAKS - 1) + && strlen(pakBasename) == 4 && !Q_stricmpn( pakBasename, "pak", 3 ) + && pakBasename[3] >= '0' && pakBasename[3] <= '0' + NUM_ID_PAKS - 1) { if( curpack->checksum != pak_checksums[pakBasename[3]-'0'] ) { if(pakBasename[3] == '0') { Com_Printf("\n\n" - "**************************************************\n" - "WARNING: " BASEGAME "/pak0.pk3 is present but its checksum (%u)\n" - "is not correct. Please re-copy pak0.pk3 from your\n" - "legitimate Q3 CDROM.\n" - "**************************************************\n\n\n", - curpack->checksum ); + "**************************************************\n" + "WARNING: " BASEGAME "/pak0.pk3 is present but its checksum (%u)\n" + "is not correct. Please re-copy pak0.pk3 from your\n" + "legitimate Q3 CDROM.\n" + "**************************************************\n\n\n", + curpack->checksum ); } else { Com_Printf("\n\n" - "**************************************************\n" - "WARNING: " BASEGAME "/pak%d.pk3 is present but its checksum (%u)\n" - "is not correct. Please re-install the point release\n" - "**************************************************\n\n\n", - pakBasename[3]-'0', curpack->checksum ); + "**************************************************\n" + "WARNING: " BASEGAME "/pak%d.pk3 is present but its checksum (%u)\n" + "is not correct. Please re-install the point release\n" + "**************************************************\n\n\n", + pakBasename[3]-'0', curpack->checksum ); } } foundPak |= 1<<(pakBasename[3]-'0'); } else if(!Q_stricmpn(curpack->pakGamename, BASETA, MAX_OSPATH) - && strlen(pakBasename) == 4 && !Q_stricmpn(pakBasename, "pak", 3) - && pakBasename[3] >= '0' && pakBasename[3] <= '0' + NUM_TA_PAKS - 1) - + && strlen(pakBasename) == 4 && !Q_stricmpn(pakBasename, "pak", 3) + && pakBasename[3] >= '0' && pakBasename[3] <= '0' + NUM_TA_PAKS - 1) + { if(curpack->checksum != missionpak_checksums[pakBasename[3]-'0']) { Com_Printf("\n\n" - "**************************************************\n" - "WARNING: " BASETA "/pak%d.pk3 is present but its checksum (%u)\n" - "is not correct. Please re-install Team Arena\n" - "**************************************************\n\n\n", - pakBasename[3]-'0', curpack->checksum ); + "**************************************************\n" + "WARNING: " BASETA "/pak%d.pk3 is present but its checksum (%u)\n" + "is not correct. Please re-install Team Arena\n" + "**************************************************\n\n\n", + pakBasename[3]-'0', curpack->checksum ); } - + foundTA |= 1 << (pakBasename[3]-'0'); } else { int index; - + // Finally check whether this pak's checksum is listed because the user tried // to trick us by renaming the file, and set foundPak's highest bit to indicate this case. - + for(index = 0; index < ARRAY_LEN(pak_checksums); index++) { if(curpack->checksum == pak_checksums[index]) { Com_Printf("\n\n" - "**************************************************\n" - "WARNING: %s is renamed pak file %s%cpak%d.pk3\n" - "Running in standalone mode won't work\n" - "Please rename, or remove this file\n" - "**************************************************\n\n\n", - curpack->pakFilename, BASEGAME, PATH_SEP, index); + "**************************************************\n" + "WARNING: %s is renamed pak file %s%cpak%d.pk3\n" + "Running in standalone mode won't work\n" + "Please rename, or remove this file\n" + "**************************************************\n\n\n", + curpack->pakFilename, BASEGAME, PATH_SEP, index); foundPak |= 0x80000000; @@ -3348,12 +3435,12 @@ static void FS_CheckPak0( void ) if(curpack->checksum == missionpak_checksums[index]) { Com_Printf("\n\n" - "**************************************************\n" - "WARNING: %s is renamed pak file %s%cpak%d.pk3\n" - "Running in standalone mode won't work\n" - "Please rename, or remove this file\n" - "**************************************************\n\n\n", - curpack->pakFilename, BASETA, PATH_SEP, index); + "**************************************************\n" + "WARNING: %s is renamed pak file %s%cpak%d.pk3\n" + "Running in standalone mode won't work\n" + "Please rename, or remove this file\n" + "**************************************************\n\n\n", + curpack->pakFilename, BASETA, PATH_SEP, index); foundTA |= 0x80000000; } @@ -3380,7 +3467,7 @@ static void FS_CheckPak0( void ) "from the demo. This may work fine, but it is not\n" "guaranteed or supported.\n" "**************************************************\n\n\n" ); - + foundPak |= 0x01; } } @@ -3394,25 +3481,25 @@ static void FS_CheckPak0( void ) if((foundPak & 0x01) != 0x01) { Q_strcat(errorText, sizeof(errorText), - "\"pak0.pk3\" is missing. Please copy it " - "from your legitimate Q3 CDROM. "); + "\"pak0.pk3\" is missing. Please copy it " + "from your legitimate Q3 CDROM. "); } if((foundPak & 0x1fe) != 0x1fe) { Q_strcat(errorText, sizeof(errorText), - "Point Release files are missing. Please " - "re-install the 1.32 point release. "); + "Point Release files are missing. Please " + "re-install the 1.32 point release. "); } Q_strcat(errorText, sizeof(errorText), - va("Also check that your ioq3 executable is in " - "the correct place and that every file " - "in the \"%s\" directory is present and readable", BASEGAME)); + va("Also check that your ioq3 executable is in " + "the correct place and that every file " + "in the \"%s\" directory is present and readable", BASEGAME)); Com_Error(ERR_FATAL, "%s", errorText); } - + if(!com_standalone->integer && foundTA && (foundTA & 0x0f) != 0x0f) { char errorText[MAX_STRING_CHARS] = ""; @@ -3420,15 +3507,15 @@ static void FS_CheckPak0( void ) if((foundTA & 0x01) != 0x01) { Com_sprintf(errorText, sizeof(errorText), - "\"" BASETA "%cpak0.pk3\" is missing. Please copy it " - "from your legitimate Quake 3 Team Arena CDROM. ", PATH_SEP); + "\"" BASETA "%cpak0.pk3\" is missing. Please copy it " + "from your legitimate Quake 3 Team Arena CDROM. ", PATH_SEP); } if((foundTA & 0x0e) != 0x0e) { Q_strcat(errorText, sizeof(errorText), - "Team Arena Point Release files are missing. Please " - "re-install the latest Team Arena point release."); + "Team Arena Point Release files are missing. Please " + "re-install the latest Team Arena point release."); } Com_Error(ERR_FATAL, "%s", errorText); @@ -3749,11 +3836,11 @@ void FS_PureServerSetReferencedPaks( const char *pakSums, const char *pakNames ) fs_serverReferencedPakNames[i] = CopyString( Cmd_Argv( i ) ); } } - + // ensure that there are as many checksums as there are pak names. if(d < c) c = d; - + fs_numServerReferencedPaks = c; } @@ -3863,8 +3950,8 @@ qboolean FS_ConditionalRestart(int checksumFeed, qboolean disconnect) if(fs_gamedirvar->modified) { if(FS_FilenameCompare(lastValidGame, fs_gamedirvar->string) && - (*lastValidGame || FS_FilenameCompare(fs_gamedirvar->string, com_basegame->string)) && - (*fs_gamedirvar->string || FS_FilenameCompare(lastValidGame, com_basegame->string))) + (*lastValidGame || FS_FilenameCompare(fs_gamedirvar->string, com_basegame->string)) && + (*fs_gamedirvar->string || FS_FilenameCompare(lastValidGame, com_basegame->string))) { Com_GameRestart(checksumFeed, disconnect); return qtrue; @@ -3872,12 +3959,12 @@ qboolean FS_ConditionalRestart(int checksumFeed, qboolean disconnect) else fs_gamedirvar->modified = qfalse; } - + if(checksumFeed != fs_checksumFeed) FS_Restart(checksumFeed); else if(fs_numServerPaks && !fs_reordered) FS_ReorderPurePaks(); - + return qfalse; } @@ -3896,28 +3983,28 @@ int FS_FOpenFileByMode( const char *qpath, fileHandle_t *f, fsMode_t mode ) { sync = qfalse; switch( mode ) { - case FS_READ: - r = FS_FOpenFileRead( qpath, f, qtrue ); - break; - case FS_WRITE: - *f = FS_FOpenFileWrite( qpath ); - r = 0; - if (*f == 0) { - r = -1; - } - break; - case FS_APPEND_SYNC: - sync = qtrue; - case FS_APPEND: - *f = FS_FOpenFileAppend( qpath ); - r = 0; - if (*f == 0) { - r = -1; - } - break; - default: - Com_Error( ERR_FATAL, "FS_FOpenFileByMode: bad mode" ); - return -1; + case FS_READ: + r = FS_FOpenFileRead( qpath, f, qtrue ); + break; + case FS_WRITE: + *f = FS_FOpenFileWrite( qpath ); + r = 0; + if (*f == 0) { + r = -1; + } + break; + case FS_APPEND_SYNC: + sync = qtrue; + case FS_APPEND: + *f = FS_FOpenFileAppend( qpath ); + r = 0; + if (*f == 0) { + r = -1; + } + break; + default: + Com_Error( ERR_FATAL, "FS_FOpenFileByMode: bad mode" ); + return -1; } if (!f) { diff --git a/code/qcommon/huffman.c b/code/qcommon/huffman.c index 941258c2..c1b9f242 100644 --- a/code/qcommon/huffman.c +++ b/code/qcommon/huffman.c @@ -405,7 +405,6 @@ void Huff_Compress(msg_t *mbuf, int offset) { huff.tree->weight = 0; huff.lhead->next = huff.lhead->prev = NULL; huff.tree->parent = huff.tree->left = huff.tree->right = NULL; - huff.loc[NYT] = huff.tree; seq[0] = (size>>8); seq[1] = size&0xff; @@ -442,6 +441,5 @@ void Huff_Init(huffman_t *huff) { huff->compressor.tree->weight = 0; huff->compressor.lhead->next = huff->compressor.lhead->prev = NULL; huff->compressor.tree->parent = huff->compressor.tree->left = huff->compressor.tree->right = NULL; - huff->compressor.loc[NYT] = huff->compressor.tree; } diff --git a/code/qcommon/msg.c b/code/qcommon/msg.c index 4ff6d63c..5623b9bb 100644 --- a/code/qcommon/msg.c +++ b/code/qcommon/msg.c @@ -631,7 +631,7 @@ void MSG_WriteDeltaKey( msg_t *msg, int key, int oldV, int newV, int bits ) { int MSG_ReadDeltaKey( msg_t *msg, int key, int oldV, int bits ) { if ( MSG_ReadBits( msg, 1 ) ) { - return MSG_ReadBits( msg, bits ) ^ (key & kbitmask[bits]); + return MSG_ReadBits( msg, bits ) ^ (key & kbitmask[ bits - 1 ]); } return oldV; } @@ -666,70 +666,9 @@ usercmd_t communication ============================================================================ */ -// ms is allways sent, the others are optional -#define CM_ANGLE1 (1<<0) -#define CM_ANGLE2 (1<<1) -#define CM_ANGLE3 (1<<2) -#define CM_FORWARD (1<<3) -#define CM_SIDE (1<<4) -#define CM_UP (1<<5) -#define CM_BUTTONS (1<<6) -#define CM_WEAPON (1<<7) - /* ===================== -MSG_WriteDeltaUsercmd -===================== -*/ -void MSG_WriteDeltaUsercmd( msg_t *msg, usercmd_t *from, usercmd_t *to ) { - if ( to->serverTime - from->serverTime < 256 ) { - MSG_WriteBits( msg, 1, 1 ); - MSG_WriteBits( msg, to->serverTime - from->serverTime, 8 ); - } else { - MSG_WriteBits( msg, 0, 1 ); - MSG_WriteBits( msg, to->serverTime, 32 ); - } - MSG_WriteDelta( msg, from->angles[0], to->angles[0], 16 ); - MSG_WriteDelta( msg, from->angles[1], to->angles[1], 16 ); - MSG_WriteDelta( msg, from->angles[2], to->angles[2], 16 ); - MSG_WriteDelta( msg, from->forwardmove, to->forwardmove, 8 ); - MSG_WriteDelta( msg, from->rightmove, to->rightmove, 8 ); - MSG_WriteDelta( msg, from->upmove, to->upmove, 8 ); - MSG_WriteDelta( msg, from->buttons, to->buttons, 16 ); - MSG_WriteDelta( msg, from->weapon, to->weapon, 8 ); -} - - -/* -===================== -MSG_ReadDeltaUsercmd -===================== -*/ -void MSG_ReadDeltaUsercmd( msg_t *msg, usercmd_t *from, usercmd_t *to ) { - if ( MSG_ReadBits( msg, 1 ) ) { - to->serverTime = from->serverTime + MSG_ReadBits( msg, 8 ); - } else { - to->serverTime = MSG_ReadBits( msg, 32 ); - } - to->angles[0] = MSG_ReadDelta( msg, from->angles[0], 16); - to->angles[1] = MSG_ReadDelta( msg, from->angles[1], 16); - to->angles[2] = MSG_ReadDelta( msg, from->angles[2], 16); - to->forwardmove = MSG_ReadDelta( msg, from->forwardmove, 8); - if( to->forwardmove == -128 ) - to->forwardmove = -127; - to->rightmove = MSG_ReadDelta( msg, from->rightmove, 8); - if( to->rightmove == -128 ) - to->rightmove = -127; - to->upmove = MSG_ReadDelta( msg, from->upmove, 8); - if( to->upmove == -128 ) - to->upmove = -127; - to->buttons = MSG_ReadDelta( msg, from->buttons, 16); - to->weapon = MSG_ReadDelta( msg, from->weapon, 8); -} - -/* -===================== -MSG_WriteDeltaUsercmd +MSG_WriteDeltaUsercmdKey ===================== */ void MSG_WriteDeltaUsercmdKey( msg_t *msg, int key, usercmd_t *from, usercmd_t *to ) { @@ -767,7 +706,7 @@ void MSG_WriteDeltaUsercmdKey( msg_t *msg, int key, usercmd_t *from, usercmd_t * /* ===================== -MSG_ReadDeltaUsercmd +MSG_ReadDeltaUsercmdKey ===================== */ void MSG_ReadDeltaUsercmdKey( msg_t *msg, int key, usercmd_t *from, usercmd_t *to ) { diff --git a/code/qcommon/net_ip.c b/code/qcommon/net_ip.c index 9d2a01f6..4ef3e345 100644 --- a/code/qcommon/net_ip.c +++ b/code/qcommon/net_ip.c @@ -810,7 +810,7 @@ void Sys_ShowIP(void) { NET_IPSocket ==================== */ -int NET_IPSocket( char *net_interface, int port, int *err ) { +SOCKET NET_IPSocket( char *net_interface, int port, int *err ) { SOCKET newsocket; struct sockaddr_in address; ioctlarg_t _true = 1; @@ -878,7 +878,7 @@ int NET_IPSocket( char *net_interface, int port, int *err ) { NET_IP6Socket ==================== */ -int NET_IP6Socket( char *net_interface, int port, struct sockaddr_in6 *bindto, int *err ) { +SOCKET NET_IP6Socket( char *net_interface, int port, struct sockaddr_in6 *bindto, int *err ) { SOCKET newsocket; struct sockaddr_in6 address; ioctlarg_t _true = 1; diff --git a/code/qcommon/q_platform.h b/code/qcommon/q_platform.h index f2baf1c7..999dd39a 100644 --- a/code/qcommon/q_platform.h +++ b/code/qcommon/q_platform.h @@ -98,7 +98,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define PATH_SEP '\\' #if defined( __WIN64__ ) -#define ARCH_STRING "x64" +#define ARCH_STRING "x86_64" #elif defined _M_ALPHA #define ARCH_STRING "AXP" #endif @@ -154,7 +154,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define ARCH_STRING "ppc" #define Q3_BIG_ENDIAN #elif defined __i386__ -#define ARCH_STRING "i386" +#define ARCH_STRING "x86" #define Q3_LITTLE_ENDIAN #elif defined __x86_64__ #undef idx64 @@ -179,16 +179,12 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define OS_STRING "kFreeBSD" #endif -#ifdef __clang__ -#define ID_INLINE static inline -#else #define ID_INLINE inline -#endif #define PATH_SEP '/' #if defined __i386__ -#define ARCH_STRING "i386" +#define ARCH_STRING "x86" #elif defined __x86_64__ #undef idx64 #define idx64 1 @@ -252,11 +248,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define PATH_SEP '/' #ifdef __i386__ -#define ARCH_STRING "i386" +#define ARCH_STRING "x86" #elif defined __amd64__ #undef idx64 #define idx64 1 -#define ARCH_STRING "amd64" +#define ARCH_STRING "x86_64" #elif defined __axp__ #define ARCH_STRING "alpha" #endif @@ -283,7 +279,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define PATH_SEP '/' #ifdef __i386__ -#define ARCH_STRING "i386" +#define ARCH_STRING "x86" #elif defined __sparc #define ARCH_STRING "sparc" #endif diff --git a/code/qcommon/q_shared.c b/code/qcommon/q_shared.c index 31d87f65..357451c5 100644 --- a/code/qcommon/q_shared.c +++ b/code/qcommon/q_shared.c @@ -286,15 +286,22 @@ PARSING static char com_token[MAX_TOKEN_CHARS]; static char com_parsename[MAX_TOKEN_CHARS]; static int com_lines; +static int com_tokenline; void COM_BeginParseSession( const char *name ) { - com_lines = 0; + com_lines = 1; + com_tokenline = 0; Com_sprintf(com_parsename, sizeof(com_parsename), "%s", name); } int COM_GetCurrentParseLine( void ) { + if ( com_tokenline ) + { + return com_tokenline; + } + return com_lines; } @@ -312,7 +319,7 @@ void COM_ParseError( char *format, ... ) Q_vsnprintf (string, sizeof(string), format, argptr); va_end (argptr); - Com_Printf("ERROR: %s, line %d: %s\n", com_parsename, com_lines, string); + Com_Printf("ERROR: %s, line %d: %s\n", com_parsename, COM_GetCurrentParseLine(), string); } void COM_ParseWarning( char *format, ... ) @@ -324,7 +331,7 @@ void COM_ParseWarning( char *format, ... ) Q_vsnprintf (string, sizeof(string), format, argptr); va_end (argptr); - Com_Printf("WARNING: %s, line %d: %s\n", com_parsename, com_lines, string); + Com_Printf("WARNING: %s, line %d: %s\n", com_parsename, COM_GetCurrentParseLine(), string); } /* @@ -434,6 +441,7 @@ char *COM_ParseExt( char **data_p, qboolean allowLineBreaks ) data = *data_p; len = 0; com_token[0] = 0; + com_tokenline = 0; // make sure incoming data is valid if ( !data ) @@ -473,6 +481,10 @@ char *COM_ParseExt( char **data_p, qboolean allowLineBreaks ) data += 2; while ( *data && ( *data != '*' || data[1] != '/' ) ) { + if ( *data == '\n' ) + { + com_lines++; + } data++; } if ( *data ) @@ -486,6 +498,9 @@ char *COM_ParseExt( char **data_p, qboolean allowLineBreaks ) } } + // token starts on this line + com_tokenline = com_lines; + // handle quoted strings if (c == '\"') { @@ -499,6 +514,10 @@ char *COM_ParseExt( char **data_p, qboolean allowLineBreaks ) *data_p = ( char * ) data; return com_token; } + if ( c == '\n' ) + { + com_lines++; + } if (len < MAX_TOKEN_CHARS - 1) { com_token[len] = c; @@ -517,8 +536,6 @@ char *COM_ParseExt( char **data_p, qboolean allowLineBreaks ) } data++; c = *data; - if ( c == '\n' ) - com_lines++; } while (c>32); com_token[len] = 0; @@ -546,16 +563,14 @@ void COM_MatchToken( char **buf_p, char *match ) { ================= SkipBracedSection -The next token should be an open brace. +The next token should be an open brace or set depth to 1 if already parsed it. Skips until a matching close brace is found. Internal brace depths are properly skipped. ================= */ -void SkipBracedSection (char **program) { +qboolean SkipBracedSection (char **program, int depth) { char *token; - int depth; - depth = 0; do { token = COM_ParseExt( program, qtrue ); if( token[1] == 0 ) { @@ -567,6 +582,8 @@ void SkipBracedSection (char **program) { } } } while( depth && *program ); + + return ( depth == 0 ); } /* diff --git a/code/qcommon/q_shared.h b/code/qcommon/q_shared.h index d3faf73e..8dffa191 100644 --- a/code/qcommon/q_shared.h +++ b/code/qcommon/q_shared.h @@ -51,6 +51,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // Heartbeat for dpmaster protocol. You shouldn't change this unless you know what you're doing #define HEARTBEAT_FOR_MASTER "DarkPlaces" +// When com_gamename is LEGACY_MASTER_GAMENAME, use quake3 master protocol. +// You shouldn't change this unless you know what you're doing +#define LEGACY_MASTER_GAMENAME "Quake3Arena" +#define LEGACY_HEARTBEAT_FOR_MASTER "QuakeArena-1" + #define BASETA "missionpack" #ifndef PRODUCT_VERSION @@ -784,7 +789,7 @@ typedef struct pc_token_s void COM_MatchToken( char**buf_p, char *match ); -void SkipBracedSection (char **program); +qboolean SkipBracedSection (char **program, int depth); void SkipRestOfLine ( char **data ); void Parse1DMatrix (char **buf_p, int x, float *m); @@ -1216,7 +1221,7 @@ typedef struct playerState_s { // not communicated over the net at all int ping; // server to game info for scoreboard - int pmove_framecount; // FIXME: don't transmit over the network + int pmove_framecount; int jumppad_frame; int entityEventSequence; } playerState_t; diff --git a/code/qcommon/qcommon.h b/code/qcommon/qcommon.h index ab2642c3..ea64d3a8 100644 --- a/code/qcommon/qcommon.h +++ b/code/qcommon/qcommon.h @@ -95,9 +95,6 @@ float MSG_ReadAngle16 (msg_t *sb); void MSG_ReadData (msg_t *sb, void *buffer, int size); int MSG_LookaheadByte (msg_t *msg); -void MSG_WriteDeltaUsercmd( msg_t *msg, struct usercmd_s *from, struct usercmd_s *to ); -void MSG_ReadDeltaUsercmd( msg_t *msg, struct usercmd_s *from, struct usercmd_s *to ); - void MSG_WriteDeltaUsercmdKey( msg_t *msg, int key, usercmd_t *from, usercmd_t *to ); void MSG_ReadDeltaUsercmdKey( msg_t *msg, int key, usercmd_t *from, usercmd_t *to ); @@ -136,6 +133,8 @@ NET #define MAX_PACKET_USERCMDS 32 // max number of usercmd_t in a packet +#define MAX_SNAPSHOT_ENTITIES 256 + #define PORT_ANY -1 #define MAX_RELIABLE_COMMANDS 64 // max string commands buffered for restransmit @@ -625,7 +624,7 @@ qboolean FS_FileExists( const char *file ); qboolean FS_CreatePath (char *OSPath); -vmInterpret_t FS_FindVM(void **startSearch, char *found, int foundlen, const char *name, int enableDll); +int FS_FindVM(void **startSearch, char *found, int foundlen, const char *name, int enableDll); char *FS_BuildOSPath( const char *base, const char *game, const char *qpath ); qboolean FS_CompareZipChecksum(const char *zipfile); @@ -642,7 +641,7 @@ fileHandle_t FS_FCreateOpenPipeFile( const char *filename ); fileHandle_t FS_SV_FOpenFileWrite( const char *filename ); long FS_SV_FOpenFileRead( const char *filename, fileHandle_t *fp ); -void FS_SV_Rename( const char *from, const char *to ); +void FS_SV_Rename( const char *from, const char *to, qboolean safe ); long FS_FOpenFileRead( const char *qpath, fileHandle_t *file, qboolean uniqueFILE ); // if uniqueFILE is true, then a new FILE will be fopened even if the file // is found in an already open pak file. If uniqueFILE is false, you must call @@ -1089,8 +1088,6 @@ void Sys_Print( const char *msg ); // any game related timing information should come from event timestamps int Sys_Milliseconds (void); -void Sys_SnapVector( float *v ); - qboolean Sys_RandomBytes( byte *string, int len ); // the system console is shown when a dedicated server is running @@ -1108,6 +1105,7 @@ qboolean Sys_StringToAdr( const char *s, netadr_t *a, netadrtype_t family ); qboolean Sys_IsLANAddress (netadr_t adr); void Sys_ShowIP(void); +FILE *Sys_FOpen( const char *ospath, const char *mode ); qboolean Sys_Mkdir( const char *path ); FILE *Sys_Mkfifo( const char *ospath ); char *Sys_Cwd( void ); diff --git a/code/qcommon/qfiles.h b/code/qcommon/qfiles.h index cc4ba816..c03f1c20 100644 --- a/code/qcommon/qfiles.h +++ b/code/qcommon/qfiles.h @@ -282,12 +282,6 @@ typedef struct { * - Thilo Schulz (arny@ats.s.bawue.de) */ -// If you want to enable support for Raven's .mdr / md4 format, uncomment the next -// line. -//#define RAVENMD4 - -#ifdef RAVENMD4 - #define MDR_IDENT (('5'<<24)+('M'<<16)+('D'<<8)+'R') #define MDR_VERSION 2 #define MDR_MAX_BONES 128 @@ -390,7 +384,6 @@ typedef struct { int ofsEnd; // end of file } mdrHeader_t; -#endif /* ============================================================================== diff --git a/code/qcommon/unzip.c b/code/qcommon/unzip.c index 2dd0bf83..4fb2d3a9 100644 --- a/code/qcommon/unzip.c +++ b/code/qcommon/unzip.c @@ -713,18 +713,13 @@ local int unzlocal_GetCurrentFileInfoInternal (file, if (lSeek!=0) { - if (ZSEEK(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) - lSeek=0; - else + if (ZSEEK(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)!=0) err=UNZ_ERRNO; } if ((file_info.size_file_comment>0) && (commentBufferSize>0)) if (ZREAD(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead) err=UNZ_ERRNO; - lSeek+=file_info.size_file_comment - uSizeRead; } - else - lSeek+=file_info.size_file_comment; if ((err==UNZ_OK) && (pfile_info!=NULL)) *pfile_info=file_info; @@ -1144,13 +1139,12 @@ extern int ZEXPORT unzOpenCurrentFile3 (file, method, level, raw, password) pfile_in_zip_read_info->stream.next_in = (voidpf)0; pfile_in_zip_read_info->stream.avail_in = 0; - err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); - if (err == Z_OK) + if (inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS) == Z_OK) pfile_in_zip_read_info->stream_initialised=1; else { TRYFREE(pfile_in_zip_read_info); - return err; + return UNZ_INTERNALERROR; } /* windowBits is passed < 0 to tell that there is no zlib header. * Note that in this case inflate *requires* an extra "dummy" byte @@ -1197,7 +1191,7 @@ extern int ZEXPORT unzOpenCurrentFile3 (file, method, level, raw, password) # endif - return UNZ_OK; + return err; } extern int ZEXPORT unzOpenCurrentFile (file) diff --git a/code/qcommon/vm_powerpc.c b/code/qcommon/vm_powerpc.c index 60eb6bb6..3d9ede65 100644 --- a/code/qcommon/vm_powerpc.c +++ b/code/qcommon/vm_powerpc.c @@ -45,11 +45,7 @@ static clock_t time_total_vm = 0; #endif /* exit() won't be called but use it because it is marked with noreturn */ -#define DIE( reason ) \ - do { \ - Com_Error(ERR_DROP, "vm_powerpc compiler error: " reason); \ - exit(1); \ - } while(0) +#define DIE( reason ) Com_Error( ERR_DROP, "vm_powerpc compiler error: " reason ) /* * vm_powerpc uses large quantities of memory during compilation, @@ -1965,8 +1961,6 @@ PPC_ComputeCode( vm_t *vm ) di_now = di_first; } } - - return; } static void diff --git a/code/qcommon/vm_sparc.c b/code/qcommon/vm_sparc.c index 578294d5..d79b4324 100644 --- a/code/qcommon/vm_sparc.c +++ b/code/qcommon/vm_sparc.c @@ -701,7 +701,7 @@ static void dst_insn_append(struct func_info * const fp) static void ErrJump(void) { - Com_Error(ERR_DROP, "program tried to execute code outside VM\n"); + Com_Error(ERR_DROP, "program tried to execute code outside VM"); exit(1); } diff --git a/code/qcommon/vm_x86.c b/code/qcommon/vm_x86.c index be6c66bf..b896883d 100644 --- a/code/qcommon/vm_x86.c +++ b/code/qcommon/vm_x86.c @@ -381,10 +381,9 @@ Error handler for jump/call to invalid instruction number ================= */ -static void ErrJump(void) +static void __attribute__((__noreturn__)) ErrJump(void) { Com_Error(ERR_DROP, "program tried to execute code outside VM"); - exit(1); } /* diff --git a/code/qcommon/vm_x86_64.c b/code/qcommon/vm_x86_64.c deleted file mode 100644 index e91bf0e3..00000000 --- a/code/qcommon/vm_x86_64.c +++ /dev/null @@ -1,1096 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2005 Ludwig Nussel - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// vm_x86_64.c -- load time compiler and execution environment for x86-64 - -#include "vm_local.h" -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#ifdef __WIN64__ - #include - #define CROSSCALL __attribute__ ((sysv_abi))//fool the vm we're SYSV ABI - //#define __USE_MINGW_ANSI_STDIO 1 //very slow - avoid if possible -#else - #include - #include - #define VM_X86_64_MMAP - #define CROSSCALL -#endif - -//#define DEBUG_VM - -#ifdef DEBUG_VM -#define Dfprintf(fd, args...) fprintf(fd, ##args) -static FILE* qdasmout; -#else -#define Dfprintf(args...) -#endif - -#define VM_FREEBUFFERS(vm) do {assembler_init(0); VM_Destroy_Compiled(vm);} while(0) - -void assembler_set_output(char* buf); -size_t assembler_get_code_size(void); -void assembler_init(int pass); -void assemble_line(const char* input, size_t len); - -static void VM_Destroy_Compiled(vm_t* self); - -/* - - |=====================| - ^ dataMask ^- programStack rdi - | - +- r8 - - eax scratch - rbx/bl opStack offset - ecx scratch (required for shifts) - edx scratch (required for divisions) - rsi scratch - rdi program frame pointer (programStack) - r8 pointer data (vm->dataBase) - r9 opStack base (opStack) - r10 start of generated code -*/ - - -static intptr_t CROSSCALL callAsmCall(intptr_t callProgramStack, int64_t callSyscallNum) -{ - vm_t *savedVM; - intptr_t ret = 0x77; - intptr_t args[MAX_VMSYSCALL_ARGS]; -// int iargs[MAX_VMSYSCALL_ARGS]; - int i; - -// Dfprintf(stderr, "callAsmCall(%ld, %ld)\n", callProgramStack, callSyscallNum); -// Com_Printf("-> callAsmCall %s, level %d, num %ld\n", currentVM->name, currentVM->callLevel, callSyscallNum); - - savedVM = currentVM; - - // save the stack to allow recursive VM entry - currentVM->programStack = callProgramStack - 4; - - args[0] = callSyscallNum; -// iargs[0] = callSyscallNum; - for(i = 0; i < ARRAY_LEN(args)-1; ++i) - { -// iargs[i+1] = *(int *)((byte *)currentVM->dataBase + callProgramStack + 8 + 4*i); - args[i+1] = *(int *)((byte *)currentVM->dataBase + callProgramStack + 8 + 4*i); - } - ret = currentVM->systemCall(args); - - currentVM = savedVM; -// Com_Printf("<- callAsmCall %s, level %d, num %ld\n", currentVM->name, currentVM->callLevel, callSyscallNum); - - return ret; -} - -#ifdef DEBUG_VM -static char *opnames[256] = { - "OP_UNDEF", - - "OP_IGNORE", - - "OP_BREAK", - - "OP_ENTER", - "OP_LEAVE", - "OP_CALL", - "OP_PUSH", - "OP_POP", - - "OP_CONST", - - "OP_LOCAL", - - "OP_JUMP", - - //------------------- - - "OP_EQ", - "OP_NE", - - "OP_LTI", - "OP_LEI", - "OP_GTI", - "OP_GEI", - - "OP_LTU", - "OP_LEU", - "OP_GTU", - "OP_GEU", - - "OP_EQF", - "OP_NEF", - - "OP_LTF", - "OP_LEF", - "OP_GTF", - "OP_GEF", - - //------------------- - - "OP_LOAD1", - "OP_LOAD2", - "OP_LOAD4", - "OP_STORE1", - "OP_STORE2", - "OP_STORE4", - "OP_ARG", - - "OP_BLOCK_COPY", - - //------------------- - - "OP_SEX8", - "OP_SEX16", - - "OP_NEGI", - "OP_ADD", - "OP_SUB", - "OP_DIVI", - "OP_DIVU", - "OP_MODI", - "OP_MODU", - "OP_MULI", - "OP_MULU", - - "OP_BAND", - "OP_BOR", - "OP_BXOR", - "OP_BCOM", - - "OP_LSH", - "OP_RSHI", - "OP_RSHU", - - "OP_NEGF", - "OP_ADDF", - "OP_SUBF", - "OP_DIVF", - "OP_MULF", - - "OP_CVIF", - "OP_CVFI" -}; -#endif // DEBUG_VM - -static unsigned char op_argsize[256] = -{ - [OP_ENTER] = 4, - [OP_LEAVE] = 4, - [OP_CONST] = 4, - [OP_LOCAL] = 4, - [OP_EQ] = 4, - [OP_NE] = 4, - [OP_LTI] = 4, - [OP_LEI] = 4, - [OP_GTI] = 4, - [OP_GEI] = 4, - [OP_LTU] = 4, - [OP_LEU] = 4, - [OP_GTU] = 4, - [OP_GEU] = 4, - [OP_EQF] = 4, - [OP_NEF] = 4, - [OP_LTF] = 4, - [OP_LEF] = 4, - [OP_GTF] = 4, - [OP_GEF] = 4, - [OP_ARG] = 1, - [OP_BLOCK_COPY] = 4, -}; - -static __attribute__ ((format (printf, 1, 2))) void emit(const char* fmt, ...) -{ - va_list ap; - char line[4096]; - va_start(ap, fmt); - Q_vsnprintf(line, sizeof(line), fmt, ap); - va_end(ap); - assemble_line(line, strlen(line)); -} - -#ifdef DEBUG_VM -#define RANGECHECK(reg, bytes) \ - emit("movl %%" #reg ", %%ecx"); \ - emit("andl $0x%x, %%ecx", vm->dataMask &~(bytes-1)); \ - emit("cmpl %%" #reg ", %%ecx"); \ - emit("jz rc_ok_i_%08x", instruction); \ - emit("movq $%"PRIu64", %%rax", (intptr_t) memviolation); \ - emit("callq *%%rax"); \ - emit("rc_ok_i_%08x:", instruction) -#elif 1 -// check is too expensive, so just confine memory access -#define RANGECHECK(reg, bytes) \ - emit("andl $0x%x, %%" #reg, vm->dataMask &~(bytes-1)) -#else -#define RANGECHECK(reg, bytes) -#endif - -#define STACK_PUSH(bytes) \ - emit("addb $0x%x, %%bl", bytes >> 2); \ - -#define STACK_POP(bytes) \ - emit("subb $0x%x, %%bl", bytes >> 2); \ - -#define CHECK_INSTR_REG(reg) \ - emit("cmpl $%u, %%"#reg, header->instructionCount); \ - emit("jb jmp_ok_i_%08x", instruction); \ - emit("movq $%"PRIu64", %%rax", (intptr_t)jmpviolation); \ - emit("callq *%%rax"); \ - emit("jmp_ok_i_%08x:", instruction) - -#define PREPARE_JMP(reg) \ - CHECK_INSTR_REG(reg); \ - emit("movq $%"PRIu64", %%rsi", (intptr_t)vm->instructionPointers); \ - emit("movl (%%rsi, %%rax, 8), %%eax"); \ - emit("addq %%r10, %%rax") - -#define CHECK_INSTR(nr) \ - do { if(nr < 0 || nr >= header->instructionCount) { \ - VM_FREEBUFFERS(vm); \ - Com_Error( ERR_DROP, \ - "%s: jump target 0x%x out of range at offset %d", __func__, nr, pc ); \ - } } while(0) - -#define JMPIARG() \ - CHECK_INSTR(iarg); \ - emit("movq $%"PRIu64", %%rax", vm->codeBase+vm->instructionPointers[iarg]); \ - emit("jmpq *%%rax") - -#define CONST_OPTIMIZE -#ifdef CONST_OPTIMIZE -#define MAYBE_EMIT_CONST() \ - if (got_const) \ - { \ - got_const = 0; \ - vm->instructionPointers[instruction-1] = assembler_get_code_size(); \ - STACK_PUSH(4); \ - emit("movl $%d, (%%r9, %%rbx, 4)", const_value); \ - } -#else -#define MAYBE_EMIT_CONST() -#endif - -// integer compare and jump -#define IJ(op) \ - MAYBE_EMIT_CONST(); \ - STACK_POP(8); \ - emit("movl 4(%%r9, %%rbx, 4), %%eax"); \ - emit("cmpl 8(%%r9, %%rbx, 4), %%eax"); \ - emit(op " i_%08x", instruction+1); \ - JMPIARG(); \ - neednilabel = 1 - -#ifdef USE_X87 -#define FJ(bits, op) \ - MAYBE_EMIT_CONST(); \ - STACK_POP(8); \ - emit("flds 4(%%r9, %%rbx, 4)");\ - emit("fcomps 8(%%r9, %%rbx, 4)");\ - emit("fnstsw %%ax");\ - emit("testb $" #bits ", %%ah");\ - emit(op " i_%08x", instruction+1);\ - JMPIARG(); \ - neednilabel = 1 -#define XJ(x) -#else -#define FJ(x, y) -#define XJ(op) \ - MAYBE_EMIT_CONST(); \ - STACK_POP(8); \ - emit("movss 4(%%r9, %%rbx, 4), %%xmm0");\ - emit("ucomiss 8(%%r9, %%rbx, 4), %%xmm0");\ - emit("jp i_%08x", instruction+1);\ - emit(op " i_%08x", instruction+1);\ - JMPIARG(); \ - neednilabel = 1 -#endif - -#define SIMPLE(op) \ - MAYBE_EMIT_CONST(); \ - emit("movl (%%r9, %%rbx, 4), %%eax"); \ - STACK_POP(4); \ - emit(op " %%eax, (%%r9, %%rbx, 4)") - -#ifdef USE_X87 -#define FSIMPLE(op) \ - MAYBE_EMIT_CONST(); \ - STACK_POP(4); \ - emit("flds (%%r9, %%rbx, 4)"); \ - emit(op " 4(%%r9, %%rbx, 4)"); \ - emit("fstps (%%r9, %%rbx, 4)") -#define XSIMPLE(op) -#else -#define FSIMPLE(op) -#define XSIMPLE(op) \ - MAYBE_EMIT_CONST(); \ - STACK_POP(4); \ - emit("movss (%%r9, %%rbx, 4), %%xmm0"); \ - emit(op " 4(%%r9, %%rbx, 4), %%xmm0"); \ - emit("movss %%xmm0, (%%r9, %%rbx, 4)") -#endif - -#define SHIFT(op) \ - MAYBE_EMIT_CONST(); \ - STACK_POP(4); \ - emit("movl 4(%%r9, %%rbx, 4), %%ecx"); \ - emit("movl (%%r9, %%rbx, 4), %%eax"); \ - emit(op " %%cl, %%eax"); \ - emit("movl %%eax, (%%r9, %%rbx, 4)") - -#ifdef DEBUG_VM -#define NOTIMPL(x) \ - do { Com_Error(ERR_DROP, "instruction not implemented: %s", opnames[x]); } while(0) -#else -#define NOTIMPL(x) \ - do { Com_Printf(S_COLOR_RED "instruction not implemented: %x\n", x); vm->compiled = qfalse; return; } while(0) -#endif - -static void* getentrypoint(vm_t* vm) -{ - return vm->codeBase; -} - -static __attribute__ ((noreturn)) void CROSSCALL eop(void) -{ - Com_Error(ERR_DROP, "End of program reached without return!"); - exit(1); -} - -static __attribute__ ((noreturn)) void CROSSCALL jmpviolation(void) -{ - Com_Error(ERR_DROP, "Program tried to execute code outside VM"); - exit(1); -} - -#ifdef DEBUG_VM -static __attribute__ ((noreturn)) void CROSSCALL memviolation(void) -{ - Com_Error(ERR_DROP, "Program tried to access memory outside VM, or unaligned memory access"); - exit(1); -} - -static __attribute__ ((noreturn)) void CROSSCALL opstackviolation(void) -{ - Com_Error(ERR_DROP, "Program corrupted the VM opStack"); - exit(1); -} -#endif - -/* -================= -VM_Compile -================= -*/ -void VM_Compile( vm_t *vm, vmHeader_t *header ) { - unsigned char op; - int pc; - unsigned instruction; - char* code; - unsigned iarg = 0; - unsigned char barg = 0; - int neednilabel = 0; - struct timeval tvstart = {0, 0}; -#ifdef DEBUG_VM - char fn_d[MAX_QPATH]; // disassembled -#endif - - int pass; - size_t compiledOfs = 0; - - // const optimization - unsigned got_const = 0, const_value = 0; - - vm->codeBase = NULL; - - gettimeofday(&tvstart, NULL); - - for (pass = 0; pass < 2; ++pass) { - - if(pass) - { - compiledOfs = assembler_get_code_size(); - vm->codeLength = compiledOfs; - - #ifdef VM_X86_64_MMAP - vm->codeBase = mmap(NULL, compiledOfs, PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); - if(vm->codeBase == MAP_FAILED) - Com_Error(ERR_FATAL, "VM_CompileX86_64: can't mmap memory"); - #elif __WIN64__ - // allocate memory with write permissions under windows. - vm->codeBase = VirtualAlloc(NULL, compiledOfs, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); - if(!vm->codeBase) - Com_Error(ERR_FATAL, "VM_CompileX86_64: VirtualAlloc failed"); - #else - vm->codeBase = malloc(compiledOfs); - if(!vm_codeBase) - Com_Error(ERR_FATAL, "VM_CompileX86_64: Failed to allocate memory"); - #endif - - assembler_set_output((char*)vm->codeBase); - } - - assembler_init(pass); - -#ifdef DEBUG_VM - strcpy(fn_d,vm->name); - strcat(fn_d, ".qdasm"); - - qdasmout = fopen(fn_d, "w"); -#endif - - // translate all instructions - pc = 0; - code = (char *)header + header->codeOffset; - - for ( instruction = 0; instruction < header->instructionCount; ++instruction ) - { - op = code[ pc ]; - ++pc; - - vm->instructionPointers[instruction] = assembler_get_code_size(); - - /* store current instruction number in r15 for debugging */ -#if DEBUG_VM0 - emit("nop"); - emit("movq $%d, %%r15", instruction); - emit("nop"); -#endif - - if(op_argsize[op] == 4) - { - iarg = *(int*)(code+pc); - pc += 4; - Dfprintf(qdasmout, "%s %8u\n", opnames[op], iarg); - } - else if(op_argsize[op] == 1) - { - barg = code[pc++]; - Dfprintf(qdasmout, "%s %8hu\n", opnames[op], barg); - } - else - { - Dfprintf(qdasmout, "%s\n", opnames[op]); - } - - if(neednilabel) - { - emit("i_%08x:", instruction); - neednilabel = 0; - } - - switch ( op ) - { - case OP_UNDEF: - NOTIMPL(op); - break; - case OP_IGNORE: - MAYBE_EMIT_CONST(); - emit("nop"); - break; - case OP_BREAK: - MAYBE_EMIT_CONST(); - emit("int3"); - break; - case OP_ENTER: - MAYBE_EMIT_CONST(); - emit("subl $%d, %%edi", iarg); - break; - case OP_LEAVE: - MAYBE_EMIT_CONST(); - emit("addl $%d, %%edi", iarg); // get rid of stack frame - emit("ret"); - break; - case OP_CALL: - RANGECHECK(edi, 4); - emit("movl $%d, (%%r8, %%rdi, 1)", instruction+1); // save next instruction - - if(got_const) - { - if ((int) const_value >= 0) - { - CHECK_INSTR(const_value); - emit("movq $%"PRIu64", %%rax", vm->codeBase+vm->instructionPointers[const_value]); - emit("callq *%%rax"); - got_const = 0; - break; - } - } - else - { - MAYBE_EMIT_CONST(); - emit("movl (%%r9, %%rbx, 4), %%eax"); // get instr from stack - STACK_POP(4); - - emit("orl %%eax, %%eax"); - emit("jl callSyscall%d", instruction); - - PREPARE_JMP(eax); - emit("callq *%%rax"); - - emit("jmp i_%08x", instruction+1); - emit("callSyscall%d:", instruction); - } - -// emit("fnsave 4(%%r9, %%rsi, 1)"); - emit("push %%rdi"); - emit("push %%r8"); - emit("push %%r9"); - emit("push %%r10"); - emit("movq %%rsp, %%rsi"); // we need to align the stack pointer - emit("subq $8, %%rsi"); // | - emit("andq $127, %%rsi"); // | - emit("subq %%rsi, %%rsp"); // <-+ - emit("push %%rsi"); - if(got_const) { - got_const = 0; - emit("movq $%u, %%rsi", -1-const_value); // second argument in rsi - } else { - emit("notl %%eax"); // convert to actual number - // first argument already in rdi - emit("movq %%rax, %%rsi"); // second argument in rsi - } - emit("movq $%"PRIu64", %%rax", (intptr_t) callAsmCall); - emit("callq *%%rax"); - emit("pop %%rsi"); - emit("addq %%rsi, %%rsp"); - emit("pop %%r10"); - emit("pop %%r9"); - emit("pop %%r8"); - emit("pop %%rdi"); -// emit("frstor 4(%%r9, %%rsi, 1)"); - STACK_PUSH(4); - emit("movl %%eax, (%%r9, %%rbx, 4)"); // store return value - neednilabel = 1; - break; - case OP_PUSH: - MAYBE_EMIT_CONST(); - STACK_PUSH(4); - break; - case OP_POP: - MAYBE_EMIT_CONST(); - STACK_POP(4); - break; - case OP_CONST: - MAYBE_EMIT_CONST(); -#ifdef CONST_OPTIMIZE - got_const = 1; - const_value = iarg; -#else - STACK_PUSH(4); - emit("movl $%d, (%%r9, %%rbx, 4)", iarg); -#endif - break; - case OP_LOCAL: - MAYBE_EMIT_CONST(); - emit("movl %%edi, %%esi"); - emit("addl $%d,%%esi", iarg); - STACK_PUSH(4); - emit("movl %%esi, (%%r9, %%rbx, 4)"); - break; - case OP_JUMP: - if(got_const) { - iarg = const_value; - got_const = 0; - JMPIARG(); - } else { - emit("movl (%%r9, %%rbx, 4), %%eax"); // get instr from stack - STACK_POP(4); - - PREPARE_JMP(eax); - emit("jmp *%%rax"); - } - break; - case OP_EQ: - IJ("jne"); - break; - case OP_NE: - IJ("je"); - break; - case OP_LTI: - IJ("jnl"); - break; - case OP_LEI: - IJ("jnle"); - break; - case OP_GTI: - IJ("jng"); - break; - case OP_GEI: - IJ("jnge"); - break; - case OP_LTU: - IJ("jnb"); - break; - case OP_LEU: - IJ("jnbe"); - break; - case OP_GTU: - IJ("jna"); - break; - case OP_GEU: - IJ("jnae"); - break; - case OP_EQF: - FJ(0x40, "jz"); - XJ("jnz"); - break; - case OP_NEF: - FJ(0x40, "jnz"); -#ifndef USE_X87 - MAYBE_EMIT_CONST(); - STACK_POP(8); - emit("movss 4(%%r9, %%rbx, 4), %%xmm0"); - emit("ucomiss 8(%%r9, %%rbx, 4), %%xmm0"); - emit("jp dojump_i_%08x", instruction); - emit("jz i_%08x", instruction+1); - emit("dojump_i_%08x:", instruction); - JMPIARG(); - neednilabel = 1; -#endif - break; - case OP_LTF: - FJ(0x01, "jz"); - XJ("jnc"); - break; - case OP_LEF: - FJ(0x41, "jz"); - XJ("ja"); - break; - case OP_GTF: - FJ(0x41, "jnz"); - XJ("jbe"); - break; - case OP_GEF: - FJ(0x01, "jnz"); - XJ("jb"); - break; - case OP_LOAD1: - MAYBE_EMIT_CONST(); - emit("movl (%%r9, %%rbx, 4), %%eax"); // get value from stack - RANGECHECK(eax, 1); - emit("movb (%%r8, %%rax, 1), %%al"); // deref into eax - emit("andq $255, %%rax"); - emit("movl %%eax, (%%r9, %%rbx, 4)"); // store on stack - break; - case OP_LOAD2: - MAYBE_EMIT_CONST(); - emit("movl (%%r9, %%rbx, 4), %%eax"); // get value from stack - RANGECHECK(eax, 2); - emit("movw (%%r8, %%rax, 1), %%ax"); // deref into eax - emit("movl %%eax, (%%r9, %%rbx, 4)"); // store on stack - break; - case OP_LOAD4: - MAYBE_EMIT_CONST(); - emit("movl (%%r9, %%rbx, 4), %%eax"); // get value from stack - RANGECHECK(eax, 4); // not a pointer!? - emit("movl (%%r8, %%rax, 1), %%eax"); // deref into eax - emit("movl %%eax, (%%r9, %%rbx, 4)"); // store on stack - break; - case OP_STORE1: - MAYBE_EMIT_CONST(); - emit("movl (%%r9, %%rbx, 4), %%eax"); // get value from stack - STACK_POP(8); - emit("andq $255, %%rax"); - emit("movl 4(%%r9, %%rbx, 4), %%esi"); // get pointer from stack - RANGECHECK(esi, 1); - emit("movb %%al, (%%r8, %%rsi, 1)"); // store in memory - break; - case OP_STORE2: - MAYBE_EMIT_CONST(); - emit("movl (%%r9, %%rbx, 4), %%eax"); // get value from stack - STACK_POP(8); - emit("movl 4(%%r9, %%rbx, 4), %%esi"); // get pointer from stack - RANGECHECK(esi, 2); - emit("movw %%ax, (%%r8, %%rsi, 1)"); // store in memory - break; - case OP_STORE4: - MAYBE_EMIT_CONST(); - emit("movl (%%r9, %%rbx, 4), %%eax"); // get value from stack - STACK_POP(8); - emit("movl 4(%%r9, %%rbx, 4), %%esi"); // get pointer from stack - RANGECHECK(esi, 4); - emit("movl %%eax, (%%r8, %%rsi, 1)"); // store in memory - break; - case OP_ARG: - MAYBE_EMIT_CONST(); - emit("movl (%%r9, %%rbx, 4), %%eax"); // get value from stack - STACK_POP(4); - emit("movl $0x%hx, %%esi", barg); - emit("addl %%edi, %%esi"); - RANGECHECK(esi, 4); - emit("movl %%eax, (%%r8,%%rsi, 1)"); // store in args space - break; - case OP_BLOCK_COPY: - - MAYBE_EMIT_CONST(); - STACK_POP(8); - emit("push %%rdi"); - emit("push %%r8"); - emit("push %%r9"); - emit("push %%r10"); - emit("movq %%rsp, %%rsi"); // we need to align the stack pointer - emit("subq $8, %%rsi"); // | - emit("andq $127, %%rsi"); // | - emit("subq %%rsi, %%rsp"); // <-+ - emit("push %%rsi"); - emit("movl 4(%%r9, %%rbx, 4), %%edi"); // 1st argument dest - emit("movl 8(%%r9, %%rbx, 4), %%rsi"); // 2nd argument src - emit("movl $%d, %%edx", iarg); // 3rd argument count - emit("movq $%"PRIu64", %%rax", (intptr_t) VM_BlockCopy); - emit("callq *%%rax"); - emit("pop %%rsi"); - emit("addq %%rsi, %%rsp"); - emit("pop %%r10"); - emit("pop %%r9"); - emit("pop %%r8"); - emit("pop %%rdi"); - - break; - case OP_SEX8: - MAYBE_EMIT_CONST(); - emit("movw (%%r9, %%rbx, 4), %%ax"); - emit("andq $255, %%rax"); - emit("cbw"); - emit("cwde"); - emit("movl %%eax, (%%r9, %%rbx, 4)"); - break; - case OP_SEX16: - MAYBE_EMIT_CONST(); - emit("movw (%%r9, %%rbx, 4), %%ax"); - emit("cwde"); - emit("movl %%eax, (%%r9, %%rbx, 4)"); - break; - case OP_NEGI: - MAYBE_EMIT_CONST(); - emit("negl (%%r9, %%rbx, 4)"); - break; - case OP_ADD: - SIMPLE("addl"); - break; - case OP_SUB: - SIMPLE("subl"); - break; - case OP_DIVI: - MAYBE_EMIT_CONST(); - STACK_POP(4); - emit("movl (%%r9, %%rbx, 4), %%eax"); - emit("cdq"); - emit("idivl 4(%%r9, %%rbx, 4)"); - emit("movl %%eax, (%%r9, %%rbx, 4)"); - break; - case OP_DIVU: - MAYBE_EMIT_CONST(); - STACK_POP(4); - emit("movl (%%r9, %%rbx, 4), %%eax"); - emit("xorq %%rdx, %%rdx"); - emit("divl 4(%%r9, %%rbx, 4)"); - emit("movl %%eax, (%%r9, %%rbx, 4)"); - break; - case OP_MODI: - MAYBE_EMIT_CONST(); - STACK_POP(4); - emit("movl (%%r9, %%rbx, 4), %%eax"); - emit("xorl %%edx, %%edx"); - emit("cdq"); - emit("idivl 4(%%r9, %%rbx, 4)"); - emit("movl %%edx, (%%r9, %%rbx, 4)"); - break; - case OP_MODU: - MAYBE_EMIT_CONST(); - STACK_POP(4); - emit("movl (%%r9, %%rbx, 4), %%eax"); - emit("xorl %%edx, %%edx"); - emit("divl 4(%%r9, %%rbx, 4)"); - emit("movl %%edx, (%%r9, %%rbx, 4)"); - break; - case OP_MULI: - MAYBE_EMIT_CONST(); - STACK_POP(4); - emit("movl (%%r9, %%rbx, 4), %%eax"); - emit("imull 4(%%r9, %%rbx, 4)"); - emit("movl %%eax, (%%r9, %%rbx, 4)"); - break; - case OP_MULU: - MAYBE_EMIT_CONST(); - STACK_POP(4); - emit("movl (%%r9, %%rbx, 4), %%eax"); - emit("mull 4(%%r9, %%rbx, 4)"); - emit("movl %%eax, (%%r9, %%rbx, 4)"); - break; - case OP_BAND: - SIMPLE("andl"); - break; - case OP_BOR: - SIMPLE("orl"); - break; - case OP_BXOR: - SIMPLE("xorl"); - break; - case OP_BCOM: - MAYBE_EMIT_CONST(); - emit("notl (%%r9, %%rbx, 4)"); - break; - case OP_LSH: - SHIFT("shl"); - break; - case OP_RSHI: - SHIFT("sarl"); - break; - case OP_RSHU: - SHIFT("shrl"); - break; - case OP_NEGF: - MAYBE_EMIT_CONST(); -#ifdef USE_X87 - emit("flds (%%r9, %%rbx, 4)"); - emit("fchs"); - emit("fstps (%%r9, %%rbx, 4)"); -#else - emit("movl $0x80000000, %%eax"); - emit("xorl %%eax, (%%r9, %%rbx, 4)"); -#endif - break; - case OP_ADDF: - FSIMPLE("fadds"); - XSIMPLE("addss"); - break; - case OP_SUBF: - FSIMPLE("fsubs"); - XSIMPLE("subss"); - break; - case OP_DIVF: - FSIMPLE("fdivs"); - XSIMPLE("divss"); - break; - case OP_MULF: - FSIMPLE("fmuls"); - XSIMPLE("mulss"); - break; - case OP_CVIF: - MAYBE_EMIT_CONST(); -#ifdef USE_X87 - emit("filds (%%r9, %%rbx, 4)"); - emit("fstps (%%r9, %%rbx, 4)"); -#else - emit("movl (%%r9, %%rbx, 4), %%eax"); - emit("cvtsi2ss %%eax, %%xmm0"); - emit("movss %%xmm0, (%%r9, %%rbx, 4)"); -#endif - break; - case OP_CVFI: - MAYBE_EMIT_CONST(); -#ifdef USE_X87 - emit("flds (%%r9, %%rbx, 4)"); - emit("fnstcw 4(%%r9, %%rbx, 4)"); - emit("movw $0x0F7F, 8(%%r9, %%rbx, 4)"); // round toward zero - emit("fldcw 8(%%r9, %%rbx, 4)"); - emit("fistpl (%%r9, %%rbx, 4)"); - emit("fldcw 4(%%r9, %%rbx, 4)"); -#else - emit("movss (%%r9, %%rbx, 4), %%xmm0"); - emit("cvttss2si %%xmm0, %%eax"); - emit("movl %%eax, (%%r9, %%rbx, 4)"); -#endif - break; - default: - NOTIMPL(op); - break; - } - - - } - - if(got_const) - { - VM_FREEBUFFERS(vm); - Com_Error(ERR_DROP, "leftover const"); - } - - emit("movq $%"PRIu64", %%rax", (intptr_t) eop); - emit("callq *%%rax"); - - } // pass loop - - assembler_init(0); - - #ifdef VM_X86_64_MMAP - if(mprotect(vm->codeBase, compiledOfs, PROT_READ|PROT_EXEC)) - Com_Error(ERR_FATAL, "VM_CompileX86_64: mprotect failed"); - #elif __WIN64__ - { - DWORD oldProtect = 0; - - // remove write permissions; give exec permision - if(!VirtualProtect(vm->codeBase, compiledOfs, PAGE_EXECUTE_READ, &oldProtect)) - Com_Error(ERR_FATAL, "VM_CompileX86_64: VirtualProtect failed"); - } - #endif - - vm->destroy = VM_Destroy_Compiled; - -#ifdef DEBUG_VM - fflush(qdasmout); - fclose(qdasmout); - -#if 0 - strcpy(fn_d,vm->name); - strcat(fn_d, ".bin"); - qdasmout = fopen(fn_d, "w"); - fwrite(vm->codeBase, compiledOfs, 1, qdasmout); - fflush(qdasmout); - fclose(qdasmout); -#endif -#endif - - #ifndef __WIN64__ //timersub and gettimeofday - if(vm->compiled) - { - struct timeval tvdone = {0, 0}; - struct timeval dur = {0, 0}; - Com_Printf( "VM file %s compiled to %i bytes of code (%p - %p)\n", vm->name, vm->codeLength, vm->codeBase, vm->codeBase+vm->codeLength ); - - gettimeofday(&tvdone, NULL); - timersub(&tvdone, &tvstart, &dur); - Com_Printf( "compilation took %"PRIu64".%06"PRIu64" seconds\n", dur.tv_sec, dur.tv_usec ); - } - #endif -} - - -void VM_Destroy_Compiled(vm_t* self) -{ - if(self && self->codeBase) - { -#ifdef VM_X86_64_MMAP - munmap(self->codeBase, self->codeLength); -#elif __WIN64__ - VirtualFree(self->codeBase, 0, MEM_RELEASE); -#else - free(self->codeBase); -#endif - } -} - -/* -============== -VM_CallCompiled - -This function is called directly by the generated code -============== -*/ - -#ifdef DEBUG_VM -static char* memData; -#endif - -int VM_CallCompiled(vm_t *vm, int *args) -{ - int stack[OPSTACK_SIZE + 15]; - int programCounter; - int programStack; - int stackOnEntry; - long opStackRet; - byte *image; - void *entryPoint; - int *opStack; - int arg; - - currentVM = vm; - -// Com_Printf("entering %s level %d, call %d, arg1 = 0x%x\n", vm->name, vm->callLevel, args[0], args[1]); - - // interpret the code - vm->currentlyInterpreting = qtrue; - -// callMask = vm->dataMask; - - // we might be called recursively, so this might not be the very top - programStack = vm->programStack; - stackOnEntry = programStack; - - // set up the stack frame - image = vm->dataBase; -#ifdef DEBUG_VM - memData = (char*)image; -#endif - - programCounter = 0; - - programStack -= ( 8 + 4 * MAX_VMMAIN_ARGS ); - - for ( arg = 0; arg < MAX_VMMAIN_ARGS; arg++ ) - *(int *)&image[ programStack + 8 + arg * 4 ] = args[ arg ]; - - *(int *)&image[ programStack + 4 ] = 0x77777777; // return stack - *(int *)&image[ programStack ] = -1; // will terminate the loop on return - - // off we go into generated code... - entryPoint = getentrypoint(vm); - opStack = PADP(stack, 16); - - *opStack = 0xDEADBEEF; - opStackRet = 0; - - __asm__ __volatile__ ( - " movq %4,%%r8 \r\n" \ - " movq %3,%%r9 \r\n" \ - " movq %2,%%r10 \r\n" \ - " push %%r15 \r\n" \ - " push %%r14 \r\n" \ - " push %%r13 \r\n" \ - " push %%r12 \r\n" \ - " subq $24, %%rsp # fix alignment as call pushes one value \r\n" \ - " callq *%%r10 \r\n" \ - " addq $24, %%rsp \r\n" \ - " pop %%r12 \r\n" \ - " pop %%r13 \r\n" \ - " pop %%r14 \r\n" \ - " pop %%r15 \r\n" - : "+D" (programStack), "+b" (opStackRet) - : "g" (entryPoint), "g" (opStack), "g" (vm->dataBase), "g" (programStack) - : "%rsi", "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%xmm0" - ); - - if(opStackRet != 1 || *opStack != 0xDEADBEEF) - Com_Error(ERR_DROP, "opStack corrupted in compiled code (offset %ld)", opStackRet); - - if ( programStack != stackOnEntry - ( 8 + 4 * MAX_VMMAIN_ARGS ) ) { - Com_Error( ERR_DROP, "programStack corrupted in compiled code" ); - } - -// Com_Printf("exiting %s level %d\n", vm->name, vm->callLevel); - vm->programStack = stackOnEntry; - - return stack[1]; -} diff --git a/code/qcommon/vm_x86_64_assembler.c b/code/qcommon/vm_x86_64_assembler.c deleted file mode 100644 index 825d0ae6..00000000 --- a/code/qcommon/vm_x86_64_assembler.c +++ /dev/null @@ -1,1461 +0,0 @@ -/* -=========================================================================== -vm_x86_64_assembler.c -- assembler for x86-64 - -Copyright (C) 2007 Ludwig Nussel , Novell inc. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -#define _ISOC99_SOURCE - -#include "vm_local.h" -#include -#include -#include -#include - -#include - -// Ignore __attribute__ on non-gcc platforms -#ifndef __GNUC__ -#ifndef __attribute__ -#define __attribute__(x) -#endif -#endif - -typedef uint8_t u8; -typedef uint16_t u16; -typedef uint32_t u32; -typedef uint64_t u64; - -static char* out; -static unsigned compiledOfs; -static unsigned assembler_pass; - -static const char* cur_line; - -static FILE* fout; - -#define crap(fmt, args...) do { \ - _crap(__FUNCTION__, fmt, ##args); \ -} while(0) - -#define CRAP_INVALID_ARGS crap("invalid arguments %s, %s", argtype2str(arg1.type),argtype2str(arg2.type)); - -#ifdef DEBUG -#define debug(fmt, args...) printf(fmt, ##args) -#else -#define debug(fmt, args...) -#endif - -static __attribute__ ((noreturn)) __attribute__ ((format (printf, 2, 3))) void _crap(const char* func, const char* fmt, ...) -{ - va_list ap; - fprintf(stderr, "%s() - ", func); - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - fputc('\n', stderr); - if(cur_line && cur_line[0]) - fprintf(stderr, "-> %s\n", cur_line); - exit(1); -} - -static void emit1(unsigned char v) -{ - int writecnt; - - if(assembler_pass) - { - out[compiledOfs++] = v; - - if(fout) - writecnt = fwrite(&v, 1, 1, fout); - - debug("%02hx ", v); - } - else - { - ++compiledOfs; - } -} - -static inline void emit2(u16 v) -{ - emit1(v&0xFF); - emit1((v>>8)&0xFF); -} - -static inline void emit4(u32 v) -{ - emit1(v&0xFF); - emit1((v>>8)&0xFF); - emit1((v>>16)&0xFF); - emit1((v>>24)&0xFF); -} - -static inline void emit8(u64 v) -{ - emit4(v&0xFFFFFFFF); - emit4((v>>32)&0xFFFFFFFF); -} - -enum { - REX_W = 0x08, - REX_R = 0x04, - REX_X = 0x02, - REX_B = 0x01, -}; - -enum { - MODRM_MOD_00 = 0x00, - MODRM_MOD_01 = 0x01 << 6, - MODRM_MOD_10 = 0x02 << 6, - MODRM_MOD_11 = 0x03 << 6, - MODRM_RM_SIB = 0x04, -}; - -typedef enum -{ - T_NONE = 0x00, - T_REGISTER = 0x01, - T_IMMEDIATE = 0x02, - T_MEMORY = 0x04, - T_LABEL = 0x08, - T_ABSOLUTE = 0x80 -} argtype_t; - -typedef enum { - R_8 = 0x100, - R_16 = 0x200, - R_64 = 0x800, - R_MSZ = 0xF00, // size mask - R_XMM = 0x2000, // xmm register. year, sucks - R_EAX = 0x00, - R_EBX = 0x03, - R_ECX = 0x01, - R_EDX = 0x02, - R_ESI = 0x06, - R_EDI = 0x07, - R_ESP = 0x04, - R_RAX = R_EAX | R_64, - R_RBX = R_EBX | R_64, - R_RCX = R_ECX | R_64, - R_RDX = R_EDX | R_64, - R_RSI = R_ESI | R_64, - R_RDI = R_EDI | R_64, - R_RSP = R_ESP | R_64, - R_R8 = 0x08 | R_64, - R_R9 = 0x09 | R_64, - R_R10 = 0x0A | R_64, - R_R15 = 0x0F | R_64, - R_AL = R_EAX | R_8, - R_AX = R_EAX | R_16, - R_BL = R_EBX | R_8, - R_CL = R_ECX | R_8, - R_XMM0 = 0x00 | R_XMM, - R_MGP = 0x0F, // mask for general purpose registers -} reg_t; - -typedef enum { - MODRM_SIB = 0, - MODRM_NOSIB = 0x3, -} modrm_sib_t; - -typedef struct { - unsigned disp; - argtype_t basetype; - union { - u64 imm; - reg_t reg; - } base; - argtype_t indextype; - union { - u64 imm; - reg_t reg; - } index; - unsigned scale; -} memref_t; - -#define LABELLEN 32 - -typedef struct { - argtype_t type; - union { - u64 imm; - reg_t reg; - memref_t mem; - char label[LABELLEN]; - } v; - int absolute:1; -} arg_t; - -typedef void (*emitfunc)(const char* op, arg_t arg1, arg_t arg2, void* data); - -typedef struct { - char* mnemonic; - emitfunc func; - void* data; -} op_t; - -typedef struct { - u8 xmmprefix; - u8 subcode; // in modrm - u8 rmcode; // opcode for reg/mem, reg - u8 mrcode; // opcode for reg, reg/mem - u8 rcode8; // opcode for reg8/mem8 - u8 rcode; // opcode for reg/mem -} opparam_t; - -static opparam_t params_add = { subcode: 0, rmcode: 0x01, }; -static opparam_t params_or = { subcode: 1, rmcode: 0x09, }; -static opparam_t params_and = { subcode: 4, rmcode: 0x21, }; -static opparam_t params_sub = { subcode: 5, rmcode: 0x29, }; -static opparam_t params_xor = { subcode: 6, rmcode: 0x31, }; -static opparam_t params_cmp = { subcode: 7, rmcode: 0x39, mrcode: 0x3b, }; -static opparam_t params_dec = { subcode: 1, rcode: 0xff, rcode8: 0xfe, }; -static opparam_t params_sar = { subcode: 7, rcode: 0xd3, rcode8: 0xd2, }; -static opparam_t params_shl = { subcode: 4, rcode: 0xd3, rcode8: 0xd2, }; -static opparam_t params_shr = { subcode: 5, rcode: 0xd3, rcode8: 0xd2, }; -static opparam_t params_idiv = { subcode: 7, rcode: 0xf7, rcode8: 0xf6, }; -static opparam_t params_div = { subcode: 6, rcode: 0xf7, rcode8: 0xf6, }; -static opparam_t params_imul = { subcode: 5, rcode: 0xf7, rcode8: 0xf6, }; -static opparam_t params_mul = { subcode: 4, rcode: 0xf7, rcode8: 0xf6, }; -static opparam_t params_neg = { subcode: 3, rcode: 0xf7, rcode8: 0xf6, }; -static opparam_t params_not = { subcode: 2, rcode: 0xf7, rcode8: 0xf6, }; - -static opparam_t params_cvtsi2ss = { xmmprefix: 0xf3, rmcode: 0x2a }; -static opparam_t params_cvttss2si = { xmmprefix: 0xf3, rmcode: 0x2c }; -static opparam_t params_addss = { xmmprefix: 0xf3, mrcode: 0x58 }; -static opparam_t params_divss = { xmmprefix: 0xf3, mrcode: 0x5e }; -static opparam_t params_movss = { xmmprefix: 0xf3, mrcode: 0x10, rmcode: 0x11 }; -static opparam_t params_mulss = { xmmprefix: 0xf3, mrcode: 0x59 }; -static opparam_t params_subss = { xmmprefix: 0xf3, mrcode: 0x5c }; -static opparam_t params_ucomiss = { mrcode: 0x2e }; - -/* ************************* */ - -static unsigned hashkey(const char *string, unsigned len) { - unsigned register hash, i; - - hash = 0; - for (i = 0; i < len && string[i] != '\0'; ++i) { - hash += string[i] * (119 + i); - } - hash = (hash ^ (hash >> 10) ^ (hash >> 20)); - return hash; -} - -struct hashentry { - char* label; - unsigned address; - struct hashentry* next; -}; -static struct hashentry* labelhash[1021]; - -// no dup check! -static void hash_add_label(const char* label, unsigned address) -{ - struct hashentry* h; - unsigned i = hashkey(label, -1U); - int labellen; - - i %= ARRAY_LEN(labelhash); - h = Z_Malloc(sizeof(struct hashentry)); - - labellen = strlen(label) + 1; - h->label = Z_Malloc(labellen); - memcpy(h->label, label, labellen); - - h->address = address; - h->next = labelhash[i]; - labelhash[i] = h; -} - -static unsigned lookup_label(const char* label) -{ - struct hashentry* h; - unsigned i = hashkey(label, -1U); - i %= ARRAY_LEN(labelhash); - for(h = labelhash[i]; h; h = h->next ) - { - if(!strcmp(h->label, label)) - return h->address; - } - if(assembler_pass) - crap("label %s undefined", label); - return 0; -} - -static void labelhash_free(void) -{ - struct hashentry* h; - unsigned i; - unsigned z = 0, min = -1U, max = 0, t = 0; - for ( i = 0; i < ARRAY_LEN(labelhash); ++i) - { - unsigned n = 0; - h = labelhash[i]; - while(h) - { - struct hashentry* next = h->next; - Z_Free(h->label); - Z_Free(h); - h = next; - ++n; - } - t+=n; - if(!n) ++z; - //else printf("%u\n", n); - min = MIN(min, n); - max = MAX(max, n); - } - printf("total %u, hsize %"PRIu64", zero %u, min %u, max %u\n", t, ARRAY_LEN(labelhash), z, min, max); - memset(labelhash, 0, sizeof(labelhash)); -} - -/* ************************* */ - - -static const char* argtype2str(argtype_t t) -{ - switch(t) - { - case T_NONE: return "none"; - case T_REGISTER: return "register"; - case T_IMMEDIATE: return "immediate"; - case T_MEMORY: return "memory"; - case T_LABEL: return "label"; - default: crap("invalid type"); - } - /* not reached */ - return T_NONE; -} - -/* ************************* */ - -static inline int iss8(int64_t v) -{ - return (SCHAR_MIN <= v && v <= SCHAR_MAX); -} - -static inline int isu8(u64 v) -{ - return (v <= UCHAR_MAX); -} - -static inline int iss16(int64_t v) -{ - return (SHRT_MIN <= v && v <= SHRT_MAX); -} - -static inline int isu16(u64 v) -{ - return (v <= USHRT_MAX); -} - -static inline int iss32(int64_t v) -{ - return (INT_MIN <= v && v <= INT_MAX); -} - -static inline int isu32(u64 v) -{ - return (v <= UINT_MAX); -} - -static void emit_opsingle(const char* mnemonic, arg_t arg1, arg_t arg2, void* data) -{ - u8 op = (u8)((uint64_t) data); - - if(arg1.type != T_NONE || arg2.type != T_NONE) - CRAP_INVALID_ARGS; - - emit1(op); -} - -static void emit_opsingle16(const char* mnemonic, arg_t arg1, arg_t arg2, void* data) -{ - emit1(0x66); - emit_opsingle(mnemonic, arg1, arg2, data); -} - -static void compute_rexmodrmsib(u8* rex_r, u8* modrm_r, u8* sib_r, arg_t* arg1, arg_t* arg2) -{ - u8 rex = 0; - u8 modrm = 0; - u8 sib = 0; - - if((arg1->type == T_REGISTER && arg2->type == T_REGISTER) - && ((arg1->v.reg & R_MSZ) != (arg2->v.reg & R_MSZ)) - && !((arg1->v.reg & R_XMM) || (arg2->v.reg & R_XMM))) - crap("both registers must be of same width"); - - if((arg1->type == T_REGISTER && arg1->v.reg & R_64) - || (arg2->type == T_REGISTER && arg2->v.reg & R_64)) - { - rex |= REX_W; - } - - if(arg1->type == T_REGISTER) - { - if((arg1->v.reg & R_MGP) > 0x07) - rex |= REX_R; - - modrm |= (arg1->v.reg & 0x07) << 3; - } - - if(arg2->type == T_REGISTER) - { - if((arg2->v.reg & R_MGP) > 0x07) - rex |= REX_B; - - modrm |= (arg2->v.reg & 0x07); - } - - if(arg2->type == T_MEMORY) - { - if((arg2->v.mem.basetype == T_REGISTER && !(arg2->v.mem.base.reg & R_64)) - || (arg2->v.mem.indextype == T_REGISTER && !(arg2->v.mem.index.reg & R_64))) - { - crap("only 64bit base/index registers are %x %x", arg2->v.mem.base.reg, arg2->v.mem.index.reg); - } - - if(arg2->v.mem.indextype == T_REGISTER) - { - modrm |= MODRM_RM_SIB; - if(!arg2->v.mem.disp) - { - modrm |= MODRM_MOD_00; - } - else if(iss8(arg2->v.mem.disp)) - { - modrm |= MODRM_MOD_01; - } - else if(isu32(arg2->v.mem.disp)) - { - modrm |= MODRM_MOD_10; - } - else - { - crap("invalid displacement"); - } - - if((arg2->v.mem.index.reg & R_MGP) > 0x07) - rex |= REX_X; - - if((arg2->v.mem.base.reg & R_MGP) > 0x07) - rex |= REX_B; - - if(arg2->v.mem.basetype != T_REGISTER) - crap("base must be register"); - switch(arg2->v.mem.scale) - { - case 1: break; - case 2: sib |= 1 << 6; break; - case 4: sib |= 2 << 6; break; - case 8: sib |= 3 << 6; break; - } - sib |= (arg2->v.mem.index.reg & 0x07) << 3; - sib |= (arg2->v.mem.base.reg & 0x07); - } - else if(arg2->v.mem.indextype == T_NONE) - { - if(!arg2->v.mem.disp) - { - modrm |= MODRM_MOD_00; - } - else if(iss8(arg2->v.mem.disp)) - { - modrm |= MODRM_MOD_01; - } - else if(isu32(arg2->v.mem.disp)) - { - modrm |= MODRM_MOD_10; - } - else - { - crap("invalid displacement"); - } - - if(arg2->v.mem.basetype != T_REGISTER) - crap("todo: base != register"); - - if((arg2->v.mem.base.reg & R_MGP) > 0x07) - rex |= REX_B; - - modrm |= arg2->v.mem.base.reg & 0x07; - } - else - { - crap("invalid indextype"); - } - } - else - { - modrm |= MODRM_MOD_11; - } - - if(rex) - rex |= 0x40; // XXX - - *rex_r = rex; - *modrm_r = modrm; - *sib_r = sib; -} - -static void maybe_emit_displacement(arg_t* arg) -{ - if(arg->type != T_MEMORY) - return; - - if(arg->v.mem.disp) - { - if(iss8(arg->v.mem.disp)) - { - emit1((u8)arg->v.mem.disp); - } - else if(isu32(arg->v.mem.disp)) - { - emit4(arg->v.mem.disp); - } - else - { - crap("invalid displacement"); - } - } -} - -/* one byte operator with register added to operator */ -static void emit_opreg(const char* mnemonic, arg_t arg1, arg_t arg2, void* data) -{ - u8 op = (u8)((uint64_t) data); - - if(arg1.type != T_REGISTER || arg2.type != T_NONE) - CRAP_INVALID_ARGS; - - if((arg1.v.reg & R_MGP) > 0x07) - emit1(0x40 | REX_B); - - op |= (arg1.v.reg & 0x07); - - emit1(op); -} - -/* operator which operates on reg/mem */ -static void emit_op_rm(const char* mnemonic, arg_t arg1, arg_t arg2, void* data) -{ - u8 rex, modrm, sib; - opparam_t* params = data; - - if((arg1.type != T_REGISTER && arg1.type != T_MEMORY) || arg2.type != T_NONE) - CRAP_INVALID_ARGS; - - compute_rexmodrmsib(&rex, &modrm, &sib, &arg2, &arg1); - - modrm |= params->subcode << 3; - - if(arg1.v.reg & R_16) - emit1(0x66); - - if(rex) emit1(rex); - if(arg1.v.reg & R_8) - emit1(params->rcode8); // op reg8/mem8, - else - emit1(params->rcode); // op reg/mem, - emit1(modrm); - if((modrm & 0x07) == MODRM_RM_SIB) - emit1(sib); - - maybe_emit_displacement(&arg1); -} - -/* operator which operates on reg/mem with cl */ -static void emit_op_rm_cl(const char* mnemonic, arg_t arg1, arg_t arg2, void* data) -{ - u8 rex, modrm, sib; - opparam_t* params = data; - - if(arg2.type != T_REGISTER || arg1.type != T_REGISTER) - CRAP_INVALID_ARGS; - - if((arg1.v.reg & R_MGP) != R_ECX && !(arg1.v.reg & R_8)) - crap("only cl register is valid"); - - arg1.type = T_NONE; // don't complain, we know it's cl anyways - - compute_rexmodrmsib(&rex, &modrm, &sib, &arg1, &arg2); - - modrm |= params->subcode << 3; - - if(arg2.v.reg & R_16) - emit1(0x66); - - if(rex) emit1(rex); - if(arg2.v.reg & R_8) - emit1(params->rcode8); // op reg8/mem8, - else - emit1(params->rcode); // op reg/mem, - emit1(modrm); - if((modrm & 0x07) == MODRM_RM_SIB) - emit1(sib); - - maybe_emit_displacement(&arg2); -} - -static void emit_mov(const char* mnemonic, arg_t arg1, arg_t arg2, void* data) -{ - u8 rex = 0; - u8 modrm = 0; - u8 sib = 0; - - if(arg1.type == T_IMMEDIATE && arg2.type == T_REGISTER) - { - u8 op = 0xb8; - - if(arg2.v.reg & R_8) - { - if(!iss8(arg1.v.imm)) - crap("value too large for 8bit register"); - - op = 0xb0; - } - else if(arg2.v.reg & R_16) - { - if(!isu16(arg1.v.imm)) - crap("value too large for 16bit register"); - emit1(0x66); - } - else if(!(arg2.v.reg & R_64)) - { - if(!isu32(arg1.v.imm)) - crap("value too large for 32bit register"); - } - - compute_rexmodrmsib(&rex, &modrm, &sib, &arg1, &arg2); - - if(rex) emit1(rex); - - op |= (arg2.v.reg & 0x07); - - emit1(op); - - if(arg2.v.reg & R_8) emit1(arg1.v.imm); - else if(arg2.v.reg & R_16) emit2(arg1.v.imm); - else if(arg2.v.reg & R_64) emit8(arg1.v.imm); - else emit4(arg1.v.imm); - } - else if(arg1.type == T_IMMEDIATE && arg2.type == T_MEMORY) - { - if(!iss32(arg1.v.imm)) - { - crap("only 32bit immediates supported"); - } - - compute_rexmodrmsib(&rex, &modrm, &sib, &arg1, &arg2); - if(rex) emit1(rex); - emit1(0xc7); // mov reg/mem, imm - emit1(modrm); - if((modrm & 0x07) == MODRM_RM_SIB) - emit1(sib); - - emit4(arg1.v.imm); - } - else if(arg1.type == T_REGISTER && arg2.type == T_REGISTER) // XXX: same as next - { - if(arg1.type != T_REGISTER || arg2.type != T_REGISTER) - crap("both args must be registers"); - - if((arg1.v.reg & R_MSZ) != (arg2.v.reg & R_MSZ)) - crap("both registers must be same width"); - - compute_rexmodrmsib(&rex, &modrm, &sib, &arg1, &arg2); - - if(rex) emit1(rex); - emit1(0x89); // mov reg reg/mem, - emit1(modrm); - } - else if(arg1.type == T_REGISTER && arg2.type == T_MEMORY) - { - compute_rexmodrmsib(&rex, &modrm, &sib, &arg1, &arg2); - - if(arg1.v.reg & R_16) - emit1(0x66); - - if(rex) emit1(rex); - if(arg1.v.reg & R_8) - emit1(0x88); // mov reg reg/mem, - else - emit1(0x89); // mov reg reg/mem, - emit1(modrm); - if((modrm & 0x07) == MODRM_RM_SIB) - emit1(sib); - - maybe_emit_displacement(&arg2); - } - else if(arg1.type == T_MEMORY && arg2.type == T_REGISTER) - { - compute_rexmodrmsib(&rex, &modrm, &sib, &arg2, &arg1); - - if(arg2.v.reg & R_16) - emit1(0x66); - - if(rex) emit1(rex); - if(arg2.v.reg & R_8) - emit1(0x8a); // mov reg/mem, reg - else - emit1(0x8b); // mov reg/mem, reg - emit1(modrm); - if((modrm & 0x07) == MODRM_RM_SIB) - emit1(sib); - - maybe_emit_displacement(&arg1); - } - else - CRAP_INVALID_ARGS; -} - -static void emit_subaddand(const char* mnemonic, arg_t arg1, arg_t arg2, void* data) -{ - u8 rex = 0; - u8 modrm = 0; - u8 sib = 0; - - opparam_t* params = data; - - if(arg1.type == T_IMMEDIATE && arg2.type == T_REGISTER) - { - if(!iss32(arg1.v.imm)) - { - crap("only 8 and 32 bit immediates supported"); - } - - compute_rexmodrmsib(&rex, &modrm, &sib, &arg1, &arg2); - modrm |= params->subcode << 3; - - if(rex) emit1(rex); - - if(arg2.v.reg & R_8) - { - emit1(0x80); // sub reg8/mem8, imm8 - emit1(modrm); - emit1(arg1.v.imm & 0xFF); - } - else if(iss8(arg1.v.imm)) - { - emit1(0x83); // sub reg/mem, imm8 - emit1(modrm); - emit1(arg1.v.imm & 0xFF); - } - else - { - emit1(0x81); // sub reg/mem, imm32 - emit1(modrm); - emit4(arg1.v.imm); - } - } - else if(arg1.type == T_REGISTER && (arg2.type == T_MEMORY || arg2.type == T_REGISTER)) - { - compute_rexmodrmsib(&rex, &modrm, &sib, &arg1, &arg2); - - if(rex) emit1(rex); - emit1(params->rmcode); // sub reg/mem, reg - emit1(modrm); - if(arg2.type == T_MEMORY && (modrm & 0x07) == MODRM_RM_SIB) - emit1(sib); - - maybe_emit_displacement(&arg2); - } - else if(arg1.type == T_MEMORY && arg2.type == T_REGISTER && params->mrcode) - { - compute_rexmodrmsib(&rex, &modrm, &sib, &arg2, &arg1); - - if(rex) emit1(rex); - emit1(params->mrcode); // sub reg, reg/mem - emit1(modrm); - if((modrm & 0x07) == MODRM_RM_SIB) - emit1(sib); - - maybe_emit_displacement(&arg1); - } - else - CRAP_INVALID_ARGS; -} - -static void emit_condjump(const char* mnemonic, arg_t arg1, arg_t arg2, void* data) -{ - unsigned off; - int disp; - unsigned char opcode = (unsigned char)(((uint64_t)data)&0xFF); - - if(arg1.type != T_LABEL || arg2.type != T_NONE) - crap("%s: argument must be label", mnemonic); - - emit1(opcode); - - off = lookup_label(arg1.v.label); - disp = off-(compiledOfs+1); - if(assembler_pass && abs(disp) > 127) - crap("cannot jump that far (%x -> %x = %x)", compiledOfs, off, disp); - - emit1(disp); -} - -static void emit_jmp(const char* mnemonic, arg_t arg1, arg_t arg2, void* data) -{ - if((arg1.type != T_LABEL && arg1.type != T_REGISTER && arg1.type != T_MEMORY) || arg2.type != T_NONE) - CRAP_INVALID_ARGS; - - if(arg1.type == T_LABEL) - { - unsigned off; - int disp; - - off = lookup_label(arg1.v.label); - disp = off-(compiledOfs+5); - emit1(0xe9); - emit4(disp); - } - else - { - u8 rex, modrm, sib; - - if(arg1.type == T_REGISTER) - { - if(!arg1.absolute) - crap("jmp must be absolute"); - - if((arg1.v.reg & R_64) != R_64) - crap("register must be 64bit"); - - arg1.v.reg ^= R_64; // no rex required for call - } - - compute_rexmodrmsib(&rex, &modrm, &sib, &arg2, &arg1); - - modrm |= 0x4 << 3; - - if(rex) emit1(rex); - emit1(0xff); - emit1(modrm); - if((modrm & 0x07) == MODRM_RM_SIB) - emit1(sib); - maybe_emit_displacement(&arg1); - } -} - -static void emit_call(const char* mnemonic, arg_t arg1, arg_t arg2, void* data) -{ - u8 rex, modrm, sib; - - if((arg1.type != T_REGISTER && arg1.type != T_IMMEDIATE) || arg2.type != T_NONE) - CRAP_INVALID_ARGS; - - if(arg1.type == T_REGISTER) - { - if(!arg1.absolute) - crap("call must be absolute"); - - if((arg1.v.reg & R_64) != R_64) - crap("register must be 64bit"); - - arg1.v.reg ^= R_64; // no rex required for call - - compute_rexmodrmsib(&rex, &modrm, &sib, &arg2, &arg1); - - modrm |= 0x2 << 3; - - if(rex) emit1(rex); - emit1(0xff); - emit1(modrm); - } - else - { - if(!isu32(arg1.v.imm)) - crap("must be 32bit argument"); - emit1(0xe8); - emit4(arg1.v.imm); - } -} - - -static void emit_twobyte(const char* mnemonic, arg_t arg1, arg_t arg2, void* data) -{ - u8 rex, modrm, sib; - - opparam_t* params = data; - - if(arg1.type == T_REGISTER && (arg2.type == T_MEMORY || arg2.type == T_REGISTER)) - { - compute_rexmodrmsib(&rex, &modrm, &sib, &arg1, &arg2); - - if(params->xmmprefix) emit1(params->xmmprefix); - if(rex) emit1(rex); - emit1(0x0f); - emit1(params->rmcode); // sub reg/mem, reg - emit1(modrm); - if((modrm & 0x07) == MODRM_RM_SIB) - emit1(sib); - - maybe_emit_displacement(&arg2); - } - else if(arg1.type == T_MEMORY && arg2.type == T_REGISTER && params->mrcode) - { - compute_rexmodrmsib(&rex, &modrm, &sib, &arg2, &arg1); - - if(params->xmmprefix) emit1(params->xmmprefix); - if(rex) emit1(rex); - emit1(0x0f); - emit1(params->mrcode); // sub reg, reg/mem - emit1(modrm); - if((modrm & 0x07) == MODRM_RM_SIB) - emit1(sib); - - maybe_emit_displacement(&arg1); - } - else - CRAP_INVALID_ARGS; -} - -static int ops_sorted = 0; -static op_t ops[] = { - { "addb", emit_subaddand, ¶ms_add }, - { "addl", emit_subaddand, ¶ms_add }, - { "addq", emit_subaddand, ¶ms_add }, - { "addss", emit_twobyte, ¶ms_addss }, - { "andb", emit_subaddand, ¶ms_and }, - { "andl", emit_subaddand, ¶ms_and }, - { "andq", emit_subaddand, ¶ms_and }, - { "callq", emit_call, NULL }, - { "cbw", emit_opsingle16, (void*)0x98 }, - { "cdq", emit_opsingle, (void*)0x99 }, - { "cmpb", emit_subaddand, ¶ms_cmp }, - { "cmpl", emit_subaddand, ¶ms_cmp }, - { "cmpq", emit_subaddand, ¶ms_cmp }, - { "cvtsi2ss", emit_twobyte, ¶ms_cvtsi2ss }, - { "cvttss2si", emit_twobyte, ¶ms_cvttss2si }, - { "cwde", emit_opsingle, (void*)0x98 }, - { "decl", emit_op_rm, ¶ms_dec }, - { "decq", emit_op_rm, ¶ms_dec }, - { "divl", emit_op_rm, ¶ms_div }, - { "divq", emit_op_rm, ¶ms_div }, - { "divss", emit_twobyte, ¶ms_divss }, - { "idivl", emit_op_rm, ¶ms_idiv }, - { "imull", emit_op_rm, ¶ms_imul }, - { "int3", emit_opsingle, (void*)0xcc }, - { "ja", emit_condjump, (void*)0x77 }, - { "jbe", emit_condjump, (void*)0x76 }, - { "jb", emit_condjump, (void*)0x72 }, - { "je", emit_condjump, (void*)0x74 }, - { "jl", emit_condjump, (void*)0x7c }, - { "jmp", emit_jmp, NULL }, - { "jmpq", emit_jmp, NULL }, - { "jnae", emit_condjump, (void*)0x72 }, - { "jna", emit_condjump, (void*)0x76 }, - { "jnbe", emit_condjump, (void*)0x77 }, - { "jnb", emit_condjump, (void*)0x73 }, - { "jnc", emit_condjump, (void*)0x73 }, - { "jne", emit_condjump, (void*)0x75 }, - { "jnge", emit_condjump, (void*)0x7c }, - { "jng", emit_condjump, (void*)0x7e }, - { "jnle", emit_condjump, (void*)0x7f }, - { "jnl", emit_condjump, (void*)0x7d }, - { "jnz", emit_condjump, (void*)0x75 }, - { "jp", emit_condjump, (void*)0x7a }, - { "jz", emit_condjump, (void*)0x74 }, - { "movb", emit_mov, NULL }, - { "movl", emit_mov, NULL }, - { "movq", emit_mov, NULL }, - { "movss", emit_twobyte, ¶ms_movss }, - { "movw", emit_mov, NULL }, - { "mull", emit_op_rm, ¶ms_mul }, - { "mulss", emit_twobyte, ¶ms_mulss }, - { "negl", emit_op_rm, ¶ms_neg }, - { "negq", emit_op_rm, ¶ms_neg }, - { "nop", emit_opsingle, (void*)0x90 }, - { "notl", emit_op_rm, ¶ms_not }, - { "notq", emit_op_rm, ¶ms_not }, - { "orb", emit_subaddand, ¶ms_or }, - { "orl", emit_subaddand, ¶ms_or }, - { "orq", emit_subaddand, ¶ms_or }, - { "pop", emit_opreg, (void*)0x58 }, - { "push", emit_opreg, (void*)0x50 }, - { "ret", emit_opsingle, (void*)0xc3 }, - { "sarl", emit_op_rm_cl, ¶ms_sar }, - { "shl", emit_op_rm_cl, ¶ms_shl }, - { "shrl", emit_op_rm_cl, ¶ms_shr }, - { "subb", emit_subaddand, ¶ms_sub }, - { "subl", emit_subaddand, ¶ms_sub }, - { "subq", emit_subaddand, ¶ms_sub }, - { "subss", emit_twobyte, ¶ms_subss }, - { "ucomiss", emit_twobyte, ¶ms_ucomiss }, - { "xorb", emit_subaddand, ¶ms_xor }, - { "xorl", emit_subaddand, ¶ms_xor }, - { "xorq", emit_subaddand, ¶ms_xor }, - { NULL, NULL, NULL } -}; - -static int opsort(const void* A, const void* B) -{ - const op_t* a = A; - const op_t* b = B; - return strcmp(a->mnemonic, b->mnemonic); -} - -static op_t* getop(const char* n) -{ -#if 0 - op_t* o = ops; - while(o->mnemonic) - { - if(!strcmp(o->mnemonic, n)) - return o; - ++o; - } - -#else - unsigned int m, t, b; - int r; - t = ARRAY_LEN(ops)-1; - - r = m = -1; - - do - { - if(r < 0) - b = m + 1; - else - t = m - 1; - - m = ((t - b) >> 1) + b; - - if((r = strcmp(ops[m].mnemonic, n)) == 0) - return &ops[m]; - } while(b <= t && t); -#endif - - return NULL; -} - -static reg_t parsereg(const char* str) -{ - const char* s = str; - if(*s == 'a' && s[1] == 'l' && !s[2]) - { - return R_AL; - } - else if(*s == 'a' && s[1] == 'x' && !s[2]) - { - return R_AX; - } - if(*s == 'b' && s[1] == 'l' && !s[2]) - { - return R_BL; - } - if(*s == 'c' && s[1] == 'l' && !s[2]) - { - return R_CL; - } - if(*s == 'x') - { - if(!strcmp(s, "xmm0")) - return R_XMM0; - } - else if(*s == 'r' && s[1]) - { - ++s; - if(s[1] == 'x') - { - switch(*s++) - { - case 'a': return R_RAX; - case 'b': return R_RBX; - case 'c': return R_RCX; - case 'd': return R_RDX; - } - } - else if(s[1] == 'i') - { - switch(*s++) - { - case 's': return R_RSI; - case 'd': return R_RDI; - } - } - else if(s[0] == 's' && s[1] == 'p' && !s[2]) - { - return R_RSP; - } - else if(*s == '8' && !s[1]) - return R_R8; - else if(*s == '9' && !s[1]) - return R_R9; - else if(*s == '1' && s[1] == '0') - return R_R10; - else if(*s == '1' && s[1] == '5') - return R_R15; - } - else if(*s == 'e' && s[1]) - { - ++s; - if(s[1] == 'x') - { - switch(*s++) - { - case 'a': return R_EAX; - case 'b': return R_EBX; - case 'c': return R_ECX; - case 'd': return R_EDX; - } - } - else if(s[1] == 'i') - { - switch(*s++) - { - case 's': return R_ESI; - case 'd': return R_EDI; - } - } - } - - crap("invalid register %s", str); - - return 0; -} - -typedef enum { - TOK_LABEL = 0x80, - TOK_INT = 0x81, - TOK_END = 0x82, - TOK_INVALID = 0x83, -} token_t; - -static unsigned char nexttok(const char** str, char* label, u64* val) -{ - const char* s = *str; - - if(label) *label = 0; - if(val) *val = 0; - - while(*s && *s == ' ') ++s; - - if(!*s) - { - return TOK_END; - } - else if(*s == '$' || *s == '*' || *s == '%' || *s == '-' || *s == ')' || *s == '(' || *s == ',') - { - *str = s+1; - return *s; - } - else if(*s >= 'a' && *s <= 'z') - { - size_t a = strspn(s+1, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"); - if(a+1 >= LABELLEN) - crap("label %s too long", s); - if(label) - { - strncpy(label, s, a+1); - label[a+1] = 0; - } - *str = s+a+1; - return TOK_LABEL; - } - else if(*s >= '0' && *s <= '9') - { - char* endptr = NULL; - u64 v = strtoull(s, &endptr, 0); - if(endptr && (endptr-s == 0)) - crap("invalid integer %s", s); - if(val) *val = v; - *str = endptr; - return TOK_INT; - } - crap("can't parse '%s'", *str); - return TOK_INVALID; -} - -static arg_t parsearg(const char** str) -{ - arg_t arg; - const char* s = *str; - char label[20]; - u64 val; - int negative = 1; - unsigned ttype; - - arg.type = T_NONE; - arg.absolute = 0; - - while(*s && *s == ' ') ++s; - - switch(nexttok(&s, label, &val)) - { - case '$' : - ttype = nexttok(&s, NULL, &val); - if(ttype == '-') - { - negative = -1; - ttype = nexttok(&s, NULL, &val); - } - if(ttype != TOK_INT) - crap("expected integer"); - arg.type = T_IMMEDIATE; - arg.v.imm = negative * val; - break; - case '*' : - if((ttype = nexttok(&s, NULL, NULL)) != '%') - { - if(ttype == '(') - goto tok_memory; - crap("expected '%%'"); - } - arg.absolute = 1; - /* fall through */ - case '%' : - if(nexttok(&s, label, &val) != TOK_LABEL) - crap("expected label"); - arg.type = T_REGISTER; - arg.v.reg = parsereg(label); - break; - case TOK_LABEL: - arg.type = T_LABEL; - strncpy(arg.v.label, label, LABELLEN); - break; - case '-': - negative = -1; - if(nexttok(&s, NULL, &val) != TOK_INT) - crap("expected integer"); - /* fall through */ - case TOK_INT: - if(nexttok(&s, label, NULL) != '(') - crap("expected '('"); // mov to/from fixed address not supported - /* fall through */ - case '(': -tok_memory: - arg.type = T_MEMORY; - arg.v.mem.indextype = T_NONE; - arg.v.mem.disp = negative * val; - ttype = nexttok(&s, label, &val); - if(ttype == '%' && nexttok(&s, label, &val) != TOK_LABEL) - { - crap("expected register"); - } - if (ttype == '%') - { - arg.v.mem.basetype = T_REGISTER; - arg.v.mem.base.reg = parsereg(label); - } - else if (ttype == TOK_INT) - { - arg.v.mem.basetype = T_IMMEDIATE; - arg.v.mem.base.imm = val; - } - if((ttype = nexttok(&s, NULL, NULL)) == ',') - { - ttype = nexttok(&s, label, &val); - if(ttype == '%' && nexttok(&s, label, &val) != TOK_LABEL) - { - crap("expected register"); - } - if (ttype == '%') - { - arg.v.mem.indextype = T_REGISTER; - arg.v.mem.index.reg = parsereg(label); - } - else if (ttype == TOK_INT) - { - crap("index must be register"); - arg.v.mem.indextype = T_IMMEDIATE; - arg.v.mem.index.imm = val; - } - if(nexttok(&s, NULL, NULL) != ',') - crap("expected ','"); - if(nexttok(&s, NULL, &val) != TOK_INT) - crap("expected integer"); - if(val != 1 && val != 2 && val != 4 && val != 8) - crap("scale must 1, 2, 4 or 8"); - arg.v.mem.scale = val; - - ttype = nexttok(&s, NULL, NULL); - } - if(ttype != ')') - { - crap("expected ')' or ','"); - } - break; - default: - crap("invalid token %hu in %s", *(unsigned char*)s, *str); - break; - } - - *str = s; - - return arg; -} - -/* ************************* */ - -void assembler_init(int pass) -{ - compiledOfs = 0; - assembler_pass = pass; - if(!pass) - { - labelhash_free(); - cur_line = NULL; - } - if(!ops_sorted) - { - ops_sorted = 1; - qsort(ops, ARRAY_LEN(ops)-1, sizeof(ops[0]), opsort); - } -} - -size_t assembler_get_code_size(void) -{ - return compiledOfs; -} - -void assembler_set_output(char* buf) -{ - out = buf; -} - -void assemble_line(const char* input, size_t len) -{ - char line[4096]; - char* s; - op_t* o; - char* opn; - arg_t arg1, arg2; - - arg1.type = T_NONE; - arg2.type = T_NONE; - opn = NULL; - o = NULL; - - if(len < 1) - return; - - if(len >= sizeof(line)) - crap("line too long"); - - memcpy(line, input, sizeof(line)); - cur_line = input; - - if(line[len-1] == '\n') line[--len] = 0; - if(line[len-1] == ':') - { - line[--len] = 0; - if(assembler_pass) - debug("%s: 0x%x\n", line, compiledOfs); - else - hash_add_label(line, compiledOfs); - } - else - { - opn = line; - s = strchr(line, ' '); - if(s) - { - *s++ = 0; - arg1 = parsearg((const char**)&s); - if(*s) - { - if(*s != ',') - crap("expected ',', got '%c'", *s); - ++s; - arg2 = parsearg((const char**)&s); - } - } - - if(!opn) - { - crap("no operator in %s", line); - } - - o = getop(opn); - if(!o) - { - crap("cannot handle op %s", opn); - } - o->func(opn, arg1, arg2, o->data); - if(assembler_pass) - debug(" - %s%s", cur_line, cur_line[strlen(cur_line)-1]=='\n'?"":"\n"); - } -} - -#ifdef SA_STANDALONE -int main(int argc, char* argv[]) -{ - char line[4096]; - size_t len; - int pass; - FILE* file = NULL; - - if(argc < 2) - { - crap("specify file"); - } - - file = fopen(argv[1], "r"); - if(!file) - { - crap("can't open file"); - } - - if(argc > 2) - { - fout = fopen(argv[2], "w"); - if(!fout) - { - crap("can't open %s for writing", argv[2]); - } - } - - for(pass = 0; pass < 2; ++pass) - { - if(fseek(file, 0, SEEK_SET)) - crap("can't rewind file"); - - if(pass) - { - char* b = malloc(assembler_get_code_size()); - if(!b) - crap("cannot allocate memory"); - assembler_set_output(b); - } - - assembler_init(pass); - - while(fgets(line, sizeof(line), file)) - { - len = strlen(line); - if(!len) continue; - - assemble_line(line, len); - } - } - - assembler_init(0); - - fclose(file); - - return 0; -} -#endif diff --git a/code/rend2/tr_image_bmp.c b/code/rend2/tr_image_bmp.c deleted file mode 100644 index 707bee3b..00000000 --- a/code/rend2/tr_image_bmp.c +++ /dev/null @@ -1,243 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -#include "../qcommon/q_shared.h" -#include "../qcommon/qfiles.h" -#include "../qcommon/qcommon.h" -#include "../renderer/tr_public.h" -extern refimport_t ri; - -typedef struct -{ - char id[2]; - unsigned fileSize; - unsigned reserved0; - unsigned bitmapDataOffset; - unsigned bitmapHeaderSize; - unsigned width; - unsigned height; - unsigned short planes; - unsigned short bitsPerPixel; - unsigned compression; - unsigned bitmapDataSize; - unsigned hRes; - unsigned vRes; - unsigned colors; - unsigned importantColors; - unsigned char palette[256][4]; -} BMPHeader_t; - -void R_LoadBMP( const char *name, byte **pic, int *width, int *height ) -{ - int columns, rows; - unsigned numPixels; - byte *pixbuf; - int row, column; - byte *buf_p; - byte *end; - union { - byte *b; - void *v; - } buffer; - int length; - BMPHeader_t bmpHeader; - byte *bmpRGBA; - - *pic = NULL; - - if(width) - *width = 0; - - if(height) - *height = 0; - - // - // load the file - // - length = ri.FS_ReadFile( ( char * ) name, &buffer.v); - if (!buffer.b || length < 0) { - return; - } - - if (length < 54) - { - ri.Error( ERR_DROP, "LoadBMP: header too short (%s)", name ); - } - - buf_p = buffer.b; - end = buffer.b + length; - - bmpHeader.id[0] = *buf_p++; - bmpHeader.id[1] = *buf_p++; - bmpHeader.fileSize = LittleLong( * ( int * ) buf_p ); - buf_p += 4; - bmpHeader.reserved0 = LittleLong( * ( int * ) buf_p ); - buf_p += 4; - bmpHeader.bitmapDataOffset = LittleLong( * ( int * ) buf_p ); - buf_p += 4; - bmpHeader.bitmapHeaderSize = LittleLong( * ( int * ) buf_p ); - buf_p += 4; - bmpHeader.width = LittleLong( * ( int * ) buf_p ); - buf_p += 4; - bmpHeader.height = LittleLong( * ( int * ) buf_p ); - buf_p += 4; - bmpHeader.planes = LittleShort( * ( short * ) buf_p ); - buf_p += 2; - bmpHeader.bitsPerPixel = LittleShort( * ( short * ) buf_p ); - buf_p += 2; - bmpHeader.compression = LittleLong( * ( int * ) buf_p ); - buf_p += 4; - bmpHeader.bitmapDataSize = LittleLong( * ( int * ) buf_p ); - buf_p += 4; - bmpHeader.hRes = LittleLong( * ( int * ) buf_p ); - buf_p += 4; - bmpHeader.vRes = LittleLong( * ( int * ) buf_p ); - buf_p += 4; - bmpHeader.colors = LittleLong( * ( int * ) buf_p ); - buf_p += 4; - bmpHeader.importantColors = LittleLong( * ( int * ) buf_p ); - buf_p += 4; - - if ( bmpHeader.bitsPerPixel == 8 ) - { - if (buf_p + sizeof(bmpHeader.palette) > end) - ri.Error( ERR_DROP, "LoadBMP: header too short (%s)", name ); - - Com_Memcpy( bmpHeader.palette, buf_p, sizeof( bmpHeader.palette ) ); - buf_p += sizeof(bmpHeader.palette); - } - - if (buffer.b + bmpHeader.bitmapDataOffset > end) - { - ri.Error( ERR_DROP, "LoadBMP: invalid offset value in header (%s)", name ); - } - - buf_p = buffer.b + bmpHeader.bitmapDataOffset; - - if ( bmpHeader.id[0] != 'B' && bmpHeader.id[1] != 'M' ) - { - ri.Error( ERR_DROP, "LoadBMP: only Windows-style BMP files supported (%s)", name ); - } - if ( bmpHeader.fileSize != length ) - { - ri.Error( ERR_DROP, "LoadBMP: header size does not match file size (%u vs. %u) (%s)", bmpHeader.fileSize, length, name ); - } - if ( bmpHeader.compression != 0 ) - { - ri.Error( ERR_DROP, "LoadBMP: only uncompressed BMP files supported (%s)", name ); - } - if ( bmpHeader.bitsPerPixel < 8 ) - { - ri.Error( ERR_DROP, "LoadBMP: monochrome and 4-bit BMP files not supported (%s)", name ); - } - - switch ( bmpHeader.bitsPerPixel ) - { - case 8: - case 16: - case 24: - case 32: - break; - default: - ri.Error( ERR_DROP, "LoadBMP: illegal pixel_size '%hu' in file '%s'", bmpHeader.bitsPerPixel, name ); - break; - } - - columns = bmpHeader.width; - rows = bmpHeader.height; - if ( rows < 0 ) - rows = -rows; - numPixels = columns * rows; - - if(columns <= 0 || !rows || numPixels > 0x1FFFFFFF // 4*1FFFFFFF == 0x7FFFFFFC < 0x7FFFFFFF - || ((numPixels * 4) / columns) / 4 != rows) - { - ri.Error (ERR_DROP, "LoadBMP: %s has an invalid image size", name); - } - if(buf_p + numPixels*bmpHeader.bitsPerPixel/8 > end) - { - ri.Error (ERR_DROP, "LoadBMP: file truncated (%s)", name); - } - - if ( width ) - *width = columns; - if ( height ) - *height = rows; - - bmpRGBA = ri.Malloc( numPixels * 4 ); - *pic = bmpRGBA; - - - for ( row = rows-1; row >= 0; row-- ) - { - pixbuf = bmpRGBA + row*columns*4; - - for ( column = 0; column < columns; column++ ) - { - unsigned char red, green, blue, alpha; - int palIndex; - unsigned short shortPixel; - - switch ( bmpHeader.bitsPerPixel ) - { - case 8: - palIndex = *buf_p++; - *pixbuf++ = bmpHeader.palette[palIndex][2]; - *pixbuf++ = bmpHeader.palette[palIndex][1]; - *pixbuf++ = bmpHeader.palette[palIndex][0]; - *pixbuf++ = 0xff; - break; - case 16: - shortPixel = * ( unsigned short * ) pixbuf; - pixbuf += 2; - *pixbuf++ = ( shortPixel & ( 31 << 10 ) ) >> 7; - *pixbuf++ = ( shortPixel & ( 31 << 5 ) ) >> 2; - *pixbuf++ = ( shortPixel & ( 31 ) ) << 3; - *pixbuf++ = 0xff; - break; - - case 24: - blue = *buf_p++; - green = *buf_p++; - red = *buf_p++; - *pixbuf++ = red; - *pixbuf++ = green; - *pixbuf++ = blue; - *pixbuf++ = 255; - break; - case 32: - blue = *buf_p++; - green = *buf_p++; - red = *buf_p++; - alpha = *buf_p++; - *pixbuf++ = red; - *pixbuf++ = green; - *pixbuf++ = blue; - *pixbuf++ = alpha; - break; - } - } - } - - ri.FS_FreeFile( buffer.v ); - -} diff --git a/code/rend2/tr_image_jpg.c b/code/rend2/tr_image_jpg.c deleted file mode 100644 index 494b4a28..00000000 --- a/code/rend2/tr_image_jpg.c +++ /dev/null @@ -1,441 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -#include "../qcommon/q_shared.h" -#include "../qcommon/qfiles.h" -#include "../qcommon/qcommon.h" -#include "../renderer/tr_public.h" -extern refimport_t ri; - -/* - * Include file for users of JPEG library. - * You will need to have included system headers that define at least - * the typedefs FILE and size_t before you can include jpeglib.h. - * (stdio.h is sufficient on ANSI-conforming systems.) - * You may also wish to include "jerror.h". - */ - -#ifdef USE_INTERNAL_JPEG -# define JPEG_INTERNALS -#endif - -#include - -#ifndef USE_INTERNAL_JPEG -# if JPEG_LIB_VERSION < 80 -# error Need system libjpeg >= 80 -# endif -#endif - -static void R_JPGErrorExit(j_common_ptr cinfo) -{ - char buffer[JMSG_LENGTH_MAX]; - - (*cinfo->err->format_message) (cinfo, buffer); - - /* Let the memory manager delete any temp files before we die */ - jpeg_destroy(cinfo); - - ri.Error(ERR_FATAL, "%s", buffer); -} - -static void R_JPGOutputMessage(j_common_ptr cinfo) -{ - char buffer[JMSG_LENGTH_MAX]; - - /* Create the message */ - (*cinfo->err->format_message) (cinfo, buffer); - - /* Send it to stderr, adding a newline */ - ri.Printf(PRINT_ALL, "%s\n", buffer); -} - -void R_LoadJPG(const char *filename, unsigned char **pic, int *width, int *height) -{ - /* This struct contains the JPEG decompression parameters and pointers to - * working space (which is allocated as needed by the JPEG library). - */ - struct jpeg_decompress_struct cinfo = {NULL}; - /* We use our private extension JPEG error handler. - * Note that this struct must live as long as the main JPEG parameter - * struct, to avoid dangling-pointer problems. - */ - /* This struct represents a JPEG error handler. It is declared separately - * because applications often want to supply a specialized error handler - * (see the second half of this file for an example). But here we just - * take the easy way out and use the standard error handler, which will - * print a message on stderr and call exit() if compression fails. - * Note that this struct must live as long as the main JPEG parameter - * struct, to avoid dangling-pointer problems. - */ - struct jpeg_error_mgr jerr; - /* More stuff */ - JSAMPARRAY buffer; /* Output row buffer */ - unsigned int row_stride; /* physical row width in output buffer */ - unsigned int pixelcount, memcount; - unsigned int sindex, dindex; - byte *out; - int len; - union { - byte *b; - void *v; - } fbuffer; - byte *buf; - - /* In this example we want to open the input file before doing anything else, - * so that the setjmp() error recovery below can assume the file is open. - * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that - * requires it in order to read binary files. - */ - - len = ri.FS_ReadFile ( ( char * ) filename, &fbuffer.v); - if (!fbuffer.b || len < 0) { - return; - } - - /* Step 1: allocate and initialize JPEG decompression object */ - - /* We have to set up the error handler first, in case the initialization - * step fails. (Unlikely, but it could happen if you are out of memory.) - * This routine fills in the contents of struct jerr, and returns jerr's - * address which we place into the link field in cinfo. - */ - cinfo.err = jpeg_std_error(&jerr); - cinfo.err->error_exit = R_JPGErrorExit; - cinfo.err->output_message = R_JPGOutputMessage; - - /* Now we can initialize the JPEG decompression object. */ - jpeg_create_decompress(&cinfo); - - /* Step 2: specify data source (eg, a file) */ - - jpeg_mem_src(&cinfo, fbuffer.b, len); - - /* Step 3: read file parameters with jpeg_read_header() */ - - (void) jpeg_read_header(&cinfo, TRUE); - /* We can ignore the return value from jpeg_read_header since - * (a) suspension is not possible with the stdio data source, and - * (b) we passed TRUE to reject a tables-only JPEG file as an error. - * See libjpeg.doc for more info. - */ - - /* Step 4: set parameters for decompression */ - - /* - * Make sure it always converts images to RGB color space. This will - * automatically convert 8-bit greyscale images to RGB as well. - */ - cinfo.out_color_space = JCS_RGB; - - /* Step 5: Start decompressor */ - - (void) jpeg_start_decompress(&cinfo); - /* We can ignore the return value since suspension is not possible - * with the stdio data source. - */ - - /* We may need to do some setup of our own at this point before reading - * the data. After jpeg_start_decompress() we have the correct scaled - * output image dimensions available, as well as the output colormap - * if we asked for color quantization. - * In this example, we need to make an output work buffer of the right size. - */ - /* JSAMPLEs per row in output buffer */ - - pixelcount = cinfo.output_width * cinfo.output_height; - - if(!cinfo.output_width || !cinfo.output_height - || ((pixelcount * 4) / cinfo.output_width) / 4 != cinfo.output_height - || pixelcount > 0x1FFFFFFF || cinfo.output_components != 3 - ) - { - // Free the memory to make sure we don't leak memory - ri.FS_FreeFile (fbuffer.v); - jpeg_destroy_decompress(&cinfo); - - ri.Error(ERR_DROP, "LoadJPG: %s has an invalid image format: %dx%d*4=%d, components: %d", filename, - cinfo.output_width, cinfo.output_height, pixelcount * 4, cinfo.output_components); - } - - memcount = pixelcount * 4; - row_stride = cinfo.output_width * cinfo.output_components; - - out = ri.Malloc(memcount); - - *width = cinfo.output_width; - *height = cinfo.output_height; - - /* Step 6: while (scan lines remain to be read) */ - /* jpeg_read_scanlines(...); */ - - /* Here we use the library's state variable cinfo.output_scanline as the - * loop counter, so that we don't have to keep track ourselves. - */ - while (cinfo.output_scanline < cinfo.output_height) { - /* jpeg_read_scanlines expects an array of pointers to scanlines. - * Here the array is only one element long, but you could ask for - * more than one scanline at a time if that's more convenient. - */ - buf = ((out+(row_stride*cinfo.output_scanline))); - buffer = &buf; - (void) jpeg_read_scanlines(&cinfo, buffer, 1); - } - - buf = out; - - // Expand from RGB to RGBA - sindex = pixelcount * cinfo.output_components; - dindex = memcount; - - do - { - buf[--dindex] = 255; - buf[--dindex] = buf[--sindex]; - buf[--dindex] = buf[--sindex]; - buf[--dindex] = buf[--sindex]; - } while(sindex); - - *pic = out; - - /* Step 7: Finish decompression */ - - jpeg_finish_decompress(&cinfo); - /* We can ignore the return value since suspension is not possible - * with the stdio data source. - */ - - /* Step 8: Release JPEG decompression object */ - - /* This is an important step since it will release a good deal of memory. */ - jpeg_destroy_decompress(&cinfo); - - /* After finish_decompress, we can close the input file. - * Here we postpone it until after no more JPEG errors are possible, - * so as to simplify the setjmp error logic above. (Actually, I don't - * think that jpeg_destroy can do an error exit, but why assume anything...) - */ - ri.FS_FreeFile (fbuffer.v); - - /* At this point you may want to check to see whether any corrupt-data - * warnings occurred (test whether jerr.pub.num_warnings is nonzero). - */ - - /* And we're done! */ -} - - -/* Expanded data destination object for stdio output */ - -typedef struct { - struct jpeg_destination_mgr pub; /* public fields */ - - byte* outfile; /* target stream */ - int size; -} my_destination_mgr; - -typedef my_destination_mgr * my_dest_ptr; - - -/* - * Initialize destination --- called by jpeg_start_compress - * before any data is actually written. - */ - -static void -init_destination (j_compress_ptr cinfo) -{ - my_dest_ptr dest = (my_dest_ptr) cinfo->dest; - - dest->pub.next_output_byte = dest->outfile; - dest->pub.free_in_buffer = dest->size; -} - - -/* - * Empty the output buffer --- called whenever buffer fills up. - * - * In typical applications, this should write the entire output buffer - * (ignoring the current state of next_output_byte & free_in_buffer), - * reset the pointer & count to the start of the buffer, and return TRUE - * indicating that the buffer has been dumped. - * - * In applications that need to be able to suspend compression due to output - * overrun, a FALSE return indicates that the buffer cannot be emptied now. - * In this situation, the compressor will return to its caller (possibly with - * an indication that it has not accepted all the supplied scanlines). The - * application should resume compression after it has made more room in the - * output buffer. Note that there are substantial restrictions on the use of - * suspension --- see the documentation. - * - * When suspending, the compressor will back up to a convenient restart point - * (typically the start of the current MCU). next_output_byte & free_in_buffer - * indicate where the restart point will be if the current call returns FALSE. - * Data beyond this point will be regenerated after resumption, so do not - * write it out when emptying the buffer externally. - */ - -static boolean -empty_output_buffer (j_compress_ptr cinfo) -{ - my_dest_ptr dest = (my_dest_ptr) cinfo->dest; - - jpeg_destroy_compress(cinfo); - - // Make crash fatal or we would probably leak memory. - ri.Error(ERR_FATAL, "Output buffer for encoded JPEG image has insufficient size of %d bytes", - dest->size); - - return FALSE; -} - -/* - * Terminate destination --- called by jpeg_finish_compress - * after all data has been written. Usually needs to flush buffer. - * - * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding - * application must deal with any cleanup that should happen even - * for error exit. - */ - -static void term_destination(j_compress_ptr cinfo) -{ -} - - -/* - * Prepare for output to a stdio stream. - * The caller must have already opened the stream, and is responsible - * for closing it after finishing compression. - */ - -static void -jpegDest (j_compress_ptr cinfo, byte* outfile, int size) -{ - my_dest_ptr dest; - - /* The destination object is made permanent so that multiple JPEG images - * can be written to the same file without re-executing jpeg_stdio_dest. - * This makes it dangerous to use this manager and a different destination - * manager serially with the same JPEG object, because their private object - * sizes may be different. Caveat programmer. - */ - if (cinfo->dest == NULL) { /* first time for this JPEG object? */ - cinfo->dest = (struct jpeg_destination_mgr *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, - sizeof(my_destination_mgr)); - } - - dest = (my_dest_ptr) cinfo->dest; - dest->pub.init_destination = init_destination; - dest->pub.empty_output_buffer = empty_output_buffer; - dest->pub.term_destination = term_destination; - dest->outfile = outfile; - dest->size = size; -} - -/* -================= -SaveJPGToBuffer - -Encodes JPEG from image in image_buffer and writes to buffer. -Expects RGB input data -================= -*/ -size_t RE_SaveJPGToBuffer(byte *buffer, size_t bufSize, int quality, - int image_width, int image_height, byte *image_buffer, int padding) -{ - struct jpeg_compress_struct cinfo; - struct jpeg_error_mgr jerr; - JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ - my_dest_ptr dest; - int row_stride; /* physical row width in image buffer */ - size_t outcount; - - /* Step 1: allocate and initialize JPEG compression object */ - cinfo.err = jpeg_std_error(&jerr); - cinfo.err->error_exit = R_JPGErrorExit; - cinfo.err->output_message = R_JPGOutputMessage; - - /* Now we can initialize the JPEG compression object. */ - jpeg_create_compress(&cinfo); - - /* Step 2: specify data destination (eg, a file) */ - /* Note: steps 2 and 3 can be done in either order. */ - jpegDest(&cinfo, buffer, bufSize); - - /* Step 3: set parameters for compression */ - cinfo.image_width = image_width; /* image width and height, in pixels */ - cinfo.image_height = image_height; - cinfo.input_components = 3; /* # of color components per pixel */ - cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ - - jpeg_set_defaults(&cinfo); - jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); - /* If quality is set high, disable chroma subsampling */ - if (quality >= 85) { - cinfo.comp_info[0].h_samp_factor = 1; - cinfo.comp_info[0].v_samp_factor = 1; - } - - /* Step 4: Start compressor */ - jpeg_start_compress(&cinfo, TRUE); - - /* Step 5: while (scan lines remain to be written) */ - /* jpeg_write_scanlines(...); */ - row_stride = image_width * cinfo.input_components + padding; /* JSAMPLEs per row in image_buffer */ - - while (cinfo.next_scanline < cinfo.image_height) { - /* jpeg_write_scanlines expects an array of pointers to scanlines. - * Here the array is only one element long, but you could pass - * more than one scanline at a time if that's more convenient. - */ - row_pointer[0] = &image_buffer[((cinfo.image_height-1)*row_stride)-cinfo.next_scanline * row_stride]; - (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); - } - - /* Step 6: Finish compression */ - jpeg_finish_compress(&cinfo); - - dest = (my_dest_ptr) cinfo.dest; - outcount = dest->size - dest->pub.free_in_buffer; - - /* Step 7: release JPEG compression object */ - jpeg_destroy_compress(&cinfo); - - /* And we're done! */ - return outcount; -} - -void RE_SaveJPG(char * filename, int quality, int image_width, int image_height, byte *image_buffer, int padding) -{ - byte *out; - size_t bufSize; - - bufSize = image_width * image_height * 3; - out = ri.Hunk_AllocateTempMemory(bufSize); - - bufSize = RE_SaveJPGToBuffer(out, bufSize, quality, image_width, image_height, image_buffer, padding); - ri.FS_WriteFile(filename, out, bufSize); - - ri.Hunk_FreeTempMemory(out); -} diff --git a/code/rend2/tr_image_pcx.c b/code/rend2/tr_image_pcx.c deleted file mode 100644 index d4dd575d..00000000 --- a/code/rend2/tr_image_pcx.c +++ /dev/null @@ -1,179 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - 2008 Ludwig Nussel - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -#include "../qcommon/q_shared.h" -#include "../qcommon/qfiles.h" -#include "../qcommon/qcommon.h" -#include "../renderer/tr_public.h" -extern refimport_t ri; - -/* -======================================================================== - -PCX files are used for 8 bit images - -======================================================================== -*/ - -typedef struct { - char manufacturer; - char version; - char encoding; - char bits_per_pixel; - unsigned short xmin,ymin,xmax,ymax; - unsigned short hres,vres; - unsigned char palette[48]; - char reserved; - char color_planes; - unsigned short bytes_per_line; - unsigned short palette_type; - unsigned short hscreensize, vscreensize; - char filler[54]; - unsigned char data[]; -} pcx_t; - -void R_LoadPCX ( const char *filename, byte **pic, int *width, int *height) -{ - union { - byte *b; - void *v; - } raw; - byte *end; - pcx_t *pcx; - int len; - unsigned char dataByte = 0, runLength = 0; - byte *out, *pix; - unsigned short w, h; - byte *pic8; - byte *palette; - int i; - unsigned size = 0; - - if (width) - *width = 0; - if (height) - *height = 0; - *pic = NULL; - - // - // load the file - // - len = ri.FS_ReadFile( ( char * ) filename, &raw.v); - if (!raw.b || len < 0) { - return; - } - - if((unsigned)len < sizeof(pcx_t)) - { - ri.Printf (PRINT_ALL, "PCX truncated: %s\n", filename); - ri.FS_FreeFile (raw.v); - return; - } - - // - // parse the PCX file - // - pcx = (pcx_t *)raw.b; - end = raw.b+len; - - w = LittleShort(pcx->xmax)+1; - h = LittleShort(pcx->ymax)+1; - size = w*h; - - if (pcx->manufacturer != 0x0a - || pcx->version != 5 - || pcx->encoding != 1 - || pcx->color_planes != 1 - || pcx->bits_per_pixel != 8 - || w >= 1024 - || h >= 1024) - { - ri.Printf (PRINT_ALL, "Bad or unsupported pcx file %s (%dx%d@%d)\n", filename, w, h, pcx->bits_per_pixel); - return; - } - - pix = pic8 = ri.Malloc ( size ); - - raw.b = pcx->data; - // FIXME: should use bytes_per_line but original q3 didn't do that either - while(pix < pic8+size) - { - if(runLength > 0) { - *pix++ = dataByte; - --runLength; - continue; - } - - if(raw.b+1 > end) - break; - dataByte = *raw.b++; - - if((dataByte & 0xC0) == 0xC0) - { - if(raw.b+1 > end) - break; - runLength = dataByte & 0x3F; - dataByte = *raw.b++; - } - else - runLength = 1; - } - - if(pix < pic8+size) - { - ri.Printf (PRINT_ALL, "PCX file truncated: %s\n", filename); - ri.FS_FreeFile (pcx); - ri.Free (pic8); - } - - if (raw.b-(byte*)pcx >= end - (byte*)769 || end[-769] != 0x0c) - { - ri.Printf (PRINT_ALL, "PCX missing palette: %s\n", filename); - ri.FS_FreeFile (pcx); - ri.Free (pic8); - return; - } - - palette = end-768; - - pix = out = ri.Malloc(4 * size ); - for (i = 0 ; i < size ; i++) - { - unsigned char p = pic8[i]; - pix[0] = palette[p*3]; - pix[1] = palette[p*3 + 1]; - pix[2] = palette[p*3 + 2]; - pix[3] = 255; - pix += 4; - } - - if (width) - *width = w; - if (height) - *height = h; - - *pic = out; - - ri.FS_FreeFile (pcx); - ri.Free (pic8); -} diff --git a/code/rend2/tr_image_png.c b/code/rend2/tr_image_png.c deleted file mode 100644 index ee37aa75..00000000 --- a/code/rend2/tr_image_png.c +++ /dev/null @@ -1,2490 +0,0 @@ -/* -=========================================================================== -ioquake3 png decoder -Copyright (C) 2007,2008 Joerg Dietrich - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -=========================================================================== -*/ - -#include "../qcommon/q_shared.h" -#include "../qcommon/qfiles.h" -#include "../qcommon/qcommon.h" -#include "../renderer/tr_public.h" -extern refimport_t ri; - -#include "../qcommon/puff.h" - -// we could limit the png size to a lower value here -#ifndef INT_MAX -#define INT_MAX 0x1fffffff -#endif - -/* -================= -PNG LOADING -================= -*/ - -/* - * Quake 3 image format : RGBA - */ - -#define Q3IMAGE_BYTESPERPIXEL (4) - -/* - * PNG specifications - */ - -/* - * The first 8 Bytes of every PNG-File are a fixed signature - * to identify the file as a PNG. - */ - -#define PNG_Signature "\x89\x50\x4E\x47\xD\xA\x1A\xA" -#define PNG_Signature_Size (8) - -/* - * After the signature diverse chunks follow. - * A chunk consists of a header and if Length - * is bigger than 0 a body and a CRC of the body follow. - */ - -struct PNG_ChunkHeader -{ - uint32_t Length; - uint32_t Type; -}; - -#define PNG_ChunkHeader_Size (8) - -typedef uint32_t PNG_ChunkCRC; - -#define PNG_ChunkCRC_Size (4) - -/* - * We use the following ChunkTypes. - * All others are ignored. - */ - -#define MAKE_CHUNKTYPE(a,b,c,d) (((a) << 24) | ((b) << 16) | ((c) << 8) | ((d))) - -#define PNG_ChunkType_IHDR MAKE_CHUNKTYPE('I', 'H', 'D', 'R') -#define PNG_ChunkType_PLTE MAKE_CHUNKTYPE('P', 'L', 'T', 'E') -#define PNG_ChunkType_IDAT MAKE_CHUNKTYPE('I', 'D', 'A', 'T') -#define PNG_ChunkType_IEND MAKE_CHUNKTYPE('I', 'E', 'N', 'D') -#define PNG_ChunkType_tRNS MAKE_CHUNKTYPE('t', 'R', 'N', 'S') - -/* - * Per specification the first chunk after the signature SHALL be IHDR. - */ - -struct PNG_Chunk_IHDR -{ - uint32_t Width; - uint32_t Height; - uint8_t BitDepth; - uint8_t ColourType; - uint8_t CompressionMethod; - uint8_t FilterMethod; - uint8_t InterlaceMethod; -}; - -#define PNG_Chunk_IHDR_Size (13) - -/* - * ColourTypes - */ - -#define PNG_ColourType_Grey (0) -#define PNG_ColourType_True (2) -#define PNG_ColourType_Indexed (3) -#define PNG_ColourType_GreyAlpha (4) -#define PNG_ColourType_TrueAlpha (6) - -/* - * number of colour components - * - * Grey : 1 grey - * True : 1 R, 1 G, 1 B - * Indexed : 1 index - * GreyAlpha : 1 grey, 1 alpha - * TrueAlpha : 1 R, 1 G, 1 B, 1 alpha - */ - -#define PNG_NumColourComponents_Grey (1) -#define PNG_NumColourComponents_True (3) -#define PNG_NumColourComponents_Indexed (1) -#define PNG_NumColourComponents_GreyAlpha (2) -#define PNG_NumColourComponents_TrueAlpha (4) - -/* - * For the different ColourTypes - * different BitDepths are specified. - */ - -#define PNG_BitDepth_1 ( 1) -#define PNG_BitDepth_2 ( 2) -#define PNG_BitDepth_4 ( 4) -#define PNG_BitDepth_8 ( 8) -#define PNG_BitDepth_16 (16) - -/* - * Only one valid CompressionMethod is standardized. - */ - -#define PNG_CompressionMethod_0 (0) - -/* - * Only one valid FilterMethod is currently standardized. - */ - -#define PNG_FilterMethod_0 (0) - -/* - * This FilterMethod defines 5 FilterTypes - */ - -#define PNG_FilterType_None (0) -#define PNG_FilterType_Sub (1) -#define PNG_FilterType_Up (2) -#define PNG_FilterType_Average (3) -#define PNG_FilterType_Paeth (4) - -/* - * Two InterlaceMethods are standardized : - * 0 - NonInterlaced - * 1 - Interlaced - */ - -#define PNG_InterlaceMethod_NonInterlaced (0) -#define PNG_InterlaceMethod_Interlaced (1) - -/* - * The Adam7 interlace method uses 7 passes. - */ - -#define PNG_Adam7_NumPasses (7) - -/* - * The compressed data starts with a header ... - */ - -struct PNG_ZlibHeader -{ - uint8_t CompressionMethod; - uint8_t Flags; -}; - -#define PNG_ZlibHeader_Size (2) - -/* - * ... and is followed by a check value - */ - -#define PNG_ZlibCheckValue_Size (4) - -/* - * Some support functions for buffered files follow. - */ - -/* - * buffered file representation - */ - -struct BufferedFile -{ - byte *Buffer; - int Length; - byte *Ptr; - int BytesLeft; -}; - -/* - * Read a file into a buffer. - */ - -static struct BufferedFile *ReadBufferedFile(const char *name) -{ - struct BufferedFile *BF; - union { - byte *b; - void *v; - } buffer; - - /* - * input verification - */ - - if(!name) - { - return(NULL); - } - - /* - * Allocate control struct. - */ - - BF = ri.Malloc(sizeof(struct BufferedFile)); - if(!BF) - { - return(NULL); - } - - /* - * Initialize the structs components. - */ - - BF->Length = 0; - BF->Buffer = NULL; - BF->Ptr = NULL; - BF->BytesLeft = 0; - - /* - * Read the file. - */ - - BF->Length = ri.FS_ReadFile((char *) name, &buffer.v); - BF->Buffer = buffer.b; - - /* - * Did we get it? Is it big enough? - */ - - if(!(BF->Buffer && (BF->Length > 0))) - { - ri.Free(BF); - - return(NULL); - } - - /* - * Set the pointers and counters. - */ - - BF->Ptr = BF->Buffer; - BF->BytesLeft = BF->Length; - - return(BF); -} - -/* - * Close a buffered file. - */ - -static void CloseBufferedFile(struct BufferedFile *BF) -{ - if(BF) - { - if(BF->Buffer) - { - ri.FS_FreeFile(BF->Buffer); - } - - ri.Free(BF); - } -} - -/* - * Get a pointer to the requested bytes. - */ - -static void *BufferedFileRead(struct BufferedFile *BF, unsigned Length) -{ - void *RetVal; - - /* - * input verification - */ - - if(!(BF && Length)) - { - return(NULL); - } - - /* - * not enough bytes left - */ - - if(Length > BF->BytesLeft) - { - return(NULL); - } - - /* - * the pointer to the requested data - */ - - RetVal = BF->Ptr; - - /* - * Raise the pointer and counter. - */ - - BF->Ptr += Length; - BF->BytesLeft -= Length; - - return(RetVal); -} - -/* - * Rewind the buffer. - */ - -static qboolean BufferedFileRewind(struct BufferedFile *BF, unsigned Offset) -{ - unsigned BytesRead; - - /* - * input verification - */ - - if(!BF) - { - return(qfalse); - } - - /* - * special trick to rewind to the beginning of the buffer - */ - - if(Offset == (unsigned)-1) - { - BF->Ptr = BF->Buffer; - BF->BytesLeft = BF->Length; - - return(qtrue); - } - - /* - * How many bytes do we have already read? - */ - - BytesRead = BF->Ptr - BF->Buffer; - - /* - * We can only rewind to the beginning of the BufferedFile. - */ - - if(Offset > BytesRead) - { - return(qfalse); - } - - /* - * lower the pointer and counter. - */ - - BF->Ptr -= Offset; - BF->BytesLeft += Offset; - - return(qtrue); -} - -/* - * Skip some bytes. - */ - -static qboolean BufferedFileSkip(struct BufferedFile *BF, unsigned Offset) -{ - /* - * input verification - */ - - if(!BF) - { - return(qfalse); - } - - /* - * We can only skip to the end of the BufferedFile. - */ - - if(Offset > BF->BytesLeft) - { - return(qfalse); - } - - /* - * lower the pointer and counter. - */ - - BF->Ptr += Offset; - BF->BytesLeft -= Offset; - - return(qtrue); -} - -/* - * Find a chunk - */ - -static qboolean FindChunk(struct BufferedFile *BF, uint32_t ChunkType) -{ - struct PNG_ChunkHeader *CH; - - uint32_t Length; - uint32_t Type; - - /* - * input verification - */ - - if(!BF) - { - return(qfalse); - } - - /* - * cycle trough the chunks - */ - - while(qtrue) - { - /* - * Read the chunk-header. - */ - - CH = BufferedFileRead(BF, PNG_ChunkHeader_Size); - if(!CH) - { - return(qfalse); - } - - /* - * Do not swap the original types - * they might be needed later. - */ - - Length = BigLong(CH->Length); - Type = BigLong(CH->Type); - - /* - * We found it! - */ - - if(Type == ChunkType) - { - /* - * Rewind to the start of the chunk. - */ - - BufferedFileRewind(BF, PNG_ChunkHeader_Size); - - break; - } - else - { - /* - * Skip the rest of the chunk. - */ - - if(Length) - { - if(!BufferedFileSkip(BF, Length + PNG_ChunkCRC_Size)) - { - return(qfalse); - } - } - } - } - - return(qtrue); -} - -/* - * Decompress all IDATs - */ - -static uint32_t DecompressIDATs(struct BufferedFile *BF, uint8_t **Buffer) -{ - uint8_t *DecompressedData; - uint32_t DecompressedDataLength; - - uint8_t *CompressedData; - uint8_t *CompressedDataPtr; - uint32_t CompressedDataLength; - - struct PNG_ChunkHeader *CH; - - uint32_t Length; - uint32_t Type; - - int BytesToRewind; - - int32_t puffResult; - uint8_t *puffDest; - uint32_t puffDestLen; - uint8_t *puffSrc; - uint32_t puffSrcLen; - - /* - * input verification - */ - - if(!(BF && Buffer)) - { - return(-1); - } - - /* - * some zeroing - */ - - DecompressedData = NULL; - DecompressedDataLength = 0; - *Buffer = DecompressedData; - - CompressedData = NULL; - CompressedDataLength = 0; - - BytesToRewind = 0; - - /* - * Find the first IDAT chunk. - */ - - if(!FindChunk(BF, PNG_ChunkType_IDAT)) - { - return(-1); - } - - /* - * Count the size of the uncompressed data - */ - - while(qtrue) - { - /* - * Read chunk header - */ - - CH = BufferedFileRead(BF, PNG_ChunkHeader_Size); - if(!CH) - { - /* - * Rewind to the start of this adventure - * and return unsuccessfull - */ - - BufferedFileRewind(BF, BytesToRewind); - - return(-1); - } - - /* - * Length and Type of chunk - */ - - Length = BigLong(CH->Length); - Type = BigLong(CH->Type); - - /* - * We have reached the end of the IDAT chunks - */ - - if(!(Type == PNG_ChunkType_IDAT)) - { - BufferedFileRewind(BF, PNG_ChunkHeader_Size); - - break; - } - - /* - * Add chunk header to count. - */ - - BytesToRewind += PNG_ChunkHeader_Size; - - /* - * Skip to next chunk - */ - - if(Length) - { - if(!BufferedFileSkip(BF, Length + PNG_ChunkCRC_Size)) - { - BufferedFileRewind(BF, BytesToRewind); - - return(-1); - } - - BytesToRewind += Length + PNG_ChunkCRC_Size; - CompressedDataLength += Length; - } - } - - BufferedFileRewind(BF, BytesToRewind); - - CompressedData = ri.Malloc(CompressedDataLength); - if(!CompressedData) - { - return(-1); - } - - CompressedDataPtr = CompressedData; - - /* - * Collect the compressed Data - */ - - while(qtrue) - { - /* - * Read chunk header - */ - - CH = BufferedFileRead(BF, PNG_ChunkHeader_Size); - if(!CH) - { - ri.Free(CompressedData); - - return(-1); - } - - /* - * Length and Type of chunk - */ - - Length = BigLong(CH->Length); - Type = BigLong(CH->Type); - - /* - * We have reached the end of the IDAT chunks - */ - - if(!(Type == PNG_ChunkType_IDAT)) - { - BufferedFileRewind(BF, PNG_ChunkHeader_Size); - - break; - } - - /* - * Copy the Data - */ - - if(Length) - { - uint8_t *OrigCompressedData; - - OrigCompressedData = BufferedFileRead(BF, Length); - if(!OrigCompressedData) - { - ri.Free(CompressedData); - - return(-1); - } - - if(!BufferedFileSkip(BF, PNG_ChunkCRC_Size)) - { - ri.Free(CompressedData); - - return(-1); - } - - memcpy(CompressedDataPtr, OrigCompressedData, Length); - CompressedDataPtr += Length; - } - } - - /* - * Let puff() calculate the decompressed data length. - */ - - puffDest = NULL; - puffDestLen = 0; - - /* - * The zlib header and checkvalue don't belong to the compressed data. - */ - - puffSrc = CompressedData + PNG_ZlibHeader_Size; - puffSrcLen = CompressedDataLength - PNG_ZlibHeader_Size - PNG_ZlibCheckValue_Size; - - /* - * first puff() to calculate the size of the uncompressed data - */ - - puffResult = puff(puffDest, &puffDestLen, puffSrc, &puffSrcLen); - if(!((puffResult == 0) && (puffDestLen > 0))) - { - ri.Free(CompressedData); - - return(-1); - } - - /* - * Allocate the buffer for the uncompressed data. - */ - - DecompressedData = ri.Malloc(puffDestLen); - if(!DecompressedData) - { - ri.Free(CompressedData); - - return(-1); - } - - /* - * Set the input again in case something was changed by the last puff() . - */ - - puffDest = DecompressedData; - puffSrc = CompressedData + PNG_ZlibHeader_Size; - puffSrcLen = CompressedDataLength - PNG_ZlibHeader_Size - PNG_ZlibCheckValue_Size; - - /* - * decompression puff() - */ - - puffResult = puff(puffDest, &puffDestLen, puffSrc, &puffSrcLen); - - /* - * The compressed data is not needed anymore. - */ - - ri.Free(CompressedData); - - /* - * Check if the last puff() was successfull. - */ - - if(!((puffResult == 0) && (puffDestLen > 0))) - { - ri.Free(DecompressedData); - - return(-1); - } - - /* - * Set the output of this function. - */ - - DecompressedDataLength = puffDestLen; - *Buffer = DecompressedData; - - return(DecompressedDataLength); -} - -/* - * the Paeth predictor - */ - -static uint8_t PredictPaeth(uint8_t a, uint8_t b, uint8_t c) -{ - /* - * a == Left - * b == Up - * c == UpLeft - */ - - uint8_t Pr; - int p; - int pa, pb, pc; - - p = ((int) a) + ((int) b) - ((int) c); - pa = abs(p - ((int) a)); - pb = abs(p - ((int) b)); - pc = abs(p - ((int) c)); - - if((pa <= pb) && (pa <= pc)) - { - Pr = a; - } - else if(pb <= pc) - { - Pr = b; - } - else - { - Pr = c; - } - - return(Pr); - -} - -/* - * Reverse the filters. - */ - -static qboolean UnfilterImage(uint8_t *DecompressedData, - uint32_t ImageHeight, - uint32_t BytesPerScanline, - uint32_t BytesPerPixel) -{ - uint8_t *DecompPtr; - uint8_t FilterType; - uint8_t *PixelLeft, *PixelUp, *PixelUpLeft; - uint32_t w, h, p; - - /* - * some zeros for the filters - */ - - uint8_t Zeros[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - - /* - * input verification - */ - - if(!(DecompressedData && BytesPerPixel)) - { - return(qfalse); - } - - /* - * ImageHeight and BytesPerScanline can be zero in small interlaced images. - */ - - if((!ImageHeight) || (!BytesPerScanline)) - { - return(qtrue); - } - - /* - * Set the pointer to the start of the decompressed Data. - */ - - DecompPtr = DecompressedData; - - /* - * Un-filtering is done in place. - */ - - /* - * Go trough all scanlines. - */ - - for(h = 0; h < ImageHeight; h++) - { - /* - * Every scanline starts with a FilterType byte. - */ - - FilterType = *DecompPtr; - DecompPtr++; - - /* - * Left pixel of the first byte in a scanline is zero. - */ - - PixelLeft = Zeros; - - /* - * Set PixelUp to previous line only if we are on the second line or above. - * - * Plus one byte for the FilterType - */ - - if(h > 0) - { - PixelUp = DecompPtr - (BytesPerScanline + 1); - } - else - { - PixelUp = Zeros; - } - - /* - * The pixel left to the first pixel of the previous scanline is zero too. - */ - - PixelUpLeft = Zeros; - - /* - * Cycle trough all pixels of the scanline. - */ - - for(w = 0; w < (BytesPerScanline / BytesPerPixel); w++) - { - /* - * Cycle trough the bytes of the pixel. - */ - - for(p = 0; p < BytesPerPixel; p++) - { - switch(FilterType) - { - case PNG_FilterType_None : - { - /* - * The byte is unfiltered. - */ - - break; - } - - case PNG_FilterType_Sub : - { - DecompPtr[p] += PixelLeft[p]; - - break; - } - - case PNG_FilterType_Up : - { - DecompPtr[p] += PixelUp[p]; - - break; - } - - case PNG_FilterType_Average : - { - DecompPtr[p] += ((uint8_t) ((((uint16_t) PixelLeft[p]) + ((uint16_t) PixelUp[p])) / 2)); - - break; - } - - case PNG_FilterType_Paeth : - { - DecompPtr[p] += PredictPaeth(PixelLeft[p], PixelUp[p], PixelUpLeft[p]); - - break; - } - - default : - { - return(qfalse); - } - } - } - - PixelLeft = DecompPtr; - - /* - * We only have an upleft pixel if we are on the second line or above. - */ - - if(h > 0) - { - PixelUpLeft = DecompPtr - (BytesPerScanline + 1); - } - - /* - * Skip to the next pixel. - */ - - DecompPtr += BytesPerPixel; - - /* - * We only have a previous line if we are on the second line and above. - */ - - if(h > 0) - { - PixelUp = DecompPtr - (BytesPerScanline + 1); - } - } - } - - return(qtrue); -} - -/* - * Convert a raw input pixel to Quake 3 RGA format. - */ - -static qboolean ConvertPixel(struct PNG_Chunk_IHDR *IHDR, - byte *OutPtr, - uint8_t *DecompPtr, - qboolean HasTransparentColour, - uint8_t *TransparentColour, - uint8_t *OutPal) -{ - /* - * input verification - */ - - if(!(IHDR && OutPtr && DecompPtr && TransparentColour && OutPal)) - { - return(qfalse); - } - - switch(IHDR->ColourType) - { - case PNG_ColourType_Grey : - { - switch(IHDR->BitDepth) - { - case PNG_BitDepth_1 : - case PNG_BitDepth_2 : - case PNG_BitDepth_4 : - { - uint8_t Step; - uint8_t GreyValue; - - Step = 0xFF / ((1 << IHDR->BitDepth) - 1); - - GreyValue = DecompPtr[0] * Step; - - OutPtr[0] = GreyValue; - OutPtr[1] = GreyValue; - OutPtr[2] = GreyValue; - OutPtr[3] = 0xFF; - - /* - * Grey supports full transparency for one specified colour - */ - - if(HasTransparentColour) - { - if(TransparentColour[1] == DecompPtr[0]) - { - OutPtr[3] = 0x00; - } - } - - - break; - } - - case PNG_BitDepth_8 : - case PNG_BitDepth_16 : - { - OutPtr[0] = DecompPtr[0]; - OutPtr[1] = DecompPtr[0]; - OutPtr[2] = DecompPtr[0]; - OutPtr[3] = 0xFF; - - /* - * Grey supports full transparency for one specified colour - */ - - if(HasTransparentColour) - { - if(IHDR->BitDepth == PNG_BitDepth_8) - { - if(TransparentColour[1] == DecompPtr[0]) - { - OutPtr[3] = 0x00; - } - } - else - { - if((TransparentColour[0] == DecompPtr[0]) && (TransparentColour[1] == DecompPtr[1])) - { - OutPtr[3] = 0x00; - } - } - } - - break; - } - - default : - { - return(qfalse); - } - } - - break; - } - - case PNG_ColourType_True : - { - switch(IHDR->BitDepth) - { - case PNG_BitDepth_8 : - { - OutPtr[0] = DecompPtr[0]; - OutPtr[1] = DecompPtr[1]; - OutPtr[2] = DecompPtr[2]; - OutPtr[3] = 0xFF; - - /* - * True supports full transparency for one specified colour - */ - - if(HasTransparentColour) - { - if((TransparentColour[1] == DecompPtr[0]) && - (TransparentColour[3] == DecompPtr[1]) && - (TransparentColour[5] == DecompPtr[2])) - { - OutPtr[3] = 0x00; - } - } - - break; - } - - case PNG_BitDepth_16 : - { - /* - * We use only the upper byte. - */ - - OutPtr[0] = DecompPtr[0]; - OutPtr[1] = DecompPtr[2]; - OutPtr[2] = DecompPtr[4]; - OutPtr[3] = 0xFF; - - /* - * True supports full transparency for one specified colour - */ - - if(HasTransparentColour) - { - if((TransparentColour[0] == DecompPtr[0]) && (TransparentColour[1] == DecompPtr[1]) && - (TransparentColour[2] == DecompPtr[2]) && (TransparentColour[3] == DecompPtr[3]) && - (TransparentColour[4] == DecompPtr[4]) && (TransparentColour[5] == DecompPtr[5])) - { - OutPtr[3] = 0x00; - } - } - - break; - } - - default : - { - return(qfalse); - } - } - - break; - } - - case PNG_ColourType_Indexed : - { - OutPtr[0] = OutPal[DecompPtr[0] * Q3IMAGE_BYTESPERPIXEL + 0]; - OutPtr[1] = OutPal[DecompPtr[0] * Q3IMAGE_BYTESPERPIXEL + 1]; - OutPtr[2] = OutPal[DecompPtr[0] * Q3IMAGE_BYTESPERPIXEL + 2]; - OutPtr[3] = OutPal[DecompPtr[0] * Q3IMAGE_BYTESPERPIXEL + 3]; - - break; - } - - case PNG_ColourType_GreyAlpha : - { - switch(IHDR->BitDepth) - { - case PNG_BitDepth_8 : - { - OutPtr[0] = DecompPtr[0]; - OutPtr[1] = DecompPtr[0]; - OutPtr[2] = DecompPtr[0]; - OutPtr[3] = DecompPtr[1]; - - break; - } - - case PNG_BitDepth_16 : - { - /* - * We use only the upper byte. - */ - - OutPtr[0] = DecompPtr[0]; - OutPtr[1] = DecompPtr[0]; - OutPtr[2] = DecompPtr[0]; - OutPtr[3] = DecompPtr[2]; - - break; - } - - default : - { - return(qfalse); - } - } - - break; - } - - case PNG_ColourType_TrueAlpha : - { - switch(IHDR->BitDepth) - { - case PNG_BitDepth_8 : - { - OutPtr[0] = DecompPtr[0]; - OutPtr[1] = DecompPtr[1]; - OutPtr[2] = DecompPtr[2]; - OutPtr[3] = DecompPtr[3]; - - break; - } - - case PNG_BitDepth_16 : - { - /* - * We use only the upper byte. - */ - - OutPtr[0] = DecompPtr[0]; - OutPtr[1] = DecompPtr[2]; - OutPtr[2] = DecompPtr[4]; - OutPtr[3] = DecompPtr[6]; - - break; - } - - default : - { - return(qfalse); - } - } - - break; - } - - default : - { - return(qfalse); - } - } - - return(qtrue); -} - - -/* - * Decode a non-interlaced image. - */ - -static qboolean DecodeImageNonInterlaced(struct PNG_Chunk_IHDR *IHDR, - byte *OutBuffer, - uint8_t *DecompressedData, - uint32_t DecompressedDataLength, - qboolean HasTransparentColour, - uint8_t *TransparentColour, - uint8_t *OutPal) -{ - uint32_t IHDR_Width; - uint32_t IHDR_Height; - uint32_t BytesPerScanline, BytesPerPixel, PixelsPerByte; - uint32_t w, h, p; - byte *OutPtr; - uint8_t *DecompPtr; - - /* - * input verification - */ - - if(!(IHDR && OutBuffer && DecompressedData && DecompressedDataLength && TransparentColour && OutPal)) - { - return(qfalse); - } - - /* - * byte swapping - */ - - IHDR_Width = BigLong(IHDR->Width); - IHDR_Height = BigLong(IHDR->Height); - - /* - * information for un-filtering - */ - - switch(IHDR->ColourType) - { - case PNG_ColourType_Grey : - { - switch(IHDR->BitDepth) - { - case PNG_BitDepth_1 : - case PNG_BitDepth_2 : - case PNG_BitDepth_4 : - { - BytesPerPixel = 1; - PixelsPerByte = 8 / IHDR->BitDepth; - - break; - } - - case PNG_BitDepth_8 : - case PNG_BitDepth_16 : - { - BytesPerPixel = (IHDR->BitDepth / 8) * PNG_NumColourComponents_Grey; - PixelsPerByte = 1; - - break; - } - - default : - { - return(qfalse); - } - } - - break; - } - - case PNG_ColourType_True : - { - switch(IHDR->BitDepth) - { - case PNG_BitDepth_8 : - case PNG_BitDepth_16 : - { - BytesPerPixel = (IHDR->BitDepth / 8) * PNG_NumColourComponents_True; - PixelsPerByte = 1; - - break; - } - - default : - { - return(qfalse); - } - } - - break; - } - - case PNG_ColourType_Indexed : - { - switch(IHDR->BitDepth) - { - case PNG_BitDepth_1 : - case PNG_BitDepth_2 : - case PNG_BitDepth_4 : - { - BytesPerPixel = 1; - PixelsPerByte = 8 / IHDR->BitDepth; - - break; - } - - case PNG_BitDepth_8 : - { - BytesPerPixel = PNG_NumColourComponents_Indexed; - PixelsPerByte = 1; - - break; - } - - default : - { - return(qfalse); - } - } - - break; - } - - case PNG_ColourType_GreyAlpha : - { - switch(IHDR->BitDepth) - { - case PNG_BitDepth_8 : - case PNG_BitDepth_16 : - { - BytesPerPixel = (IHDR->BitDepth / 8) * PNG_NumColourComponents_GreyAlpha; - PixelsPerByte = 1; - - break; - } - - default : - { - return(qfalse); - } - } - - break; - } - - case PNG_ColourType_TrueAlpha : - { - switch(IHDR->BitDepth) - { - case PNG_BitDepth_8 : - case PNG_BitDepth_16 : - { - BytesPerPixel = (IHDR->BitDepth / 8) * PNG_NumColourComponents_TrueAlpha; - PixelsPerByte = 1; - - break; - } - - default : - { - return(qfalse); - } - } - - break; - } - - default : - { - return(qfalse); - } - } - - /* - * Calculate the size of one scanline - */ - - BytesPerScanline = (IHDR_Width * BytesPerPixel + (PixelsPerByte - 1)) / PixelsPerByte; - - /* - * Check if we have enough data for the whole image. - */ - - if(!(DecompressedDataLength == ((BytesPerScanline + 1) * IHDR_Height))) - { - return(qfalse); - } - - /* - * Unfilter the image. - */ - - if(!UnfilterImage(DecompressedData, IHDR_Height, BytesPerScanline, BytesPerPixel)) - { - return(qfalse); - } - - /* - * Set the working pointers to the beginning of the buffers. - */ - - OutPtr = OutBuffer; - DecompPtr = DecompressedData; - - /* - * Create the output image. - */ - - for(h = 0; h < IHDR_Height; h++) - { - /* - * Count the pixels on the scanline for those multipixel bytes - */ - - uint32_t CurrPixel; - - /* - * skip FilterType - */ - - DecompPtr++; - - /* - * Reset the pixel count. - */ - - CurrPixel = 0; - - for(w = 0; w < (BytesPerScanline / BytesPerPixel); w++) - { - if(PixelsPerByte > 1) - { - uint8_t Mask; - uint32_t Shift; - uint8_t SinglePixel; - - for(p = 0; p < PixelsPerByte; p++) - { - if(CurrPixel < IHDR_Width) - { - Mask = (1 << IHDR->BitDepth) - 1; - Shift = (PixelsPerByte - 1 - p) * IHDR->BitDepth; - - SinglePixel = ((DecompPtr[0] & (Mask << Shift)) >> Shift); - - if(!ConvertPixel(IHDR, OutPtr, &SinglePixel, HasTransparentColour, TransparentColour, OutPal)) - { - return(qfalse); - } - - OutPtr += Q3IMAGE_BYTESPERPIXEL; - CurrPixel++; - } - } - - } - else - { - if(!ConvertPixel(IHDR, OutPtr, DecompPtr, HasTransparentColour, TransparentColour, OutPal)) - { - return(qfalse); - } - - - OutPtr += Q3IMAGE_BYTESPERPIXEL; - } - - DecompPtr += BytesPerPixel; - } - } - - return(qtrue); -} - -/* - * Decode an interlaced image. - */ - -static qboolean DecodeImageInterlaced(struct PNG_Chunk_IHDR *IHDR, - byte *OutBuffer, - uint8_t *DecompressedData, - uint32_t DecompressedDataLength, - qboolean HasTransparentColour, - uint8_t *TransparentColour, - uint8_t *OutPal) -{ - uint32_t IHDR_Width; - uint32_t IHDR_Height; - uint32_t BytesPerScanline[PNG_Adam7_NumPasses], BytesPerPixel, PixelsPerByte; - uint32_t PassWidth[PNG_Adam7_NumPasses], PassHeight[PNG_Adam7_NumPasses]; - uint32_t WSkip[PNG_Adam7_NumPasses], WOffset[PNG_Adam7_NumPasses], HSkip[PNG_Adam7_NumPasses], HOffset[PNG_Adam7_NumPasses]; - uint32_t w, h, p, a; - byte *OutPtr; - uint8_t *DecompPtr; - uint32_t TargetLength; - - /* - * input verification - */ - - if(!(IHDR && OutBuffer && DecompressedData && DecompressedDataLength && TransparentColour && OutPal)) - { - return(qfalse); - } - - /* - * byte swapping - */ - - IHDR_Width = BigLong(IHDR->Width); - IHDR_Height = BigLong(IHDR->Height); - - /* - * Skip and Offset for the passes. - */ - - WSkip[0] = 8; - WOffset[0] = 0; - HSkip[0] = 8; - HOffset[0] = 0; - - WSkip[1] = 8; - WOffset[1] = 4; - HSkip[1] = 8; - HOffset[1] = 0; - - WSkip[2] = 4; - WOffset[2] = 0; - HSkip[2] = 8; - HOffset[2] = 4; - - WSkip[3] = 4; - WOffset[3] = 2; - HSkip[3] = 4; - HOffset[3] = 0; - - WSkip[4] = 2; - WOffset[4] = 0; - HSkip[4] = 4; - HOffset[4] = 2; - - WSkip[5] = 2; - WOffset[5] = 1; - HSkip[5] = 2; - HOffset[5] = 0; - - WSkip[6] = 1; - WOffset[6] = 0; - HSkip[6] = 2; - HOffset[6] = 1; - - /* - * Calculate the sizes of the passes. - */ - - PassWidth[0] = (IHDR_Width + 7) / 8; - PassHeight[0] = (IHDR_Height + 7) / 8; - - PassWidth[1] = (IHDR_Width + 3) / 8; - PassHeight[1] = (IHDR_Height + 7) / 8; - - PassWidth[2] = (IHDR_Width + 3) / 4; - PassHeight[2] = (IHDR_Height + 3) / 8; - - PassWidth[3] = (IHDR_Width + 1) / 4; - PassHeight[3] = (IHDR_Height + 3) / 4; - - PassWidth[4] = (IHDR_Width + 1) / 2; - PassHeight[4] = (IHDR_Height + 1) / 4; - - PassWidth[5] = (IHDR_Width + 0) / 2; - PassHeight[5] = (IHDR_Height + 1) / 2; - - PassWidth[6] = (IHDR_Width + 0) / 1; - PassHeight[6] = (IHDR_Height + 0) / 2; - - /* - * information for un-filtering - */ - - switch(IHDR->ColourType) - { - case PNG_ColourType_Grey : - { - switch(IHDR->BitDepth) - { - case PNG_BitDepth_1 : - case PNG_BitDepth_2 : - case PNG_BitDepth_4 : - { - BytesPerPixel = 1; - PixelsPerByte = 8 / IHDR->BitDepth; - - break; - } - - case PNG_BitDepth_8 : - case PNG_BitDepth_16 : - { - BytesPerPixel = (IHDR->BitDepth / 8) * PNG_NumColourComponents_Grey; - PixelsPerByte = 1; - - break; - } - - default : - { - return(qfalse); - } - } - - break; - } - - case PNG_ColourType_True : - { - switch(IHDR->BitDepth) - { - case PNG_BitDepth_8 : - case PNG_BitDepth_16 : - { - BytesPerPixel = (IHDR->BitDepth / 8) * PNG_NumColourComponents_True; - PixelsPerByte = 1; - - break; - } - - default : - { - return(qfalse); - } - } - - break; - } - - case PNG_ColourType_Indexed : - { - switch(IHDR->BitDepth) - { - case PNG_BitDepth_1 : - case PNG_BitDepth_2 : - case PNG_BitDepth_4 : - { - BytesPerPixel = 1; - PixelsPerByte = 8 / IHDR->BitDepth; - - break; - } - - case PNG_BitDepth_8 : - { - BytesPerPixel = PNG_NumColourComponents_Indexed; - PixelsPerByte = 1; - - break; - } - - default : - { - return(qfalse); - } - } - - break; - } - - case PNG_ColourType_GreyAlpha : - { - switch(IHDR->BitDepth) - { - case PNG_BitDepth_8 : - case PNG_BitDepth_16 : - { - BytesPerPixel = (IHDR->BitDepth / 8) * PNG_NumColourComponents_GreyAlpha; - PixelsPerByte = 1; - - break; - } - - default : - { - return(qfalse); - } - } - - break; - } - - case PNG_ColourType_TrueAlpha : - { - switch(IHDR->BitDepth) - { - case PNG_BitDepth_8 : - case PNG_BitDepth_16 : - { - BytesPerPixel = (IHDR->BitDepth / 8) * PNG_NumColourComponents_TrueAlpha; - PixelsPerByte = 1; - - break; - } - - default : - { - return(qfalse); - } - } - - break; - } - - default : - { - return(qfalse); - } - } - - /* - * Calculate the size of the scanlines per pass - */ - - for(a = 0; a < PNG_Adam7_NumPasses; a++) - { - BytesPerScanline[a] = (PassWidth[a] * BytesPerPixel + (PixelsPerByte - 1)) / PixelsPerByte; - } - - /* - * Calculate the size of all passes - */ - - TargetLength = 0; - - for(a = 0; a < PNG_Adam7_NumPasses; a++) - { - TargetLength += ((BytesPerScanline[a] + (BytesPerScanline[a] ? 1 : 0)) * PassHeight[a]); - } - - /* - * Check if we have enough data for the whole image. - */ - - if(!(DecompressedDataLength == TargetLength)) - { - return(qfalse); - } - - /* - * Unfilter the image. - */ - - DecompPtr = DecompressedData; - - for(a = 0; a < PNG_Adam7_NumPasses; a++) - { - if(!UnfilterImage(DecompPtr, PassHeight[a], BytesPerScanline[a], BytesPerPixel)) - { - return(qfalse); - } - - DecompPtr += ((BytesPerScanline[a] + (BytesPerScanline[a] ? 1 : 0)) * PassHeight[a]); - } - - /* - * Set the working pointers to the beginning of the buffers. - */ - - DecompPtr = DecompressedData; - - /* - * Create the output image. - */ - - for(a = 0; a < PNG_Adam7_NumPasses; a++) - { - for(h = 0; h < PassHeight[a]; h++) - { - /* - * Count the pixels on the scanline for those multipixel bytes - */ - - uint32_t CurrPixel; - - /* - * skip FilterType - * but only when the pass has a width bigger than zero - */ - - if(BytesPerScanline[a]) - { - DecompPtr++; - } - - /* - * Reset the pixel count. - */ - - CurrPixel = 0; - - for(w = 0; w < (BytesPerScanline[a] / BytesPerPixel); w++) - { - if(PixelsPerByte > 1) - { - uint8_t Mask; - uint32_t Shift; - uint8_t SinglePixel; - - for(p = 0; p < PixelsPerByte; p++) - { - if(CurrPixel < PassWidth[a]) - { - Mask = (1 << IHDR->BitDepth) - 1; - Shift = (PixelsPerByte - 1 - p) * IHDR->BitDepth; - - SinglePixel = ((DecompPtr[0] & (Mask << Shift)) >> Shift); - - OutPtr = OutBuffer + (((((h * HSkip[a]) + HOffset[a]) * IHDR_Width) + ((CurrPixel * WSkip[a]) + WOffset[a])) * Q3IMAGE_BYTESPERPIXEL); - - if(!ConvertPixel(IHDR, OutPtr, &SinglePixel, HasTransparentColour, TransparentColour, OutPal)) - { - return(qfalse); - } - - CurrPixel++; - } - } - - } - else - { - OutPtr = OutBuffer + (((((h * HSkip[a]) + HOffset[a]) * IHDR_Width) + ((w * WSkip[a]) + WOffset[a])) * Q3IMAGE_BYTESPERPIXEL); - - if(!ConvertPixel(IHDR, OutPtr, DecompPtr, HasTransparentColour, TransparentColour, OutPal)) - { - return(qfalse); - } - } - - DecompPtr += BytesPerPixel; - } - } - } - - return(qtrue); -} - -/* - * The PNG loader - */ - -void R_LoadPNG(const char *name, byte **pic, int *width, int *height) -{ - struct BufferedFile *ThePNG; - byte *OutBuffer; - uint8_t *Signature; - struct PNG_ChunkHeader *CH; - uint32_t ChunkHeaderLength; - uint32_t ChunkHeaderType; - struct PNG_Chunk_IHDR *IHDR; - uint32_t IHDR_Width; - uint32_t IHDR_Height; - PNG_ChunkCRC *CRC; - uint8_t *InPal; - uint8_t *DecompressedData; - uint32_t DecompressedDataLength; - uint32_t i; - - /* - * palette with 256 RGBA entries - */ - - uint8_t OutPal[1024]; - - /* - * transparent colour from the tRNS chunk - */ - - qboolean HasTransparentColour = qfalse; - uint8_t TransparentColour[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; - - /* - * input verification - */ - - if(!(name && pic)) - { - return; - } - - /* - * Zero out return values. - */ - - *pic = NULL; - - if(width) - { - *width = 0; - } - - if(height) - { - *height = 0; - } - - /* - * Read the file. - */ - - ThePNG = ReadBufferedFile(name); - if(!ThePNG) - { - return; - } - - /* - * Read the siganture of the file. - */ - - Signature = BufferedFileRead(ThePNG, PNG_Signature_Size); - if(!Signature) - { - CloseBufferedFile(ThePNG); - - return; - } - - /* - * Is it a PNG? - */ - - if(memcmp(Signature, PNG_Signature, PNG_Signature_Size)) - { - CloseBufferedFile(ThePNG); - - return; - } - - /* - * Read the first chunk-header. - */ - - CH = BufferedFileRead(ThePNG, PNG_ChunkHeader_Size); - if(!CH) - { - CloseBufferedFile(ThePNG); - - return; - } - - /* - * PNG multi-byte types are in Big Endian - */ - - ChunkHeaderLength = BigLong(CH->Length); - ChunkHeaderType = BigLong(CH->Type); - - /* - * Check if the first chunk is an IHDR. - */ - - if(!((ChunkHeaderType == PNG_ChunkType_IHDR) && (ChunkHeaderLength == PNG_Chunk_IHDR_Size))) - { - CloseBufferedFile(ThePNG); - - return; - } - - /* - * Read the IHDR. - */ - - IHDR = BufferedFileRead(ThePNG, PNG_Chunk_IHDR_Size); - if(!IHDR) - { - CloseBufferedFile(ThePNG); - - return; - } - - /* - * Read the CRC for IHDR - */ - - CRC = BufferedFileRead(ThePNG, PNG_ChunkCRC_Size); - if(!CRC) - { - CloseBufferedFile(ThePNG); - - return; - } - - /* - * Here we could check the CRC if we wanted to. - */ - - /* - * multi-byte type swapping - */ - - IHDR_Width = BigLong(IHDR->Width); - IHDR_Height = BigLong(IHDR->Height); - - /* - * Check if Width and Height are valid. - */ - - if(!((IHDR_Width > 0) && (IHDR_Height > 0)) - || IHDR_Width > INT_MAX / Q3IMAGE_BYTESPERPIXEL / IHDR_Height) - { - CloseBufferedFile(ThePNG); - - ri.Printf( PRINT_WARNING, "%s: invalid image size\n", name ); - - return; - } - - /* - * Do we need to check if the dimensions of the image are valid for Quake3? - */ - - /* - * Check if CompressionMethod and FilterMethod are valid. - */ - - if(!((IHDR->CompressionMethod == PNG_CompressionMethod_0) && (IHDR->FilterMethod == PNG_FilterMethod_0))) - { - CloseBufferedFile(ThePNG); - - return; - } - - /* - * Check if InterlaceMethod is valid. - */ - - if(!((IHDR->InterlaceMethod == PNG_InterlaceMethod_NonInterlaced) || (IHDR->InterlaceMethod == PNG_InterlaceMethod_Interlaced))) - { - CloseBufferedFile(ThePNG); - - return; - } - - /* - * Read palette for an indexed image. - */ - - if(IHDR->ColourType == PNG_ColourType_Indexed) - { - /* - * We need the palette first. - */ - - if(!FindChunk(ThePNG, PNG_ChunkType_PLTE)) - { - CloseBufferedFile(ThePNG); - - return; - } - - /* - * Read the chunk-header. - */ - - CH = BufferedFileRead(ThePNG, PNG_ChunkHeader_Size); - if(!CH) - { - CloseBufferedFile(ThePNG); - - return; - } - - /* - * PNG multi-byte types are in Big Endian - */ - - ChunkHeaderLength = BigLong(CH->Length); - ChunkHeaderType = BigLong(CH->Type); - - /* - * Check if the chunk is a PLTE. - */ - - if(!(ChunkHeaderType == PNG_ChunkType_PLTE)) - { - CloseBufferedFile(ThePNG); - - return; - } - - /* - * Check if Length is divisible by 3 - */ - - if(ChunkHeaderLength % 3) - { - CloseBufferedFile(ThePNG); - - return; - } - - /* - * Read the raw palette data - */ - - InPal = BufferedFileRead(ThePNG, ChunkHeaderLength); - if(!InPal) - { - CloseBufferedFile(ThePNG); - - return; - } - - /* - * Read the CRC for the palette - */ - - CRC = BufferedFileRead(ThePNG, PNG_ChunkCRC_Size); - if(!CRC) - { - CloseBufferedFile(ThePNG); - - return; - } - - /* - * Set some default values. - */ - - for(i = 0; i < 256; i++) - { - OutPal[i * Q3IMAGE_BYTESPERPIXEL + 0] = 0x00; - OutPal[i * Q3IMAGE_BYTESPERPIXEL + 1] = 0x00; - OutPal[i * Q3IMAGE_BYTESPERPIXEL + 2] = 0x00; - OutPal[i * Q3IMAGE_BYTESPERPIXEL + 3] = 0xFF; - } - - /* - * Convert to the Quake3 RGBA-format. - */ - - for(i = 0; i < (ChunkHeaderLength / 3); i++) - { - OutPal[i * Q3IMAGE_BYTESPERPIXEL + 0] = InPal[i*3+0]; - OutPal[i * Q3IMAGE_BYTESPERPIXEL + 1] = InPal[i*3+1]; - OutPal[i * Q3IMAGE_BYTESPERPIXEL + 2] = InPal[i*3+2]; - OutPal[i * Q3IMAGE_BYTESPERPIXEL + 3] = 0xFF; - } - } - - /* - * transparency information is sometimes stored in a tRNS chunk - */ - - /* - * Let's see if there is a tRNS chunk - */ - - if(FindChunk(ThePNG, PNG_ChunkType_tRNS)) - { - uint8_t *Trans; - - /* - * Read the chunk-header. - */ - - CH = BufferedFileRead(ThePNG, PNG_ChunkHeader_Size); - if(!CH) - { - CloseBufferedFile(ThePNG); - - return; - } - - /* - * PNG multi-byte types are in Big Endian - */ - - ChunkHeaderLength = BigLong(CH->Length); - ChunkHeaderType = BigLong(CH->Type); - - /* - * Check if the chunk is a tRNS. - */ - - if(!(ChunkHeaderType == PNG_ChunkType_tRNS)) - { - CloseBufferedFile(ThePNG); - - return; - } - - /* - * Read the transparency information. - */ - - Trans = BufferedFileRead(ThePNG, ChunkHeaderLength); - if(!Trans) - { - CloseBufferedFile(ThePNG); - - return; - } - - /* - * Read the CRC. - */ - - CRC = BufferedFileRead(ThePNG, PNG_ChunkCRC_Size); - if(!CRC) - { - CloseBufferedFile(ThePNG); - - return; - } - - /* - * Only for Grey, True and Indexed ColourType should tRNS exist. - */ - - switch(IHDR->ColourType) - { - case PNG_ColourType_Grey : - { - if(!ChunkHeaderLength == 2) - { - CloseBufferedFile(ThePNG); - - return; - } - - HasTransparentColour = qtrue; - - /* - * Grey can have one colour which is completely transparent. - * This colour is always stored in 16 bits. - */ - - TransparentColour[0] = Trans[0]; - TransparentColour[1] = Trans[1]; - - break; - } - - case PNG_ColourType_True : - { - if(!ChunkHeaderLength == 6) - { - CloseBufferedFile(ThePNG); - - return; - } - - HasTransparentColour = qtrue; - - /* - * True can have one colour which is completely transparent. - * This colour is always stored in 16 bits. - */ - - TransparentColour[0] = Trans[0]; - TransparentColour[1] = Trans[1]; - TransparentColour[2] = Trans[2]; - TransparentColour[3] = Trans[3]; - TransparentColour[4] = Trans[4]; - TransparentColour[5] = Trans[5]; - - break; - } - - case PNG_ColourType_Indexed : - { - /* - * Maximum of 256 one byte transparency entries. - */ - - if(ChunkHeaderLength > 256) - { - CloseBufferedFile(ThePNG); - - return; - } - - HasTransparentColour = qtrue; - - /* - * alpha values for palette entries - */ - - for(i = 0; i < ChunkHeaderLength; i++) - { - OutPal[i * Q3IMAGE_BYTESPERPIXEL + 3] = Trans[i]; - } - - break; - } - - /* - * All other ColourTypes should not have tRNS chunks - */ - - default : - { - CloseBufferedFile(ThePNG); - - return; - } - } - } - - /* - * Rewind to the start of the file. - */ - - if(!BufferedFileRewind(ThePNG, -1)) - { - CloseBufferedFile(ThePNG); - - return; - } - - /* - * Skip the signature - */ - - if(!BufferedFileSkip(ThePNG, PNG_Signature_Size)) - { - CloseBufferedFile(ThePNG); - - return; - } - - /* - * Decompress all IDAT chunks - */ - - DecompressedDataLength = DecompressIDATs(ThePNG, &DecompressedData); - if(!(DecompressedDataLength && DecompressedData)) - { - CloseBufferedFile(ThePNG); - - return; - } - - /* - * Allocate output buffer. - */ - - OutBuffer = ri.Malloc(IHDR_Width * IHDR_Height * Q3IMAGE_BYTESPERPIXEL); - if(!OutBuffer) - { - ri.Free(DecompressedData); - CloseBufferedFile(ThePNG); - - return; - } - - /* - * Interlaced and Non-interlaced images need to be handled differently. - */ - - switch(IHDR->InterlaceMethod) - { - case PNG_InterlaceMethod_NonInterlaced : - { - if(!DecodeImageNonInterlaced(IHDR, OutBuffer, DecompressedData, DecompressedDataLength, HasTransparentColour, TransparentColour, OutPal)) - { - ri.Free(OutBuffer); - ri.Free(DecompressedData); - CloseBufferedFile(ThePNG); - - return; - } - - break; - } - - case PNG_InterlaceMethod_Interlaced : - { - if(!DecodeImageInterlaced(IHDR, OutBuffer, DecompressedData, DecompressedDataLength, HasTransparentColour, TransparentColour, OutPal)) - { - ri.Free(OutBuffer); - ri.Free(DecompressedData); - CloseBufferedFile(ThePNG); - - return; - } - - break; - } - - default : - { - ri.Free(OutBuffer); - ri.Free(DecompressedData); - CloseBufferedFile(ThePNG); - - return; - } - } - - /* - * update the pointer to the image data - */ - - *pic = OutBuffer; - - /* - * Fill width and height. - */ - - if(width) - { - *width = IHDR_Width; - } - - if(height) - { - *height = IHDR_Height; - } - - /* - * DecompressedData is not needed anymore. - */ - - ri.Free(DecompressedData); - - /* - * We have all data, so close the file. - */ - - CloseBufferedFile(ThePNG); -} diff --git a/code/rend2/tr_image_tga.c b/code/rend2/tr_image_tga.c deleted file mode 100644 index 27ca0d7b..00000000 --- a/code/rend2/tr_image_tga.c +++ /dev/null @@ -1,324 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -#include "../qcommon/q_shared.h" -#include "../qcommon/qfiles.h" -#include "../qcommon/qcommon.h" -#include "../renderer/tr_public.h" -extern refimport_t ri; - -/* -======================================================================== - -TGA files are used for 24/32 bit images - -======================================================================== -*/ - -typedef struct _TargaHeader { - unsigned char id_length, colormap_type, image_type; - unsigned short colormap_index, colormap_length; - unsigned char colormap_size; - unsigned short x_origin, y_origin, width, height; - unsigned char pixel_size, attributes; -} TargaHeader; - -void R_LoadTGA ( const char *name, byte **pic, int *width, int *height) -{ - unsigned columns, rows, numPixels; - byte *pixbuf; - int row, column; - byte *buf_p; - byte *end; - union { - byte *b; - void *v; - } buffer; - TargaHeader targa_header; - byte *targa_rgba; - int length; - - *pic = NULL; - - if(width) - *width = 0; - if(height) - *height = 0; - - // - // load the file - // - length = ri.FS_ReadFile ( ( char * ) name, &buffer.v); - if (!buffer.b || length < 0) { - return; - } - - if(length < 18) - { - ri.Error( ERR_DROP, "LoadTGA: header too short (%s)", name ); - } - - buf_p = buffer.b; - end = buffer.b + length; - - targa_header.id_length = buf_p[0]; - targa_header.colormap_type = buf_p[1]; - targa_header.image_type = buf_p[2]; - - memcpy(&targa_header.colormap_index, &buf_p[3], 2); - memcpy(&targa_header.colormap_length, &buf_p[5], 2); - targa_header.colormap_size = buf_p[7]; - memcpy(&targa_header.x_origin, &buf_p[8], 2); - memcpy(&targa_header.y_origin, &buf_p[10], 2); - memcpy(&targa_header.width, &buf_p[12], 2); - memcpy(&targa_header.height, &buf_p[14], 2); - targa_header.pixel_size = buf_p[16]; - targa_header.attributes = buf_p[17]; - - targa_header.colormap_index = LittleShort(targa_header.colormap_index); - targa_header.colormap_length = LittleShort(targa_header.colormap_length); - targa_header.x_origin = LittleShort(targa_header.x_origin); - targa_header.y_origin = LittleShort(targa_header.y_origin); - targa_header.width = LittleShort(targa_header.width); - targa_header.height = LittleShort(targa_header.height); - - buf_p += 18; - - if (targa_header.image_type!=2 - && targa_header.image_type!=10 - && targa_header.image_type != 3 ) - { - ri.Error (ERR_DROP, "LoadTGA: Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported"); - } - - if ( targa_header.colormap_type != 0 ) - { - ri.Error( ERR_DROP, "LoadTGA: colormaps not supported" ); - } - - if ( ( targa_header.pixel_size != 32 && targa_header.pixel_size != 24 ) && targa_header.image_type != 3 ) - { - ri.Error (ERR_DROP, "LoadTGA: Only 32 or 24 bit images supported (no colormaps)"); - } - - columns = targa_header.width; - rows = targa_header.height; - numPixels = columns * rows * 4; - - if(!columns || !rows || numPixels > 0x7FFFFFFF || numPixels / columns / 4 != rows) - { - ri.Error (ERR_DROP, "LoadTGA: %s has an invalid image size", name); - } - - - targa_rgba = ri.Malloc (numPixels); - - if (targa_header.id_length != 0) - { - if (buf_p + targa_header.id_length > end) - ri.Error( ERR_DROP, "LoadTGA: header too short (%s)", name ); - - buf_p += targa_header.id_length; // skip TARGA image comment - } - - if ( targa_header.image_type==2 || targa_header.image_type == 3 ) - { - if(buf_p + columns*rows*targa_header.pixel_size/8 > end) - { - ri.Error (ERR_DROP, "LoadTGA: file truncated (%s)", name); - } - - // Uncompressed RGB or gray scale image - for(row=rows-1; row>=0; row--) - { - pixbuf = targa_rgba + row*columns*4; - for(column=0; column=0; row--) { - pixbuf = targa_rgba + row*columns*4; - for(column=0; column end) - ri.Error (ERR_DROP, "LoadTGA: file truncated (%s)", name); - packetHeader= *buf_p++; - packetSize = 1 + (packetHeader & 0x7f); - if (packetHeader & 0x80) { // run-length packet - if(buf_p + targa_header.pixel_size/8 > end) - ri.Error (ERR_DROP, "LoadTGA: file truncated (%s)", name); - switch (targa_header.pixel_size) { - case 24: - blue = *buf_p++; - green = *buf_p++; - red = *buf_p++; - alphabyte = 255; - break; - case 32: - blue = *buf_p++; - green = *buf_p++; - red = *buf_p++; - alphabyte = *buf_p++; - break; - default: - ri.Error( ERR_DROP, "LoadTGA: illegal pixel_size '%d' in file '%s'", targa_header.pixel_size, name ); - break; - } - - for(j=0;j0) - row--; - else - goto breakOut; - pixbuf = targa_rgba + row*columns*4; - } - } - } - else { // non run-length packet - - if(buf_p + targa_header.pixel_size/8*packetSize > end) - ri.Error (ERR_DROP, "LoadTGA: file truncated (%s)", name); - for(j=0;j0) - row--; - else - goto breakOut; - pixbuf = targa_rgba + row*columns*4; - } - } - } - } - breakOut:; - } - } - -#if 0 - // TTimo: this is the chunk of code to ensure a behavior that meets TGA specs - // bit 5 set => top-down - if (targa_header.attributes & 0x20) { - unsigned char *flip = (unsigned char*)malloc (columns*4); - unsigned char *src, *dst; - - for (row = 0; row < rows/2; row++) { - src = targa_rgba + row * 4 * columns; - dst = targa_rgba + (rows - row - 1) * 4 * columns; - - memcpy (flip, src, columns*4); - memcpy (src, dst, columns*4); - memcpy (dst, flip, columns*4); - } - free (flip); - } -#endif - // instead we just print a warning - if (targa_header.attributes & 0x20) { - ri.Printf( PRINT_WARNING, "WARNING: '%s' TGA file header declares top-down image, ignoring\n", name); - } - - if (width) - *width = columns; - if (height) - *height = rows; - - *pic = targa_rgba; - - ri.FS_FreeFile (buffer.v); -} diff --git a/code/renderer/qgl.h b/code/renderer/qgl.h deleted file mode 100644 index 52961937..00000000 --- a/code/renderer/qgl.h +++ /dev/null @@ -1,380 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -/* -** QGL.H -*/ - -#ifndef __QGL_H__ -#define __QGL_H__ - -#ifdef USE_LOCAL_HEADERS -# include "SDL_opengl.h" -#else -# include -#endif - -extern void (APIENTRYP qglActiveTextureARB) (GLenum texture); -extern void (APIENTRYP qglClientActiveTextureARB) (GLenum texture); -extern void (APIENTRYP qglMultiTexCoord2fARB) (GLenum target, GLfloat s, GLfloat t); - -extern void (APIENTRYP qglLockArraysEXT) (GLint first, GLsizei count); -extern void (APIENTRYP qglUnlockArraysEXT) (void); - - -//=========================================================================== - -#define qglAccum glAccum -#define qglAlphaFunc glAlphaFunc -#define qglAreTexturesResident glAreTexturesResident -#define qglArrayElement glArrayElement -#define qglBegin glBegin -#define qglBindTexture glBindTexture -#define qglBitmap glBitmap -#define qglBlendFunc glBlendFunc -#define qglCallList glCallList -#define qglCallLists glCallLists -#define qglClear glClear -#define qglClearAccum glClearAccum -#define qglClearColor glClearColor -#define qglClearDepth glClearDepth -#define qglClearIndex glClearIndex -#define qglClearStencil glClearStencil -#define qglClipPlane glClipPlane -#define qglColor3b glColor3b -#define qglColor3bv glColor3bv -#define qglColor3d glColor3d -#define qglColor3dv glColor3dv -#define qglColor3f glColor3f -#define qglColor3fv glColor3fv -#define qglColor3i glColor3i -#define qglColor3iv glColor3iv -#define qglColor3s glColor3s -#define qglColor3sv glColor3sv -#define qglColor3ub glColor3ub -#define qglColor3ubv glColor3ubv -#define qglColor3ui glColor3ui -#define qglColor3uiv glColor3uiv -#define qglColor3us glColor3us -#define qglColor3usv glColor3usv -#define qglColor4b glColor4b -#define qglColor4bv glColor4bv -#define qglColor4d glColor4d -#define qglColor4dv glColor4dv -#define qglColor4f glColor4f -#define qglColor4fv glColor4fv -#define qglColor4i glColor4i -#define qglColor4iv glColor4iv -#define qglColor4s glColor4s -#define qglColor4sv glColor4sv -#define qglColor4ub glColor4ub -#define qglColor4ubv glColor4ubv -#define qglColor4ui glColor4ui -#define qglColor4uiv glColor4uiv -#define qglColor4us glColor4us -#define qglColor4usv glColor4usv -#define qglColorMask glColorMask -#define qglColorMaterial glColorMaterial -#define qglColorPointer glColorPointer -#define qglCopyPixels glCopyPixels -#define qglCopyTexImage1D glCopyTexImage1D -#define qglCopyTexImage2D glCopyTexImage2D -#define qglCopyTexSubImage1D glCopyTexSubImage1D -#define qglCopyTexSubImage2D glCopyTexSubImage2D -#define qglCullFace glCullFace -#define qglDeleteLists glDeleteLists -#define qglDeleteTextures glDeleteTextures -#define qglDepthFunc glDepthFunc -#define qglDepthMask glDepthMask -#define qglDepthRange glDepthRange -#define qglDisable glDisable -#define qglDisableClientState glDisableClientState -#define qglDrawArrays glDrawArrays -#define qglDrawBuffer glDrawBuffer -#define qglDrawElements glDrawElements -#define qglDrawPixels glDrawPixels -#define qglEdgeFlag glEdgeFlag -#define qglEdgeFlagPointer glEdgeFlagPointer -#define qglEdgeFlagv glEdgeFlagv -#define qglEnable glEnable -#define qglEnableClientState glEnableClientState -#define qglEnd glEnd -#define qglEndList glEndList -#define qglEvalCoord1d glEvalCoord1d -#define qglEvalCoord1dv glEvalCoord1dv -#define qglEvalCoord1f glEvalCoord1f -#define qglEvalCoord1fv glEvalCoord1fv -#define qglEvalCoord2d glEvalCoord2d -#define qglEvalCoord2dv glEvalCoord2dv -#define qglEvalCoord2f glEvalCoord2f -#define qglEvalCoord2fv glEvalCoord2fv -#define qglEvalMesh1 glEvalMesh1 -#define qglEvalMesh2 glEvalMesh2 -#define qglEvalPoint1 glEvalPoint1 -#define qglEvalPoint2 glEvalPoint2 -#define qglFeedbackBuffer glFeedbackBuffer -#define qglFinish glFinish -#define qglFlush glFlush -#define qglFogf glFogf -#define qglFogfv glFogfv -#define qglFogi glFogi -#define qglFogiv glFogiv -#define qglFrontFace glFrontFace -#define qglFrustum glFrustum -#define qglGenLists glGenLists -#define qglGenTextures glGenTextures -#define qglGetBooleanv glGetBooleanv -#define qglGetClipPlane glGetClipPlane -#define qglGetDoublev glGetDoublev -#define qglGetError glGetError -#define qglGetFloatv glGetFloatv -#define qglGetIntegerv glGetIntegerv -#define qglGetLightfv glGetLightfv -#define qglGetLightiv glGetLightiv -#define qglGetMapdv glGetMapdv -#define qglGetMapfv glGetMapfv -#define qglGetMapiv glGetMapiv -#define qglGetMaterialfv glGetMaterialfv -#define qglGetMaterialiv glGetMaterialiv -#define qglGetPixelMapfv glGetPixelMapfv -#define qglGetPixelMapuiv glGetPixelMapuiv -#define qglGetPixelMapusv glGetPixelMapusv -#define qglGetPointerv glGetPointerv -#define qglGetPolygonStipple glGetPolygonStipple -#define qglGetString glGetString -#define qglGetTexGendv glGetTexGendv -#define qglGetTexGenfv glGetTexGenfv -#define qglGetTexGeniv glGetTexGeniv -#define qglGetTexImage glGetTexImage -#define qglGetTexLevelParameterfv glGetTexLevelParameterfv -#define qglGetTexLevelParameteriv glGetTexLevelParameteriv -#define qglGetTexParameterfv glGetTexParameterfv -#define qglGetTexParameteriv glGetTexParameteriv -#define qglHint glHint -#define qglIndexMask glIndexMask -#define qglIndexPointer glIndexPointer -#define qglIndexd glIndexd -#define qglIndexdv glIndexdv -#define qglIndexf glIndexf -#define qglIndexfv glIndexfv -#define qglIndexi glIndexi -#define qglIndexiv glIndexiv -#define qglIndexs glIndexs -#define qglIndexsv glIndexsv -#define qglIndexub glIndexub -#define qglIndexubv glIndexubv -#define qglInitNames glInitNames -#define qglInterleavedArrays glInterleavedArrays -#define qglIsEnabled glIsEnabled -#define qglIsList glIsList -#define qglIsTexture glIsTexture -#define qglLightModelf glLightModelf -#define qglLightModelfv glLightModelfv -#define qglLightModeli glLightModeli -#define qglLightModeliv glLightModeliv -#define qglLightf glLightf -#define qglLightfv glLightfv -#define qglLighti glLighti -#define qglLightiv glLightiv -#define qglLineStipple glLineStipple -#define qglLineWidth glLineWidth -#define qglListBase glListBase -#define qglLoadIdentity glLoadIdentity -#define qglLoadMatrixd glLoadMatrixd -#define qglLoadMatrixf glLoadMatrixf -#define qglLoadName glLoadName -#define qglLogicOp glLogicOp -#define qglMap1d glMap1d -#define qglMap1f glMap1f -#define qglMap2d glMap2d -#define qglMap2f glMap2f -#define qglMapGrid1d glMapGrid1d -#define qglMapGrid1f glMapGrid1f -#define qglMapGrid2d glMapGrid2d -#define qglMapGrid2f glMapGrid2f -#define qglMaterialf glMaterialf -#define qglMaterialfv glMaterialfv -#define qglMateriali glMateriali -#define qglMaterialiv glMaterialiv -#define qglMatrixMode glMatrixMode -#define qglMultMatrixd glMultMatrixd -#define qglMultMatrixf glMultMatrixf -#define qglNewList glNewList -#define qglNormal3b glNormal3b -#define qglNormal3bv glNormal3bv -#define qglNormal3d glNormal3d -#define qglNormal3dv glNormal3dv -#define qglNormal3f glNormal3f -#define qglNormal3fv glNormal3fv -#define qglNormal3i glNormal3i -#define qglNormal3iv glNormal3iv -#define qglNormal3s glNormal3s -#define qglNormal3sv glNormal3sv -#define qglNormalPointer glNormalPointer -#define qglOrtho glOrtho -#define qglPassThrough glPassThrough -#define qglPixelMapfv glPixelMapfv -#define qglPixelMapuiv glPixelMapuiv -#define qglPixelMapusv glPixelMapusv -#define qglPixelStoref glPixelStoref -#define qglPixelStorei glPixelStorei -#define qglPixelTransferf glPixelTransferf -#define qglPixelTransferi glPixelTransferi -#define qglPixelZoom glPixelZoom -#define qglPointSize glPointSize -#define qglPolygonMode glPolygonMode -#define qglPolygonOffset glPolygonOffset -#define qglPolygonStipple glPolygonStipple -#define qglPopAttrib glPopAttrib -#define qglPopClientAttrib glPopClientAttrib -#define qglPopMatrix glPopMatrix -#define qglPopName glPopName -#define qglPrioritizeTextures glPrioritizeTextures -#define qglPushAttrib glPushAttrib -#define qglPushClientAttrib glPushClientAttrib -#define qglPushMatrix glPushMatrix -#define qglPushName glPushName -#define qglRasterPos2d glRasterPos2d -#define qglRasterPos2dv glRasterPos2dv -#define qglRasterPos2f glRasterPos2f -#define qglRasterPos2fv glRasterPos2fv -#define qglRasterPos2i glRasterPos2i -#define qglRasterPos2iv glRasterPos2iv -#define qglRasterPos2s glRasterPos2s -#define qglRasterPos2sv glRasterPos2sv -#define qglRasterPos3d glRasterPos3d -#define qglRasterPos3dv glRasterPos3dv -#define qglRasterPos3f glRasterPos3f -#define qglRasterPos3fv glRasterPos3fv -#define qglRasterPos3i glRasterPos3i -#define qglRasterPos3iv glRasterPos3iv -#define qglRasterPos3s glRasterPos3s -#define qglRasterPos3sv glRasterPos3sv -#define qglRasterPos4d glRasterPos4d -#define qglRasterPos4dv glRasterPos4dv -#define qglRasterPos4f glRasterPos4f -#define qglRasterPos4fv glRasterPos4fv -#define qglRasterPos4i glRasterPos4i -#define qglRasterPos4iv glRasterPos4iv -#define qglRasterPos4s glRasterPos4s -#define qglRasterPos4sv glRasterPos4sv -#define qglReadBuffer glReadBuffer -#define qglReadPixels glReadPixels -#define qglRectd glRectd -#define qglRectdv glRectdv -#define qglRectf glRectf -#define qglRectfv glRectfv -#define qglRecti glRecti -#define qglRectiv glRectiv -#define qglRects glRects -#define qglRectsv glRectsv -#define qglRenderMode glRenderMode -#define qglRotated glRotated -#define qglRotatef glRotatef -#define qglScaled glScaled -#define qglScalef glScalef -#define qglScissor glScissor -#define qglSelectBuffer glSelectBuffer -#define qglShadeModel glShadeModel -#define qglStencilFunc glStencilFunc -#define qglStencilMask glStencilMask -#define qglStencilOp glStencilOp -#define qglTexCoord1d glTexCoord1d -#define qglTexCoord1dv glTexCoord1dv -#define qglTexCoord1f glTexCoord1f -#define qglTexCoord1fv glTexCoord1fv -#define qglTexCoord1i glTexCoord1i -#define qglTexCoord1iv glTexCoord1iv -#define qglTexCoord1s glTexCoord1s -#define qglTexCoord1sv glTexCoord1sv -#define qglTexCoord2d glTexCoord2d -#define qglTexCoord2dv glTexCoord2dv -#define qglTexCoord2f glTexCoord2f -#define qglTexCoord2fv glTexCoord2fv -#define qglTexCoord2i glTexCoord2i -#define qglTexCoord2iv glTexCoord2iv -#define qglTexCoord2s glTexCoord2s -#define qglTexCoord2sv glTexCoord2sv -#define qglTexCoord3d glTexCoord3d -#define qglTexCoord3dv glTexCoord3dv -#define qglTexCoord3f glTexCoord3f -#define qglTexCoord3fv glTexCoord3fv -#define qglTexCoord3i glTexCoord3i -#define qglTexCoord3iv glTexCoord3iv -#define qglTexCoord3s glTexCoord3s -#define qglTexCoord3sv glTexCoord3sv -#define qglTexCoord4d glTexCoord4d -#define qglTexCoord4dv glTexCoord4dv -#define qglTexCoord4f glTexCoord4f -#define qglTexCoord4fv glTexCoord4fv -#define qglTexCoord4i glTexCoord4i -#define qglTexCoord4iv glTexCoord4iv -#define qglTexCoord4s glTexCoord4s -#define qglTexCoord4sv glTexCoord4sv -#define qglTexCoordPointer glTexCoordPointer -#define qglTexEnvf glTexEnvf -#define qglTexEnvfv glTexEnvfv -#define qglTexEnvi glTexEnvi -#define qglTexEnviv glTexEnviv -#define qglTexGend glTexGend -#define qglTexGendv glTexGendv -#define qglTexGenf glTexGenf -#define qglTexGenfv glTexGenfv -#define qglTexGeni glTexGeni -#define qglTexGeniv glTexGeniv -#define qglTexImage1D glTexImage1D -#define qglTexImage2D glTexImage2D -#define qglTexParameterf glTexParameterf -#define qglTexParameterfv glTexParameterfv -#define qglTexParameteri glTexParameteri -#define qglTexParameteriv glTexParameteriv -#define qglTexSubImage1D glTexSubImage1D -#define qglTexSubImage2D glTexSubImage2D -#define qglTranslated glTranslated -#define qglTranslatef glTranslatef -#define qglVertex2d glVertex2d -#define qglVertex2dv glVertex2dv -#define qglVertex2f glVertex2f -#define qglVertex2fv glVertex2fv -#define qglVertex2i glVertex2i -#define qglVertex2iv glVertex2iv -#define qglVertex2s glVertex2s -#define qglVertex2sv glVertex2sv -#define qglVertex3d glVertex3d -#define qglVertex3dv glVertex3dv -#define qglVertex3f glVertex3f -#define qglVertex3fv glVertex3fv -#define qglVertex3i glVertex3i -#define qglVertex3iv glVertex3iv -#define qglVertex3s glVertex3s -#define qglVertex3sv glVertex3sv -#define qglVertex4d glVertex4d -#define qglVertex4dv glVertex4dv -#define qglVertex4f glVertex4f -#define qglVertex4fv glVertex4fv -#define qglVertex4i glVertex4i -#define qglVertex4iv glVertex4iv -#define qglVertex4s glVertex4s -#define qglVertex4sv glVertex4sv -#define qglVertexPointer glVertexPointer -#define qglViewport glViewport - -#endif diff --git a/code/renderer/qglextensions.h b/code/renderer/qglextensions.h deleted file mode 100644 index 575ab38c..00000000 --- a/code/renderer/qglextensions.h +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef __QGLEXTENSIONS_H__ -#define __QGLEXTENSIONS_H__ - -#define GL_EXT_framebuffer_object_functions \ - HANDLE_EXT_FUNC( PFNGLGENFRAMEBUFFERSEXTPROC, glGenFramebuffersEXT) \ - HANDLE_EXT_FUNC( PFNGLBINDFRAMEBUFFEREXTPROC, glBindFramebufferEXT) \ - HANDLE_EXT_FUNC( PFNGLFRAMEBUFFERTEXTURE2DEXTPROC, glFramebufferTexture2DEXT) \ - HANDLE_EXT_FUNC( PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC, glFramebufferRenderbufferEXT) \ - HANDLE_EXT_FUNC( PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC, glCheckFramebufferStatusEXT) \ - HANDLE_EXT_FUNC( PFNGLDELETEFRAMEBUFFERSEXTPROC, glDeleteFramebuffersEXT) \ - HANDLE_EXT_FUNC( PFNGLGENERATEMIPMAPEXTPROC, glGenerateMipmapEXT) \ - HANDLE_EXT_FUNC( PFNGLDELETERENDERBUFFERSEXTPROC, glDeleteRenderbuffersEXT) \ - HANDLE_EXT_FUNC( PFNGLGENRENDERBUFFERSEXTPROC, glGenRenderbuffersEXT) \ - HANDLE_EXT_FUNC( PFNGLRENDERBUFFERSTORAGEEXTPROC, glRenderbufferStorageEXT) \ - HANDLE_EXT_FUNC( PFNGLBINDRENDERBUFFEREXTPROC, glBindRenderbufferEXT) \ - -#define GL_ARB_occlusion_query_functions \ - HANDLE_EXT_FUNC( PFNGLGENQUERIESARBPROC, glGenQueriesARB) \ - HANDLE_EXT_FUNC( PFNGLDELETEQUERIESARBPROC, glDeleteQueriesARB) \ - HANDLE_EXT_FUNC( PFNGLISQUERYARBPROC, glIsQueryARB) \ - HANDLE_EXT_FUNC( PFNGLBEGINQUERYARBPROC, glBeginQueryARB) \ - HANDLE_EXT_FUNC( PFNGLENDQUERYARBPROC, glEndQueryARB) \ - HANDLE_EXT_FUNC( PFNGLGETQUERYIVARBPROC, glGetQueryivARB) \ - HANDLE_EXT_FUNC( PFNGLGETQUERYOBJECTIVARBPROC, glGetQueryObjectivARB) \ - HANDLE_EXT_FUNC( PFNGLGETQUERYOBJECTUIVARBPROC, glGetQueryObjectuivARB) \ - -#define GL_MISSING_FUNCTIONS \ - HANDLE_EXT_FUNC( PFNGLBLENDEQUATIONPROC, glBlendEquation) \ - -#define GL_ARB_color_buffer_float_functions \ - HANDLE_EXT_FUNC( PFNGLCLAMPCOLORARBPROC, glClampColorARB) \ - -#ifndef GL_EXT_framebuffer_multisample - #define GL_EXT_framebuffer_multisample 1 - #define GL_RENDERBUFFER_SAMPLES_EXT 0x8CAB - #define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x8D56 - #define GL_MAX_SAMPLES_EXT 0x8D57 - typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); -#endif - -#define GL_EXT_framebuffer_multisample_functions \ - HANDLE_EXT_FUNC(PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC, glRenderbufferStorageMultisampleEXT) \ - - - -#ifndef GL_EXT_framebuffer_blit - #define GL_EXT_framebuffer_blit 1 - #define GL_READ_FRAMEBUFFER_EXT 0x8CA8 - #define GL_DRAW_FRAMEBUFFER_EXT 0x8CA9 - #define GL_DRAW_FRAMEBUFFER_BINDING_EXT GL_FRAMEBUFFER_BINDING_EXT - #define GL_READ_FRAMEBUFFER_BINDING_EXT 0x8CAA - typedef void (APIENTRYP PFNGLBLITFRAMEBUFFEREXTPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); -#endif - -#define GL_EXT_framebuffer_blit_functions \ - HANDLE_EXT_FUNC(PFNGLBLITFRAMEBUFFEREXTPROC, glBlitFramebufferEXT) \ - - -#define ADD_ALL_EXTENSION_FUNCTIONS \ - GL_EXT_framebuffer_object_functions \ - GL_EXT_framebuffer_multisample_functions \ - GL_EXT_framebuffer_blit_functions \ - GL_ARB_occlusion_query_functions \ - GL_ARB_color_buffer_float_functions \ - GL_MISSING_FUNCTIONS \ - -#endif diff --git a/code/renderer/tr_extramath.c b/code/renderer/tr_extramath.c deleted file mode 100644 index 074e09f5..00000000 --- a/code/renderer/tr_extramath.c +++ /dev/null @@ -1,151 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2010 James Canete (use.less01@gmail.com) - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_extramath.c - extra math needed by the renderer not in qmath.c - -#include "tr_local.h" - -// Some matrix helper functions -// FIXME: do these already exist in ioq3 and I don't know about them? - -void Matrix16Zero( matrix_t out ) -{ - out[ 0] = 0.0f; out[ 4] = 0.0f; out[ 8] = 0.0f; out[12] = 0.0f; - out[ 1] = 0.0f; out[ 5] = 0.0f; out[ 9] = 0.0f; out[13] = 0.0f; - out[ 2] = 0.0f; out[ 6] = 0.0f; out[10] = 0.0f; out[14] = 0.0f; - out[ 3] = 0.0f; out[ 7] = 0.0f; out[11] = 0.0f; out[15] = 0.0f; -} - -void Matrix16Identity( matrix_t out ) -{ - out[ 0] = 1.0f; out[ 4] = 0.0f; out[ 8] = 0.0f; out[12] = 0.0f; - out[ 1] = 0.0f; out[ 5] = 1.0f; out[ 9] = 0.0f; out[13] = 0.0f; - out[ 2] = 0.0f; out[ 6] = 0.0f; out[10] = 1.0f; out[14] = 0.0f; - out[ 3] = 0.0f; out[ 7] = 0.0f; out[11] = 0.0f; out[15] = 1.0f; -} - -void Matrix16Copy( const matrix_t in, matrix_t out ) -{ - out[ 0] = in[ 0]; out[ 4] = in[ 4]; out[ 8] = in[ 8]; out[12] = in[12]; - out[ 1] = in[ 1]; out[ 5] = in[ 5]; out[ 9] = in[ 9]; out[13] = in[13]; - out[ 2] = in[ 2]; out[ 6] = in[ 6]; out[10] = in[10]; out[14] = in[14]; - out[ 3] = in[ 3]; out[ 7] = in[ 7]; out[11] = in[11]; out[15] = in[15]; -} - -void Matrix16Multiply( const matrix_t in1, const matrix_t in2, matrix_t out ) -{ - out[ 0] = in1[ 0] * in2[ 0] + in1[ 4] * in2[ 1] + in1[ 8] * in2[ 2] + in1[12] * in2[ 3]; - out[ 1] = in1[ 1] * in2[ 0] + in1[ 5] * in2[ 1] + in1[ 9] * in2[ 2] + in1[13] * in2[ 3]; - out[ 2] = in1[ 2] * in2[ 0] + in1[ 6] * in2[ 1] + in1[10] * in2[ 2] + in1[14] * in2[ 3]; - out[ 3] = in1[ 3] * in2[ 0] + in1[ 7] * in2[ 1] + in1[11] * in2[ 2] + in1[15] * in2[ 3]; - - out[ 4] = in1[ 0] * in2[ 4] + in1[ 4] * in2[ 5] + in1[ 8] * in2[ 6] + in1[12] * in2[ 7]; - out[ 5] = in1[ 1] * in2[ 4] + in1[ 5] * in2[ 5] + in1[ 9] * in2[ 6] + in1[13] * in2[ 7]; - out[ 6] = in1[ 2] * in2[ 4] + in1[ 6] * in2[ 5] + in1[10] * in2[ 6] + in1[14] * in2[ 7]; - out[ 7] = in1[ 3] * in2[ 4] + in1[ 7] * in2[ 5] + in1[11] * in2[ 6] + in1[15] * in2[ 7]; - - out[ 8] = in1[ 0] * in2[ 8] + in1[ 4] * in2[ 9] + in1[ 8] * in2[10] + in1[12] * in2[11]; - out[ 9] = in1[ 1] * in2[ 8] + in1[ 5] * in2[ 9] + in1[ 9] * in2[10] + in1[13] * in2[11]; - out[10] = in1[ 2] * in2[ 8] + in1[ 6] * in2[ 9] + in1[10] * in2[10] + in1[14] * in2[11]; - out[11] = in1[ 3] * in2[ 8] + in1[ 7] * in2[ 9] + in1[11] * in2[10] + in1[15] * in2[11]; - - out[12] = in1[ 0] * in2[12] + in1[ 4] * in2[13] + in1[ 8] * in2[14] + in1[12] * in2[15]; - out[13] = in1[ 1] * in2[12] + in1[ 5] * in2[13] + in1[ 9] * in2[14] + in1[13] * in2[15]; - out[14] = in1[ 2] * in2[12] + in1[ 6] * in2[13] + in1[10] * in2[14] + in1[14] * in2[15]; - out[15] = in1[ 3] * in2[12] + in1[ 7] * in2[13] + in1[11] * in2[14] + in1[15] * in2[15]; -} - -void Matrix16Transform( const matrix_t in1, const vec4_t in2, vec4_t out ) -{ - out[ 0] = in1[ 0] * in2[ 0] + in1[ 4] * in2[ 1] + in1[ 8] * in2[ 2] + in1[12] * in2[ 3]; - out[ 1] = in1[ 1] * in2[ 0] + in1[ 5] * in2[ 1] + in1[ 9] * in2[ 2] + in1[13] * in2[ 3]; - out[ 2] = in1[ 2] * in2[ 0] + in1[ 6] * in2[ 1] + in1[10] * in2[ 2] + in1[14] * in2[ 3]; - out[ 3] = in1[ 3] * in2[ 0] + in1[ 7] * in2[ 1] + in1[11] * in2[ 2] + in1[15] * in2[ 3]; -} - -qboolean Matrix16Compare( const matrix_t a, const matrix_t b ) -{ - return !(a[ 0] != b[ 0] || a[ 4] != b[ 4] || a[ 8] != b[ 8] || a[12] != b[12] || - a[ 1] != b[ 1] || a[ 5] != b[ 5] || a[ 9] != b[ 9] || a[13] != b[13] || - a[ 2] != b[ 2] || a[ 6] != b[ 6] || a[10] != b[10] || a[14] != b[14] || - a[ 3] != b[ 3] || a[ 7] != b[ 7] || a[11] != b[11] || a[15] != b[15]); -} - -void Matrix16Dump( const matrix_t in ) -{ - ri.Printf(PRINT_ALL, "%3.5f %3.5f %3.5f %3.5f\n", in[ 0], in[ 4], in[ 8], in[12]); - ri.Printf(PRINT_ALL, "%3.5f %3.5f %3.5f %3.5f\n", in[ 1], in[ 5], in[ 9], in[13]); - ri.Printf(PRINT_ALL, "%3.5f %3.5f %3.5f %3.5f\n", in[ 2], in[ 6], in[10], in[14]); - ri.Printf(PRINT_ALL, "%3.5f %3.5f %3.5f %3.5f\n", in[ 3], in[ 7], in[11], in[15]); -} - -void Matrix16Translation( vec3_t vec, matrix_t out ) -{ - out[ 0] = 1.0f; out[ 4] = 0.0f; out[ 8] = 0.0f; out[12] = vec[0]; - out[ 1] = 0.0f; out[ 5] = 1.0f; out[ 9] = 0.0f; out[13] = vec[1]; - out[ 2] = 0.0f; out[ 6] = 0.0f; out[10] = 1.0f; out[14] = vec[2]; - out[ 3] = 0.0f; out[ 7] = 0.0f; out[11] = 0.0f; out[15] = 1.0f; -} - -void Matrix16Ortho( float left, float right, float bottom, float top, float znear, float zfar, matrix_t out ) -{ - Matrix16Zero(out); - out[ 0] = 2.0f / (right - left); - out[ 5] = 2.0f / (top - bottom); - out[10] = 2.0f / (zfar - znear); - out[12] = -(right + left) / (right - left); - out[13] = -(top + bottom) / (top - bottom); - out[14] = -(zfar + znear) / (zfar - znear); - out[15] = 1.0f; -} - -void VectorLerp( vec3_t a, vec3_t b, float lerp, vec3_t c) -{ - c[0] = a[0] * (1.0f - lerp) + b[0] * lerp; - c[1] = a[1] * (1.0f - lerp) + b[1] * lerp; - c[2] = a[2] * (1.0f - lerp) + b[2] * lerp; -} - -qboolean SpheresIntersect(vec3_t origin1, float radius1, vec3_t origin2, float radius2) -{ - float radiusSum = radius1 + radius2; - vec3_t diff; - - VectorSubtract(origin1, origin2, diff); - - if (DotProduct(diff, diff) <= radiusSum * radiusSum) - { - return qtrue; - } - - return qfalse; -} - -void BoundingSphereOfSpheres(vec3_t origin1, float radius1, vec3_t origin2, float radius2, vec3_t origin3, float *radius3) -{ - vec3_t diff; - - VectorScale(origin1, 0.5f, origin3); - VectorMA(origin3, 0.5f, origin2, origin3); - - VectorSubtract(origin1, origin2, diff); - *radius3 = VectorLength(diff) * 0.5 + MAX(radius1, radius2); -} diff --git a/code/renderer/tr_extramath.h b/code/renderer/tr_extramath.h deleted file mode 100644 index ef591363..00000000 --- a/code/renderer/tr_extramath.h +++ /dev/null @@ -1,74 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2010 James Canete (use.less01@gmail.com) - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_extramath.h - -#ifndef __TR_EXTRAMATH_H__ -#define __TR_EXTRAMATH_H__ - -typedef vec_t matrix_t[16]; - -void Matrix16Zero( matrix_t out ); -void Matrix16Identity( matrix_t out ); -void Matrix16Copy( const matrix_t in, matrix_t out ); -void Matrix16Multiply( const matrix_t in1, const matrix_t in2, matrix_t out ); -void Matrix16Transform( const matrix_t in1, const vec4_t in2, vec4_t out ); -qboolean Matrix16Compare(const matrix_t a, const matrix_t b); -void Matrix16Dump( const matrix_t in ); -void Matrix16Translation( vec3_t vec, matrix_t out ); -void Matrix16Ortho( float left, float right, float bottom, float top, float znear, float zfar, matrix_t out ); - -#define VectorCopy4(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3]) -#define VectorSet4(v,x,y,z,w) ((v)[0]=(x),(v)[1]=(y),(v)[2]=(z),(v)[3]=(w)) -#define DotProduct4(a,b) ((a)[0]*(b)[0] + (a)[1]*(b)[1] + (a)[2]*(b)[2] + (a)[3]*(b)[3]) -#define VectorScale4(a,b,c) ((c)[0]=(a)[0]*(b),(c)[1]=(a)[1]*(b),(c)[2]=(a)[2]*(b),(c)[3]=(a)[3]*(b)) - -#define VectorCopy5(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3],(b)[4]=(a)[4]) - -static ID_INLINE int VectorCompare4(const vec4_t v1, const vec4_t v2) -{ - if(v1[0] != v2[0] || v1[1] != v2[1] || v1[2] != v2[2] || v1[3] != v2[3]) - { - return 0; - } - return 1; -} - -static ID_INLINE int VectorCompare5(const vec5_t v1, const vec5_t v2) -{ - if(v1[0] != v2[0] || v1[1] != v2[1] || v1[2] != v2[2] || v1[3] != v2[3] || v1[4] != v2[4]) - { - return 0; - } - return 1; -} - -void VectorLerp( vec3_t a, vec3_t b, float lerp, vec3_t c); - - -qboolean SpheresIntersect(vec3_t origin1, float radius1, vec3_t origin2, float radius2); -void BoundingSphereOfSpheres(vec3_t origin1, float radius1, vec3_t origin2, float radius2, vec3_t origin3, float *radius3); - -#ifndef SGN -#define SGN(x) (((x) >= 0) ? !!(x) : -1) -#endif - -#endif diff --git a/code/renderer/tr_fbo.c b/code/renderer/tr_fbo.c deleted file mode 100644 index 188f8954..00000000 --- a/code/renderer/tr_fbo.c +++ /dev/null @@ -1,499 +0,0 @@ -#include "tr_local.h" - -#define MAX_FBO_COLOR_BUFFERS 8 - -/* -=============== -Render buffer -Can be either a zbuffer, a stencil buffer or a multisampled color buffer -=============== -*/ - -struct fboRenderBuffer_s { - GLuint id; - int internalFormat; - - int width; - int height; - qboolean msaa; -}; - -typedef fboRenderBuffer_t fboZBuffer_t; -typedef fboRenderBuffer_t fboStencilBuffer_t; - -/* -=============== -Color buffer - -If anti-aliased we'll have a texture, a render buffer -and two frame buffers needed for the MSAA resolve. - -Otherwise, only the texture is initialized. -=============== -*/ - -struct fboColorBuffer_s { - fboRenderBuffer_t *buf; - image_t *tex; - GLuint fboResolve[2]; - qboolean dirty; -}; - -/* -=============== -Frame buffer - -Has one or more color buffers, an optional zbuffer -and an optional stencil buffer -=============== -*/ - -struct fbo_s { - GLuint id; - - int numColorBufs; - - fboColorBuffer_t* color[MAX_FBO_COLOR_BUFFERS]; - fboZBuffer_t* depth; - fboStencilBuffer_t* stencil; - - char name[MAX_QPATH]; -}; - - -qboolean R_FBO_CheckStatus(void) -{ - GLenum status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - const char* msg = "unknown error"; - - switch (status) - { - case GL_FRAMEBUFFER_COMPLETE_EXT: - return qtrue; - - case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: - msg = "incomplete attachment"; - break; - - case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: - msg = "missing attachment"; - break; - - //case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT: - // msg = "duplicate attachment"; - // break; - - case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: - msg = "mismatched dimensions"; - break; - - case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: - msg = "mismatched formats"; - break; - - case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: - msg = "incomplete draw buffer"; - break; - - case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: - msg = "incomplete read buffer"; - break; - - case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT: - msg = "mismatched multisample settings"; - break; - - case GL_FRAMEBUFFER_UNSUPPORTED_EXT: - msg = "unsupported"; - break; - - default: - msg = va("0x%x", status); - break; - } - - ri.Error(ERR_FATAL, "Framebuffer setup error: %s\n", msg); - - return qfalse; -} - -void R_FBO_InitRenderBuffer(fboRenderBuffer_t* buf) -{ - buf->id = 0; - qglGenRenderbuffersEXT(1, &buf->id); - qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, buf->id); - if (buf->msaa) - { - qglRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, tr.fbo.samples, buf->internalFormat, buf->width, buf->height); - } - else - { - qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, buf->internalFormat, buf->width, buf->height); - } - qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); -} - -void R_FBO_ReleaseRenderBuffer(fboRenderBuffer_t* buf) -{ - if (buf->id == 0) - return; - - qglDeleteRenderbuffersEXT(1, &buf->id); - buf->id = 0; -} - -fboRenderBuffer_t *R_FBO_CreateRenderBuffer(int width, int height, int pixelformat, qboolean msaa) -{ - fboRenderBuffer_t* ret = NULL; - if (tr.fbo.numRenderBuffers >= ARRAY_SIZE(tr.fbo.renderBuffers)) - { - ri.Error(ERR_FATAL, "Too many FBO render buffers\n"); - return NULL; - } - - ret = ri.Hunk_Alloc(sizeof(*ret), h_low); - memset(ret, 0, sizeof(*ret)); - - ret->width = width; - ret->height = height; - ret->internalFormat = pixelformat; - ret->msaa = (msaa && tr.fbo.samples > 1); - - R_FBO_InitRenderBuffer(ret); - - tr.fbo.renderBuffers[tr.fbo.numRenderBuffers++] = ret; - - return ret; -} - -fboColorBuffer_t *R_FBO_CreateColorBuffer(const char* name, int width, int height, qboolean msaa, qboolean mipmap, int clamp) -{ - if (tr.fbo.numColorBuffers>= ARRAY_SIZE(tr.fbo.colorBuffers)) - { - ri.Error(ERR_FATAL, "Too many FBO color buffers\n"); - return NULL; - } - else - { - qboolean realmsaa = msaa && tr.fbo.samples > 1; - image_t *texture = R_CreateRenderTarget(name, width, height, mipmap, clamp); - fboRenderBuffer_t *buf = realmsaa ? R_FBO_CreateRenderBuffer(width, height, texture->internalFormat, qtrue) : NULL; - fboColorBuffer_t *ret = ri.Hunk_Alloc(sizeof(*ret), h_low); - - Com_Memset(ret, 0, sizeof(*ret)); - - ret->buf = buf; - ret->tex = texture; - ret->dirty = qfalse; - - if (realmsaa) - { - qglGenFramebuffersEXT(2, ret->fboResolve); - - qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ret->fboResolve[0]); - qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, ret->buf->id); - R_FBO_CheckStatus(); - - qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ret->fboResolve[1]); - qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, ret->tex->texnum, 0); - R_FBO_CheckStatus(); - - qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - } - else - { - ret->fboResolve[0] = ret->fboResolve[1] = 0; - } - - tr.fbo.colorBuffers[tr.fbo.numColorBuffers++] = ret; - - return ret; - } -} - -void R_FBO_ReleaseColorBuffer(fboColorBuffer_t* color) -{ - if (color->buf) - { - qglDeleteFramebuffersEXT(2, color->fboResolve); - } -} - -fboZBuffer_t *R_FBO_CreateZBuffer(int width, int height, qboolean msaa) -{ - return R_FBO_CreateRenderBuffer(width, height, GL_DEPTH_COMPONENT24, msaa); -} - -void R_FBO_Init(fbo_t* fbo) -{ - memset(fbo, 0, sizeof(*fbo)); - qglGenFramebuffersEXT(1, &fbo->id); -} - -void R_FBO_Release(fbo_t* fbo) -{ - if (fbo->id == 0) - return; - - qglDeleteFramebuffersEXT(1, &fbo->id); - fbo->id = 0; -} - -void R_FBO_AddColorBuffer(fbo_t* fbo, fboColorBuffer_t* color) -{ - GLenum attach; - if (fbo->numColorBufs >= ARRAY_SIZE(fbo->color)) - { - ri.Error(ERR_FATAL, "Max FBO color buffers exceeded.\n"); - return; - } - fbo->color[fbo->numColorBufs++] = color; - - qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->id); - attach = GL_COLOR_ATTACHMENT0_EXT + fbo->numColorBufs - 1; - if (color->buf) - { - qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, attach, GL_RENDERBUFFER_EXT, color->buf->id); - } - else - { - qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attach, GL_TEXTURE_2D, color->tex->texnum, 0); - } -} - -/* -=============== -R_FBO_Bind -=============== -*/ - -fbo_t* R_FBO_Bind(fbo_t* fbo) -{ - fbo_t* old = glState.currentFBO; - GLuint id = 0; - if (!glRefConfig.framebufferObject) - { - glState.currentFBO = NULL; - return NULL; - } - - if (old == fbo) - return old; - - glState.currentFBO = fbo; - if (fbo) - id = fbo->id; - - qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, id); - - if (fbo) - { - int i; - for (i=0; inumColorBufs; ++i) - { - fboColorBuffer_t* color = fbo->color[i]; - color->dirty = (color->buf != NULL); - } - - if (1) - R_FBO_CheckStatus(); - } - - return old; -} - -/* -=============== -R_FBO_BindColorBuffer -=============== -*/ - -void R_FBO_BindColorBuffer(fbo_t* fbo, int index) -{ - fboColorBuffer_t* color = fbo->color[index]; - if (color->dirty) - { - color->dirty = qfalse; - - // resolve - if (color->buf) - { - int id; - int width = color->buf->width; - int height = color->buf->height; - - qglBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, color->fboResolve[0]); - qglBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, color->fboResolve[1]); - qglBlitFramebufferEXT(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_LINEAR); - - if (glState.currentFBO) - id = glState.currentFBO->id; - else - id = 0; - - qglBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, id); - qglBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, id); - } - } - GL_Bind(color->tex); -} - -/* -=============== -R_FBO_CreateEx -=============== -*/ - -fbo_t* R_FBO_CreateEx(const char* name, int numColorBuffers, fboColorBuffer_t** colorBuffers, fboZBuffer_t* depth, fboStencilBuffer_t* stencil) -{ - fbo_t* fbo = NULL; - - if (tr.fbo.numFBOs >= ARRAY_SIZE(tr.fbo.fbos)) - { - ri.Error(ERR_FATAL, "Too many FBO's\n"); - return NULL; - } - - ri.Printf(PRINT_DEVELOPER, "Creating FBO %s: %d color/%d depth/%d stencil\n", name, numColorBuffers, depth != NULL, stencil != NULL); - - fbo = ri.Hunk_Alloc(sizeof(*fbo), h_low); - - R_FBO_Init(fbo); - - Q_strncpyz(fbo->name, name, ARRAY_SIZE(fbo->name)); - - while (numColorBuffers-- > 0) - R_FBO_AddColorBuffer(fbo, *colorBuffers++); - - fbo->depth = depth; - fbo->stencil = stencil; - - qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->id); - - if (fbo->depth) - qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbo->depth->id); - - if (fbo->stencil) - qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbo->stencil->id); - - qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); - - tr.fbo.fbos[tr.fbo.numFBOs++] = fbo; - - return fbo; -} - -fbo_t* R_FBO_CreateSimple(const char* name, fboColorBuffer_t* color, fboZBuffer_t* depth, fboStencilBuffer_t* stencil) -{ - return R_FBO_CreateEx(name, color != NULL, &color, depth, stencil); -} - -/* -=============== -R_FBO_CreateDefaultBuffers -=============== -*/ - -static void R_FBO_CreateDefaultBuffers(void) -{ - qboolean msaa = tr.fbo.samples > 1; - - tr.fbo.full[0] = R_FBO_CreateSimple( - "main", - R_FBO_CreateColorBuffer("*framebuffer0", glConfig.vidWidth, glConfig.vidHeight, msaa, qfalse, GL_CLAMP_TO_EDGE), - R_FBO_CreateZBuffer(glConfig.vidWidth, glConfig.vidHeight, msaa), - NULL); - - tr.fbo.full[1] = R_FBO_CreateSimple( - "postprocess", - R_FBO_CreateColorBuffer("*framebuffer1", glConfig.vidWidth, glConfig.vidHeight, msaa, qfalse, GL_CLAMP_TO_EDGE), - tr.fbo.full[0]->depth, - NULL); - - tr.fbo.quarter[0] = R_FBO_CreateSimple( - "quarter0", - R_FBO_CreateColorBuffer("*quarterBuffer0", glConfig.vidWidth/2, glConfig.vidHeight/2, qfalse, qfalse, GL_CLAMP_TO_EDGE), - NULL, - NULL); - - tr.fbo.quarter[1] = R_FBO_CreateSimple( - "quarter1", - R_FBO_CreateColorBuffer("*quarterBuffer1", glConfig.vidWidth/2, glConfig.vidHeight/2, qfalse, qfalse, GL_CLAMP_TO_EDGE), - NULL, - NULL); - - tr.fbo.tiny[0] = R_FBO_CreateSimple( - "tiny0", - R_FBO_CreateColorBuffer("*tinyBuffer0", glConfig.vidWidth/4, glConfig.vidHeight/4, qfalse, qfalse, GL_CLAMP_TO_EDGE), - NULL, - NULL); - - tr.fbo.tiny[1] = R_FBO_CreateSimple( - "tiny1", - R_FBO_CreateColorBuffer("*tinyBuffer1", glConfig.vidWidth/4, glConfig.vidHeight/4, qfalse, qfalse, GL_CLAMP_TO_EDGE), - NULL, - NULL); - - ri.Printf(PRINT_DEVELOPER, "...created %d FBOs\n", tr.fbo.numFBOs); -} - -/* -=============== -R_InitFBOs -=============== -*/ - -void R_InitFBOs(void) -{ - GLint maxSamples = 0; - if (!glRefConfig.framebufferObject) - return; - - ri.Printf(PRINT_ALL, "------- R_InitFBOs -------\n"); - - if (glRefConfig.framebufferMultisample && glRefConfig.framebufferBlit) - { - qglGetIntegerv(GL_MAX_SAMPLES_EXT, &maxSamples); - tr.fbo.samples = maxSamples < r_ext_multisample->integer ? maxSamples : r_ext_multisample->integer; - if (tr.fbo.samples < 2) - tr.fbo.samples = 0; - } - else - { - tr.fbo.samples = 0; - } - - if (tr.fbo.samples > 1) - ri.Printf(PRINT_ALL, "MSAA enabled with %d samples (max %d)\n", tr.fbo.samples, maxSamples); - - R_FBO_CreateDefaultBuffers(); - - R_FBO_Bind(tr.fbo.full[0]); -} - - -/* -=============== -R_ShutDownFBOs -=============== -*/ - -void R_ShutDownFBOs(void) -{ - if (!glRefConfig.framebufferObject) - return; - - ri.Printf(PRINT_ALL, "------- R_ShutdownFBOs -------\n"); - - R_FBO_Bind(NULL); - - while (tr.fbo.numRenderBuffers>0) - R_FBO_ReleaseRenderBuffer(tr.fbo.renderBuffers[--tr.fbo.numRenderBuffers]); - - while (tr.fbo.numColorBuffers>0) - R_FBO_ReleaseColorBuffer(tr.fbo.colorBuffers[--tr.fbo.numColorBuffers]); - - while (tr.fbo.numFBOs>0) - R_FBO_Release(tr.fbo.fbos[--tr.fbo.numFBOs]); -} - diff --git a/code/renderer/tr_font.c b/code/renderer/tr_font.c deleted file mode 100644 index 87465e52..00000000 --- a/code/renderer/tr_font.c +++ /dev/null @@ -1,555 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_font.c -// -// -// The font system uses FreeType 2.x to render TrueType fonts for use within the game. -// As of this writing ( Nov, 2000 ) Team Arena uses these fonts for all of the ui and -// about 90% of the cgame presentation. A few areas of the CGAME were left uses the old -// fonts since the code is shared with standard Q3A. -// -// If you include this font rendering code in a commercial product you MUST include the -// following somewhere with your product, see www.freetype.org for specifics or changes. -// The Freetype code also uses some hinting techniques that MIGHT infringe on patents -// held by apple so be aware of that also. -// -// As of Q3A 1.25+ and Team Arena, we are shipping the game with the font rendering code -// disabled. This removes any potential patent issues and it keeps us from having to -// distribute an actual TrueTrype font which is 1. expensive to do and 2. seems to require -// an act of god to accomplish. -// -// What we did was pre-render the fonts using FreeType ( which is why we leave the FreeType -// credit in the credits ) and then saved off the glyph data and then hand touched up the -// font bitmaps so they scale a bit better in GL. -// -// There are limitations in the way fonts are saved and reloaded in that it is based on -// point size and not name. So if you pre-render Helvetica in 18 point and Impact in 18 point -// you will end up with a single 18 point data file and image set. Typically you will want to -// choose 3 sizes to best approximate the scaling you will be doing in the ui scripting system -// -// In the UI Scripting code, a scale of 1.0 is equal to a 48 point font. In Team Arena, we -// use three or four scales, most of them exactly equaling the specific rendered size. We -// rendered three sizes in Team Arena, 12, 16, and 20. -// -// To generate new font data you need to go through the following steps. -// 1. delete the fontImage_x_xx.tga files and fontImage_xx.dat files from the fonts path. -// 2. in a ui script, specificy a font, smallFont, and bigFont keyword with font name and -// point size. the original TrueType fonts must exist in fonts at this point. -// 3. run the game, you should see things normally. -// 4. Exit the game and there will be three dat files and at least three tga files. The -// tga's are in 256x256 pages so if it takes three images to render a 24 point font you -// will end up with fontImage_0_24.tga through fontImage_2_24.tga -// 5. In future runs of the game, the system looks for these images and data files when a s -// specific point sized font is rendered and loads them for use. -// 6. Because of the original beta nature of the FreeType code you will probably want to hand -// touch the font bitmaps. -// -// Currently a define in the project turns on or off the FreeType code which is currently -// defined out. To pre-render new fonts you need enable the define ( BUILD_FREETYPE ) and -// uncheck the exclude from build check box in the FreeType2 area of the Renderer project. - - -#include "tr_local.h" -#include "../qcommon/qcommon.h" - -#ifdef BUILD_FREETYPE -#include -#include FT_ERRORS_H -#include FT_SYSTEM_H -#include FT_IMAGE_H -#include FT_FREETYPE_H -#include FT_OUTLINE_H - -#define _FLOOR(x) ((x) & -64) -#define _CEIL(x) (((x)+63) & -64) -#define _TRUNC(x) ((x) >> 6) - -FT_Library ftLibrary = NULL; -#endif - -#define MAX_FONTS 6 -static int registeredFontCount = 0; -static fontInfo_t registeredFont[MAX_FONTS]; - -#ifdef BUILD_FREETYPE -void R_GetGlyphInfo(FT_GlyphSlot glyph, int *left, int *right, int *width, int *top, int *bottom, int *height, int *pitch) { - *left = _FLOOR( glyph->metrics.horiBearingX ); - *right = _CEIL( glyph->metrics.horiBearingX + glyph->metrics.width ); - *width = _TRUNC(*right - *left); - - *top = _CEIL( glyph->metrics.horiBearingY ); - *bottom = _FLOOR( glyph->metrics.horiBearingY - glyph->metrics.height ); - *height = _TRUNC( *top - *bottom ); - *pitch = ( qtrue ? (*width+3) & -4 : (*width+7) >> 3 ); -} - - -FT_Bitmap *R_RenderGlyph(FT_GlyphSlot glyph, glyphInfo_t* glyphOut) { - FT_Bitmap *bit2; - int left, right, width, top, bottom, height, pitch, size; - - R_GetGlyphInfo(glyph, &left, &right, &width, &top, &bottom, &height, &pitch); - - if ( glyph->format == ft_glyph_format_outline ) { - size = pitch*height; - - bit2 = ri.Malloc(sizeof(FT_Bitmap)); - - bit2->width = width; - bit2->rows = height; - bit2->pitch = pitch; - bit2->pixel_mode = ft_pixel_mode_grays; - //bit2->pixel_mode = ft_pixel_mode_mono; - bit2->buffer = ri.Malloc(pitch*height); - bit2->num_grays = 256; - - Com_Memset( bit2->buffer, 0, size ); - - FT_Outline_Translate( &glyph->outline, -left, -bottom ); - - FT_Outline_Get_Bitmap( ftLibrary, &glyph->outline, bit2 ); - - glyphOut->height = height; - glyphOut->pitch = pitch; - glyphOut->top = (glyph->metrics.horiBearingY >> 6) + 1; - glyphOut->bottom = bottom; - - return bit2; - } else { - ri.Printf(PRINT_ALL, "Non-outline fonts are not supported\n"); - } - return NULL; -} - -void WriteTGA (char *filename, byte *data, int width, int height) { - byte *buffer; - int i, c; - int row; - unsigned char *flip; - unsigned char *src, *dst; - - buffer = ri.Malloc(width*height*4 + 18); - Com_Memset (buffer, 0, 18); - buffer[2] = 2; // uncompressed type - buffer[12] = width&255; - buffer[13] = width>>8; - buffer[14] = height&255; - buffer[15] = height>>8; - buffer[16] = 32; // pixel size - - // swap rgb to bgr - c = 18 + width * height * 4; - for (i=18 ; iglyph, &glyph); - if (bitmap) { - glyph.xSkip = (face->glyph->metrics.horiAdvance >> 6) + 1; - } else { - return &glyph; - } - - if (glyph.height > *maxHeight) { - *maxHeight = glyph.height; - } - - if (calcHeight) { - ri.Free(bitmap->buffer); - ri.Free(bitmap); - return &glyph; - } - -/* - // need to convert to power of 2 sizes so we do not get - // any scaling from the gl upload - for (scaled_width = 1 ; scaled_width < glyph.pitch ; scaled_width<<=1) - ; - for (scaled_height = 1 ; scaled_height < glyph.height ; scaled_height<<=1) - ; -*/ - - scaled_width = glyph.pitch; - scaled_height = glyph.height; - - // we need to make sure we fit - if (*xOut + scaled_width + 1 >= 255) { - *xOut = 0; - *yOut += *maxHeight + 1; - } - - if (*yOut + *maxHeight + 1 >= 255) { - *yOut = -1; - *xOut = -1; - ri.Free(bitmap->buffer); - ri.Free(bitmap); - return &glyph; - } - - - src = bitmap->buffer; - dst = imageOut + (*yOut * 256) + *xOut; - - if (bitmap->pixel_mode == ft_pixel_mode_mono) { - for (i = 0; i < glyph.height; i++) { - int j; - unsigned char *_src = src; - unsigned char *_dst = dst; - unsigned char mask = 0x80; - unsigned char val = *_src; - for (j = 0; j < glyph.pitch; j++) { - if (mask == 0x80) { - val = *_src++; - } - if (val & mask) { - *_dst = 0xff; - } - mask >>= 1; - - if ( mask == 0 ) { - mask = 0x80; - } - _dst++; - } - - src += glyph.pitch; - dst += 256; - } - } else { - for (i = 0; i < glyph.height; i++) { - Com_Memcpy(dst, src, glyph.pitch); - src += glyph.pitch; - dst += 256; - } - } - - // we now have an 8 bit per pixel grey scale bitmap - // that is width wide and pf->ftSize->metrics.y_ppem tall - - glyph.imageHeight = scaled_height; - glyph.imageWidth = scaled_width; - glyph.s = (float)*xOut / 256; - glyph.t = (float)*yOut / 256; - glyph.s2 = glyph.s + (float)scaled_width / 256; - glyph.t2 = glyph.t + (float)scaled_height / 256; - - *xOut += scaled_width + 1; - - ri.Free(bitmap->buffer); - ri.Free(bitmap); - } - - return &glyph; -} -#endif - -static int fdOffset; -static byte *fdFile; - -int readInt( void ) { - int i = fdFile[fdOffset]+(fdFile[fdOffset+1]<<8)+(fdFile[fdOffset+2]<<16)+(fdFile[fdOffset+3]<<24); - fdOffset += 4; - return i; -} - -typedef union { - byte fred[4]; - float ffred; -} poor; - -float readFloat( void ) { - poor me; -#if defined Q3_BIG_ENDIAN - me.fred[0] = fdFile[fdOffset+3]; - me.fred[1] = fdFile[fdOffset+2]; - me.fred[2] = fdFile[fdOffset+1]; - me.fred[3] = fdFile[fdOffset+0]; -#elif defined Q3_LITTLE_ENDIAN - me.fred[0] = fdFile[fdOffset+0]; - me.fred[1] = fdFile[fdOffset+1]; - me.fred[2] = fdFile[fdOffset+2]; - me.fred[3] = fdFile[fdOffset+3]; -#endif - fdOffset += 4; - return me.ffred; -} - -void RE_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font) { -#ifdef BUILD_FREETYPE - FT_Face face; - int j, k, xOut, yOut, lastStart, imageNumber; - int scaledSize, newSize, maxHeight, left; - unsigned char *out, *imageBuff; - glyphInfo_t *glyph; - image_t *image; - qhandle_t h; - float max; - float dpi = 72; - float glyphScale; -#endif - void *faceData; - int i, len; - char name[1024]; - - if (!fontName) { - ri.Printf(PRINT_ALL, "RE_RegisterFont: called with empty name\n"); - return; - } - - if (pointSize <= 0) { - pointSize = 12; - } - - // make sure the render thread is stopped - R_SyncRenderThread(); - - if (registeredFontCount >= MAX_FONTS) { - ri.Printf(PRINT_WARNING, "RE_RegisterFont: Too many fonts registered already.\n"); - return; - } - - Com_sprintf(name, sizeof(name), "fonts/fontImage_%i.dat",pointSize); - for (i = 0; i < registeredFontCount; i++) { - if (Q_stricmp(name, registeredFont[i].name) == 0) { - Com_Memcpy(font, ®isteredFont[i], sizeof(fontInfo_t)); - return; - } - } - - len = ri.FS_ReadFile(name, NULL); - if (len == sizeof(fontInfo_t)) { - ri.FS_ReadFile(name, &faceData); - fdOffset = 0; - fdFile = faceData; - for(i=0; iglyphs[i].height = readInt(); - font->glyphs[i].top = readInt(); - font->glyphs[i].bottom = readInt(); - font->glyphs[i].pitch = readInt(); - font->glyphs[i].xSkip = readInt(); - font->glyphs[i].imageWidth = readInt(); - font->glyphs[i].imageHeight = readInt(); - font->glyphs[i].s = readFloat(); - font->glyphs[i].t = readFloat(); - font->glyphs[i].s2 = readFloat(); - font->glyphs[i].t2 = readFloat(); - font->glyphs[i].glyph = readInt(); - Q_strncpyz(font->glyphs[i].shaderName, (const char *)&fdFile[fdOffset], sizeof(font->glyphs[i].shaderName)); - fdOffset += sizeof(font->glyphs[i].shaderName); - } - font->glyphScale = readFloat(); - Com_Memcpy(font->name, &fdFile[fdOffset], MAX_QPATH); - -// Com_Memcpy(font, faceData, sizeof(fontInfo_t)); - Q_strncpyz(font->name, name, sizeof(font->name)); - for (i = GLYPH_START; i < GLYPH_END; i++) { - font->glyphs[i].glyph = RE_RegisterShaderNoMip(font->glyphs[i].shaderName); - } - Com_Memcpy(®isteredFont[registeredFontCount++], font, sizeof(fontInfo_t)); - return; - } - -#ifndef BUILD_FREETYPE - ri.Printf(PRINT_WARNING, "RE_RegisterFont: FreeType code not available\n"); -#else - if (ftLibrary == NULL) { - ri.Printf(PRINT_WARNING, "RE_RegisterFont: FreeType not initialized.\n"); - return; - } - - len = ri.FS_ReadFile(fontName, &faceData); - if (len <= 0) { - ri.Printf(PRINT_WARNING, "RE_RegisterFont: Unable to read font file '%s'\n", fontName); - return; - } - - // allocate on the stack first in case we fail - if (FT_New_Memory_Face( ftLibrary, faceData, len, 0, &face )) { - ri.Printf(PRINT_WARNING, "RE_RegisterFont: FreeType, unable to allocate new face.\n"); - return; - } - - - if (FT_Set_Char_Size( face, pointSize << 6, pointSize << 6, dpi, dpi)) { - ri.Printf(PRINT_WARNING, "RE_RegisterFont: FreeType, unable to set face char size.\n"); - return; - } - - //*font = ®isteredFonts[registeredFontCount++]; - - // make a 256x256 image buffer, once it is full, register it, clean it and keep going - // until all glyphs are rendered - - out = ri.Malloc(1024*1024); - if (out == NULL) { - ri.Printf(PRINT_WARNING, "RE_RegisterFont: ri.Malloc failure during output image creation.\n"); - return; - } - Com_Memset(out, 0, 1024*1024); - - maxHeight = 0; - - for (i = GLYPH_START; i < GLYPH_END; i++) { - RE_ConstructGlyphInfo(out, &xOut, &yOut, &maxHeight, face, (unsigned char)i, qtrue); - } - - xOut = 0; - yOut = 0; - i = GLYPH_START; - lastStart = i; - imageNumber = 0; - - while ( i <= GLYPH_END ) { - - glyph = RE_ConstructGlyphInfo(out, &xOut, &yOut, &maxHeight, face, (unsigned char)i, qfalse); - - if (xOut == -1 || yOut == -1 || i == GLYPH_END) { - // ran out of room - // we need to create an image from the bitmap, set all the handles in the glyphs to this point - // - - scaledSize = 256*256; - newSize = scaledSize * 4; - imageBuff = ri.Malloc(newSize); - left = 0; - max = 0; - for ( k = 0; k < (scaledSize) ; k++ ) { - if (max < out[k]) { - max = out[k]; - } - } - - if (max > 0) { - max = 255/max; - } - - for ( k = 0; k < (scaledSize) ; k++ ) { - imageBuff[left++] = 255; - imageBuff[left++] = 255; - imageBuff[left++] = 255; - - imageBuff[left++] = ((float)out[k] * max); - } - - Com_sprintf (name, sizeof(name), "fonts/fontImage_%i_%i.tga", imageNumber++, pointSize); - if (r_saveFontData->integer) { - WriteTGA(name, imageBuff, 256, 256); - } - - //Com_sprintf (name, sizeof(name), "fonts/fontImage_%i_%i", imageNumber++, pointSize); - image = R_CreateImage(name, imageBuff, 256, 256, qfalse, qfalse, GL_CLAMP_TO_EDGE); - h = RE_RegisterShaderFromImage(name, LIGHTMAP_2D, image, qfalse); - for (j = lastStart; j < i; j++) { - font->glyphs[j].glyph = h; - Q_strncpyz(font->glyphs[j].shaderName, name, sizeof(font->glyphs[j].shaderName)); - } - lastStart = i; - Com_Memset(out, 0, 1024*1024); - xOut = 0; - yOut = 0; - ri.Free(imageBuff); - i++; - } else { - Com_Memcpy(&font->glyphs[i], glyph, sizeof(glyphInfo_t)); - i++; - } - } - - // change the scale to be relative to 1 based on 72 dpi ( so dpi of 144 means a scale of .5 ) - glyphScale = 72.0f / dpi; - - // we also need to adjust the scale based on point size relative to 48 points as the ui scaling is based on a 48 point font - glyphScale *= 48.0f / pointSize; - - registeredFont[registeredFontCount].glyphScale = glyphScale; - font->glyphScale = glyphScale; - Com_Memcpy(®isteredFont[registeredFontCount++], font, sizeof(fontInfo_t)); - - if (r_saveFontData->integer) { - ri.FS_WriteFile(va("fonts/fontImage_%i.dat", pointSize), font, sizeof(fontInfo_t)); - } - - ri.Free(out); - - ri.FS_FreeFile(faceData); -#endif -} - - - -void R_InitFreeType(void) { -#ifdef BUILD_FREETYPE - if (FT_Init_FreeType( &ftLibrary )) { - ri.Printf(PRINT_WARNING, "R_InitFreeType: Unable to initialize FreeType.\n"); - } -#endif - registeredFontCount = 0; -} - - -void R_DoneFreeType(void) { -#ifdef BUILD_FREETYPE - if (ftLibrary) { - FT_Done_FreeType( ftLibrary ); - ftLibrary = NULL; - } -#endif - registeredFontCount = 0; -} - diff --git a/code/renderer/tr_glsl.c b/code/renderer/tr_glsl.c deleted file mode 100644 index b7d77504..00000000 --- a/code/renderer/tr_glsl.c +++ /dev/null @@ -1,2079 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2006-2009 Robert Beckebans - -This file is part of XreaL source code. - -XreaL source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -XreaL source code 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with XreaL source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_glsl.c -#include "tr_local.h" - -void GLSL_BindNullProgram(void); - -// FIXME: Do something that isn't this messy -static const char *fallbackGenericShader_vp = -"attribute vec4 attr_Position;\r\nattribute vec4 attr_TexCoord0;\r\nattribut" -"e vec4 attr_TexCoord1;\r\nattribute vec3 attr_Normal;\r\nattribute vec4 att" -"r_Color;\r\n\r\n#if defined(USE_VERTEX_ANIMATION)\r\nattribute vec4 attr_Po" -"sition2;\r\nattribute vec3 attr_Normal2;\r\n#endif\r\n\r\nuniform mat4 u_" -"DiffuseTexMatrix;\r\nuniform vec3 u_ViewOrigin;\r\n\r\n#if defined(USE_TC" -"GEN)\r\nuniform int u_TCGen0;\r\nuniform vec3 u_TCGen0Vector0;\r\nunif" -"orm vec3 u_TCGen0Vector1;\r\n#endif\r\n\r\n#if defined(USE_FOG)\r\nunifor" -"m vec4 u_FogDistance;\r\nuniform vec4 u_FogDepth;\r\nuniform float u_F" -"ogEyeT;\r\nuniform vec4 u_FogColorMask;\r\n#endif\r\n\r\n#if defined(USE_" -"DEFORM_VERTEXES)\r\nuniform int u_DeformGen;\r\nuniform float u_DeformP" -"arams[5];\r\n#endif\r\n\r\nuniform float u_Time;\r\n\r\nuniform mat4 u_M" -"odelViewProjectionMatrix;\r\nuniform vec4 u_BaseColor;\r\nuniform vec4 " -"u_VertColor;\r\n\r\n#if defined(USE_RGBAGEN)\r\nuniform int u_ColorGen;" -"\r\nuniform int u_AlphaGen;\r\nuniform vec3 u_AmbientLight;\r\nuniform" -" vec3 u_DirectedLight;\r\nuniform vec4 u_LightOrigin;\r\nuniform float " -" u_PortalRange;\r\n#endif\r\n\r\n#if defined(USE_VERTEX_ANIMATION)\r\nunifo" -"rm float u_VertexLerp;\r\n#endif\r\n\r\nvarying vec2 var_DiffuseTex;\r\n" -"#if defined(USE_LIGHTMAP)\r\nvarying vec2 var_LightTex;\r\n#endif\r\nvary" -"ing vec4 var_Color;\r\n\r\nvec2 DoTexMatrix(vec2 st, vec3 position, mat4 " -"texMatrix)\r\n{\r\n\tfloat amplitude = texMatrix[3][0];\r\n\tfloat phase = " -"texMatrix[3][1];\r\n\tvec2 st2 = (texMatrix * vec4(st, 1.0, 0.0)).st;\r\n\r" -"\n\tvec3 offsetPos = position.xyz / 1024.0;\r\n\toffsetPos.x += offsetPos.z" -";\r\n\r\n\tvec2 texOffset = sin((offsetPos.xy + vec2(phase)) * 2.0 * M_PI);" -"\r\n\t\r\n\treturn st2 + texOffset * amplitude;\r\n}\r\n\r\n#if defined(USE" -"_DEFORM_VERTEXES)\r\nfloat triangle(float x)\r\n{\r\n\treturn max(1.0 - abs" -"(x), 0);\r\n}\r\n\r\nfloat sawtooth(float x)\r\n{\r\n\treturn x - floor(x);" -"\r\n}\r\n\r\nvec4 DeformPosition(const vec4 pos, const vec3 normal, const v" -"ec2 st)\r\n{\r\n\tfloat base = u_DeformParams[0];\r\n\tfloat amplitude" -" = u_DeformParams[1];\r\n\tfloat phase = u_DeformParams[2];\r\n\tfloat " -"frequency = u_DeformParams[3];\r\n\tfloat spread = u_DeformParams[4];\r" -"\n\t\r\n\tif (u_DeformGen == DGEN_BULGE)\r\n\t{\r\n\t\tphase *= M_PI * 0.25" -" * st.x;\r\n\t}\r\n\telse // if (u_DeformGen <= DGEN_WAVE_INVERSE_SAWTOOTH)" -"\r\n\t{\r\n\t\tphase += (pos.x + pos.y + pos.z) * spread;\r\n\t}\r\n\r\n\tf" -"loat value = phase + (u_Time * frequency);\r\n\tfloat func;\r\n\r\n\tif (u_" -"DeformGen == DGEN_WAVE_SIN)\r\n\t{\r\n\t\tfunc = sin(value * 2.0 * M_PI);\r" -"\n\t}\r\n\telse if (u_DeformGen == DGEN_WAVE_SQUARE)\r\n\t{\r\n\t\tfunc = s" -"ign(sin(value * 2.0 * M_PI));\r\n\t}\r\n\telse if (u_DeformGen == DGEN_WAVE" -"_TRIANGLE)\r\n\t{\r\n\t\tfunc = triangle(value);\r\n\t}\r\n\telse if (u_Def" -"ormGen == DGEN_WAVE_SAWTOOTH)\r\n\t{\r\n\t\tfunc = sawtooth(value);\r\n\t}" -"\r\n\telse if (u_DeformGen == DGEN_WAVE_INVERSE_SAWTOOTH)\r\n\t{\r\n\t\tfun" -"c = (1.0 - sawtooth(value));\r\n\t}\r\n\telse if (u_DeformGen == DGEN_BULGE" -")\r\n\t{\r\n\t\tfunc = sin(value);\r\n\t}\r\n\t\r\n\tvec4 deformed = pos;\r" -"\n\tdeformed.xyz += normal * (base + func * amplitude);\r\n\r\n\treturn def" -"ormed;\r\n}\r\n#endif\r\n\r\n#if defined(USE_TCGEN)\r\nvec2 GenTexCoords(in" -"t TCGen, vec4 position, vec3 normal, vec3 TCGenVector0, vec3 TCGenVector1)" -"\r\n{\r\n\tvec2 tex = attr_TexCoord0.st;\r\n\r\n\tif (TCGen == TCGEN_LIGHTM" -"AP)\r\n\t{\r\n\t\ttex = attr_TexCoord1.st;\r\n\t}\r\n\telse if (TCGen == TC" -"GEN_ENVIRONMENT_MAPPED)\r\n\t{\r\n\t\tvec3 viewer = normalize(u_ViewOrigin " -"- position.xyz);\r\n\t\tvec3 reflected = normal * 2.0 * dot(normal, viewer)" -" - viewer;\r\n\r\n\t\ttex.s = 0.5 + reflected.y * 0.5;\r\n\t\ttex.t = 0.5 -" -" reflected.z * 0.5;\r\n\t}\r\n\telse if (TCGen == TCGEN_VECTOR)\r\n\t{\r\n" -"\t\ttex.s = dot(position.xyz, TCGenVector0);\r\n\t\ttex.t = dot(position.xy" -"z, TCGenVector1);\r\n\t}\r\n\t\r\n\treturn tex;\r\n}\r\n#endif\r\n\r\nvoid " -"main()\r\n{\r\n#if defined(USE_VERTEX_ANIMATION)\r\n\tvec4 position = mix(a" -"ttr_Position, attr_Position2, u_VertexLerp);\r\n\tvec3 normal = normalize(m" -"ix(attr_Normal, attr_Normal2, u_VertexLerp));\r\n#else\r\n\tvec4 position =" -" attr_Position;\r\n\tvec3 normal = attr_Normal;\r\n#endif\r\n\r\n#if define" -"d(USE_DEFORM_VERTEXES)\r\n\tposition = DeformPosition(position, normal, att" -"r_TexCoord0.st);\r\n#endif\r\n\r\n\tgl_Position = u_ModelViewProjectionMatr" -"ix * position;\r\n\r\n#if defined(USE_TCGEN)\r\n\tvec2 tex = GenTexCoords(u" -"_TCGen0, position, normal, u_TCGen0Vector0, u_TCGen0Vector1);\r\n#else\r\n" -"\tvec2 tex = attr_TexCoord0.st;\r\n#endif\r\n\tvar_DiffuseTex = DoTexMatrix" -"(tex, position.xyz, u_DiffuseTexMatrix);\r\n\r\n#if defined(USE_LIGHTMAP)\r" -"\n\tvar_LightTex = attr_TexCoord1.st;\r\n#endif\r\n\r\n\tvar_Color = u_Base" -"Color + u_VertColor * attr_Color;\r\n\r\n#if defined(USE_RGBAGEN)\r\n\tif (" -"u_ColorGen == CGEN_LIGHTING_DIFFUSE)\r\n\t{\r\n\t\tfloat incoming = max(dot" -"(normal, u_LightOrigin.xyz), 0.0);\r\n\r\n\t\tvar_Color.rgb = min(u_Directe" -"dLight * incoming + u_AmbientLight, 1.0);\r\n\t}\r\n\t\r\n\tvec3 toView = u" -"_ViewOrigin - position.xyz;\r\n\r\n\tif (u_AlphaGen == AGEN_LIGHTING_SPECUL" -"AR)\r\n\t{\r\n\t\tvec3 lightDir = normalize(vec3(-960.0, -1980.0, 96.0) - p" -"osition.xyz);\r\n\t\tvec3 viewer = normalize(toView);\r\n\t\tvec3 halfangle" -" = normalize(lightDir + viewer);\r\n\t\t\r\n\t\tvar_Color.a = pow(max(dot(n" -"ormal, halfangle), 0.0), 8.0);\r\n\t}\r\n\telse if (u_AlphaGen == AGEN_PORT" -"AL)\r\n\t{\r\n\t\tfloat alpha = length(toView) / u_PortalRange;\r\n\r\n\t\t" -"var_Color.a = min(alpha, 1.0);\r\n\t}\r\n\telse if (u_AlphaGen == AGEN_FRES" -"NEL)\r\n\t{\r\n\t\tvec3 viewer = normalize(toView);\r\n\t\t\r\n\t\tvar_Colo" -"r.a = 0.10 + 0.90 * pow(1.0 - dot(normal, viewer), 5);\r\n\t}\r\n#endif\r\n" -"\r\n#if defined (USE_FOG)\r\n\tfloat s = dot(position.xyz, u_FogDistance.xy" -"z) + u_FogDistance.w;\r\n\tfloat t = dot(position.xyz, u_FogDepth.xyz) + u_" -"FogDepth.w;\r\n\t\r\n\tif (t >= 1.0)\r\n\t{\r\n\t\ts *= t / (t - min(u_FogE" -"yeT, 0.0));\r\n\t}\r\n\telse\r\n\t{\r\n\t\ts *= max(t + sign(u_FogEyeT), 0." -"0);\r\n\t}\r\n\t\r\n\ts = 1.0 - sqrt(clamp(s * 8.0, 0.0, 1.0));\r\n\t\r\n\t" -"var_Color *= u_FogColorMask * s - (u_FogColorMask - vec4(1.0));\r\n#endif\r" -"\n}\r\n"; - -static const char *fallbackGenericShader_fp = -"uniform sampler2D u_DiffuseMap;\r\n\r\n#if defined(USE_LIGHTMAP)\r\nuniform" -" sampler2D u_LightMap;\r\n#endif\r\n\r\nuniform int u_Texture1Env;\r" -"\n\r\nvarying vec2 var_DiffuseTex;\r\n\r\n#if defined(USE_LIGHTMAP)\r" -"\nvarying vec2 var_LightTex;\r\n#endif\r\n\r\nvarying vec4 var_Co" -"lor;\r\n\r\n\r\nvoid main()\r\n{\r\n\tvec4 color = texture2D(u_DiffuseMap," -" var_DiffuseTex);\r\n\r\n#if defined(USE_LIGHTMAP)\r\n\tvec4 color2 = textu" -"re2D(u_LightMap, var_LightTex);\r\n\r\n\tif (u_Texture1Env == TEXENV_MODU" -"LATE)\r\n\t{\r\n\t\tcolor *= color2;\r\n\t}\r\n\telse if (u_Texture1Env == " -"TEXENV_ADD)\r\n\t{\r\n\t\tcolor += color2;\r\n\t}\r\n\telse if (u_Texture1E" -"nv == TEXENV_REPLACE)\r\n\t{\r\n\t\tcolor = color2;\r\n\t}\r\n#endif\r\n\r" -"\n\tgl_FragColor = color * var_Color;\r\n}\r\n"; - -static const char *fallbackTextureColorShader_vp = -"#version 120\r\n\r\nattribute vec4 attr_Position;\r\nattribute vec4 attr_Te" -"xCoord0;\r\n\r\nuniform mat4 u_ModelViewProjectionMatrix;\r\n\r\nvarying " -"vec2 var_Tex1;\r\n\r\n\r\nvoid main()\r\n{\r\n\tgl_Position = u_ModelView" -"ProjectionMatrix * attr_Position;\r\n\tvar_Tex1 = attr_TexCoord0.st;\r\n}\r" -"\n"; - -static const char *fallbackTextureColorShader_fp = -"#version 120\r\n\r\nuniform sampler2D u_DiffuseMap;\r\nuniform vec4 u_" -"Color;\r\n\r\nvarying vec2 var_Tex1;\r\n\r\n\r\nvoid main()\r\n{\r" -"\n\tgl_FragColor = texture2D(u_DiffuseMap, var_Tex1) * u_Color;\r\n}\r\n"; - -static const char *fallbackFogPassShader_vp = -"attribute vec4 attr_Position;\r\nattribute vec3 attr_Normal;\r\nattribute" -" vec4 attr_TexCoord0;\r\n\r\n//#if defined(USE_VERTEX_ANIMATION)\r\nattrib" -"ute vec4 attr_Position2;\r\nattribute vec3 attr_Normal2;\r\n//#endif\r\n" -"\r\nuniform vec4 u_FogDistance;\r\nuniform vec4 u_FogDepth;\r\nunifor" -"m float u_FogEyeT;\r\n\r\n//#if defined(USE_DEFORM_VERTEXES)\r\nuniform i" -"nt u_DeformGen;\r\nuniform float u_DeformParams[5];\r\n//#endif\r\n\r" -"\nuniform float u_Time;\r\nuniform mat4 u_ModelViewProjectionMatrix;\r" -"\n\r\n//#if defined(USE_VERTEX_ANIMATION)\r\nuniform float u_VertexLerp;" -"\r\n//#endif\r\n\r\nvarying float var_Scale;\r\n\r\n\r\nfloat triangle(fl" -"oat x)\r\n{\r\n\treturn max(1.0 - abs(x), 0);\r\n}\r\n\r\nfloat sawtooth(fl" -"oat x)\r\n{\r\n\treturn x - floor(x);\r\n}\r\n\r\nvec4 DeformPosition(const" -" vec4 pos, const vec3 normal, const vec2 st)\r\n{\r\n\tif (u_DeformGen == 0" -")\r\n\t{\r\n\t\treturn pos;\r\n\t}\r\n\r\n\tfloat base = u_DeformParam" -"s[0];\r\n\tfloat amplitude = u_DeformParams[1];\r\n\tfloat phase = u_De" -"formParams[2];\r\n\tfloat frequency = u_DeformParams[3];\r\n\tfloat spread " -"= u_DeformParams[4];\r\n\t\t\r\n\tif (u_DeformGen <= DGEN_WAVE_INVERSE_S" -"AWTOOTH)\r\n\t{\r\n\t\tphase += (pos.x + pos.y + pos.z) * spread;\r\n\t}\r" -"\n\telse if (u_DeformGen == DGEN_BULGE)\r\n\t{\r\n\t\tphase *= M_PI * 0.25 " -"* st.x;\r\n\t}\r\n\r\n\tfloat value = phase + (u_Time * frequency);\r\n\tfl" -"oat func;\r\n\r\n\tif (u_DeformGen == DGEN_WAVE_SIN)\r\n\t{\r\n\t\tfunc = s" -"in(value * 2.0 * M_PI);\r\n\t}\r\n\telse if (u_DeformGen == DGEN_WAVE_SQUAR" -"E)\r\n\t{\r\n\t\tfunc = sign(sin(value * 2.0 * M_PI));\r\n\t}\r\n\telse if " -"(u_DeformGen == DGEN_WAVE_TRIANGLE)\r\n\t{\r\n\t\tfunc = triangle(value);\r" -"\n\t}\r\n\telse if (u_DeformGen == DGEN_WAVE_SAWTOOTH)\r\n\t{\r\n\t\tfunc =" -" sawtooth(value);\r\n\t}\r\n\telse if (u_DeformGen == DGEN_WAVE_INVERSE_SAW" -"TOOTH)\r\n\t{\r\n\t\tfunc = (1.0 - sawtooth(value));\r\n\t}\r\n\telse if (u" -"_DeformGen == DGEN_BULGE)\r\n\t{\r\n\t\tfunc = sin(value);\r\n\t}\r\n\r\n\t" -"vec4 deformed = pos;\r\n\tdeformed.xyz += normal * (base + func * amplitude" -");\r\n\r\n\treturn deformed;\r\n\r\n}\r\n\r\nvoid main()\r\n{\r\n\tvec4 pos" -"ition = mix(attr_Position, attr_Position2, u_VertexLerp);\r\n\tvec3 normal " -"= normalize(mix(attr_Normal, attr_Normal2, u_VertexLerp));\r\n\r\n\tpositio" -"n = DeformPosition(position, normal, attr_TexCoord0.st);\r\n\r\n\tgl_Positi" -"on = u_ModelViewProjectionMatrix * position;\r\n\r\n\tfloat s = dot(positio" -"n.xyz, u_FogDistance.xyz) + u_FogDistance.w;\r\n\tfloat t = dot(position.xy" -"z, u_FogDepth.xyz) + u_FogDepth.w;\r\n\r\n\tif (t >= 1.0)\r\n\t{\r\n\t\ts *" -"= t / (t - min(u_FogEyeT, 0.0));\r\n\t}\r\n\telse\r\n\t{\r\n\t\ts *= max(t " -"+ sign(u_FogEyeT), 0.0);\r\n\t}\r\n\r\n\tvar_Scale = clamp(s * 8.0, 0.0, 1." -"0);\r\n}\r\n"; - -static const char *fallbackFogPassShader_fp = -"uniform vec4 u_Color;\r\n\r\nvarying float var_Scale;\r\n\r\nvoid main()\r" -"\n{\r\n\tgl_FragColor = u_Color;\r\n\tgl_FragColor.a *= sqrt(var_Scale);\r" -"\n}\r\n"; - -static const char *fallbackDlightShader_vp = -"attribute vec4 attr_Position;\r\nattribute vec4 attr_TexCoord0;\r\nattribut" -"e vec3 attr_Normal;\r\n\r\nuniform vec4 u_DlightInfo;\r\n\r\nuniform int " -" u_DeformGen;\r\nuniform float u_DeformParams[5];\r\n\r\nuniform float " -"u_Time;\r\nuniform vec4 u_Color;\r\nuniform mat4 u_ModelViewProjectionM" -"atrix;\r\n\r\nvarying vec2 var_Tex1;\r\nvarying vec4 var_Color;\r\n\r\n" -"float triangle(float x)\r\n{\r\n\treturn max(1.0 - abs(x), 0);\r\n}\r\n\r\n" -"float sawtooth(float x)\r\n{\r\n\treturn x - floor(x);\r\n}\r\n\r\nvec4 Def" -"ormPosition(const vec4 pos, const vec3 normal, const vec2 st)\r\n{\r\n\tif " -"(u_DeformGen == 0)\r\n\t{\r\n\t\treturn pos;\r\n\t}\r\n\r\n\tfloat base = " -" u_DeformParams[0];\r\n\tfloat amplitude = u_DeformParams[1];\r\n\tfloat" -" phase = u_DeformParams[2];\r\n\tfloat frequency = u_DeformParams[3];\r" -"\n\tfloat spread = u_DeformParams[4];\r\n\t\t\r\n\tif (u_DeformGen <= DG" -"EN_WAVE_INVERSE_SAWTOOTH)\r\n\t{\r\n\t\tphase += (pos.x + pos.y + pos.z) * " -"spread;\r\n\t}\r\n\telse if (u_DeformGen == DGEN_BULGE)\r\n\t{\r\n\t\tphase" -" *= M_PI * 0.25 * st.x;\r\n\t}\r\n\r\n\tfloat value = phase + (u_Time * fre" -"quency);\r\n\tfloat func;\r\n\r\n\tif (u_DeformGen == DGEN_WAVE_SIN)\r\n\t{" -"\r\n\t\tfunc = sin(value * 2.0 * M_PI);\r\n\t}\r\n\telse if (u_DeformGen ==" -" DGEN_WAVE_SQUARE)\r\n\t{\r\n\t\tfunc = sign(sin(value * 2.0 * M_PI));\r\n" -"\t}\r\n\telse if (u_DeformGen == DGEN_WAVE_TRIANGLE)\r\n\t{\r\n\t\tfunc = t" -"riangle(value);\r\n\t}\r\n\telse if (u_DeformGen == DGEN_WAVE_SAWTOOTH)\r\n" -"\t{\r\n\t\tfunc = sawtooth(value);\r\n\t}\r\n\telse if (u_DeformGen == DGEN" -"_WAVE_INVERSE_SAWTOOTH)\r\n\t{\r\n\t\tfunc = (1.0 - sawtooth(value));\r\n\t" -"}\r\n\telse if (u_DeformGen == DGEN_BULGE)\r\n\t{\r\n\t\tfunc = sin(value);" -"\r\n\t}\r\n\r\n\tvec4 deformed = pos;\r\n\tdeformed.xyz += normal * (base +" -" func * amplitude);\r\n\r\n\treturn deformed;\r\n\r\n}\r\n\r\nvoid main()\r" -"\n{\r\n\tvec4 position = attr_Position;\r\n\tvec3 normal = attr_Normal;\r\n" -"\r\n\tposition = DeformPosition(position, normal, attr_TexCoord0.st);\r\n\r" -"\n\tgl_Position = u_ModelViewProjectionMatrix * position;\r\n\t\t\r\n\tvec3" -" dist = u_DlightInfo.xyz - position.xyz;\t\r\n\r\n\tfloat diffz = abs(dist." -"z);\r\n\tfloat radius = 1.0 / u_DlightInfo.a;\r\n\r\n\tvec2 tex = vec2(0.5)" -" + dist.xy * u_DlightInfo.a;\r\n\tfloat dlightmod = max(sign(dot(dist, norm" -"al)), 0.0);\r\n\tdlightmod *= clamp(2.0 * (radius - diffz) * u_DlightInfo.a" -", 0.0, 1.0);\r\n\r\n\tvar_Tex1 = tex;\r\n\tvar_Color = u_Color;\r\n\tvar_Co" -"lor.rgb *= dlightmod;\r\n}\r\n"; - -static const char *fallbackDlightShader_fp = -"uniform sampler2D u_DiffuseMap;\r\n\r\nvarying vec2 var_Tex1;\r\nvaryi" -"ng vec4 var_Color;\r\n\r\n\r\nvoid main()\r\n{\r\n\tvec4 color = textu" -"re2D(u_DiffuseMap, var_Tex1);\r\n\r\n\tgl_FragColor = color * var_Color;\r" -"\n}\r\n"; - -static const char *fallbackLightallShader_vp = -"attribute vec4 attr_TexCoord0;\r\n#if defined(USE_LIGHTMAP)\r\nattribute ve" -"c4 attr_TexCoord1;\r\n#endif\r\nattribute vec4 attr_Color;\r\n\r\nattribute" -" vec4 attr_Position;\r\nattribute vec3 attr_Normal;\r\n\r\n#if defined(USE_" -"NORMALMAP)\r\nattribute vec3 attr_Tangent;\r\nattribute vec3 attr_Bitangent" -";\r\n#endif\r\n\r\n#if defined(USE_VERTEX_ANIMATION)\r\nattribute vec4 attr" -"_Position2;\r\nattribute vec3 attr_Normal2;\r\n #if defined(USE_NORMALMAP)" -"\r\nattribute vec3 attr_Tangent2;\r\nattribute vec3 attr_Bitangent2;\r\n #" -"endif\r\n#endif\r\n\r\nuniform mat4 u_DiffuseTexMatrix;\r\nuniform vec3 " -" u_ViewOrigin;\r\nuniform mat4 u_ModelViewProjectionMatrix;\r\nuniform ve" -"c4 u_BaseColor;\r\nuniform vec4 u_VertColor;\r\n\r\n#if defined(USE_MOD" -"ELMATRIX)\r\nuniform mat4 u_ModelMatrix;\r\n#endif\r\n\r\n#if defined(USE" -"_VERTEX_ANIMATION)\r\nuniform float u_VertexLerp;\r\n#endif\r\n\r\nvarying" -" vec2 var_DiffuseTex;\r\n\r\n#if defined(USE_LIGHTMAP)\r\nvarying vec2 " -"var_LightTex;\r\n#endif\r\n\r\nvarying vec4 var_Color;\r\n\r\nvarying vec" -"3 var_Position;\r\nvarying vec3 var_Normal;\r\n\r\n#if defined(USE_NORM" -"ALMAP)\r\nvarying vec3 var_Tangent;\r\nvarying vec3 var_Bitangent;\r\n#" -"endif\r\n\r\nvec2 DoTexMatrix(vec2 st, vec3 position, mat4 texMatrix)\r\n{" -"\r\n\tvec2 st2 = (texMatrix * vec4(st, 1, 0)).st;\r\n\r\n\tvec3 offsetPos =" -" position.xyz / 1024.0;\r\n\toffsetPos.x += offsetPos.z;\r\n\r\n\tvec2 texO" -"ffset = sin((offsetPos.xy + vec2(texMatrix[3][1])) * 2.0 * M_PI);\r\n\t\r\n" -"\treturn st2 + texOffset * texMatrix[3][0];\r\n}\r\n\r\nvoid main()\r\n{\r" -"\n#if defined(USE_VERTEX_ANIMATION)\r\n\tvec4 position = mix(attr_Position" -", attr_Position2, u_VertexLerp);\r\n\tvec3 normal = normalize(mix(attr_N" -"ormal, attr_Normal2, u_VertexLerp));\r\n #if defined(USE_NORMALMAP)" -"\r\n\tvec3 tangent = normalize(mix(attr_Tangent, attr_Tangent2, u_Ver" -"texLerp));\r\n\tvec3 bitangent = normalize(mix(attr_Bitangent, attr_Bitange" -"nt2, u_VertexLerp));\r\n #endif\r\n#else\r\n\tvec4 position = attr_Positi" -"on;\r\n\tvec3 normal = attr_Normal;\r\n #if defined(USE_NORMALMAP)\r\n " -" vec3 tangent = attr_Tangent;\r\n vec3 bitangent = attr_Bita" -"ngent;\r\n #endif\r\n#endif\r\n\r\n\tgl_Position = u_ModelViewProjectionMa" -"trix * position;\r\n\r\n#if defined(TCGEN_ENVIRONMENT)\r\n\tvec2 tex;\r\n\t" -"vec3 viewer = normalize(u_ViewOrigin - position.xyz);\r\n\tvec3 reflected =" -" normal * 2.0 * dot(normal, viewer) - viewer;\r\n\r\n\ttex.s = 0.5 + reflec" -"ted.y * 0.5;\r\n\ttex.t = 0.5 - reflected.z * 0.5;\r\n#else\r\n\tvec2 tex =" -" attr_TexCoord0.st;\r\n#endif\r\n\r\n\tvar_DiffuseTex = DoTexMatrix(tex, po" -"sition.xyz, u_DiffuseTexMatrix);\r\n\r\n#if defined(USE_LIGHTMAP)\r\n\tvar_" -"LightTex = attr_TexCoord1.st;\r\n#endif\r\n\t\r\n\tvar_Color = u_BaseColor " -"+ u_VertColor * attr_Color;\r\n\r\n#if defined(USE_MODELMATRIX)\r\n\tvar_Po" -"sition = (u_ModelMatrix * position).xyz;\r\n\tvar_Normal = (u_ModelMatr" -"ix * vec4(normal, 0.0)).xyz;\r\n\r\n #if defined(USE_NORMALMAP)\r\n\tvar_T" -"angent = (u_ModelMatrix * vec4(tangent, 0.0)).xyz;\r\n\tvar_Bitangent = (" -"u_ModelMatrix * vec4(bitangent, 0.0)).xyz;\r\n #endif\r\n#else\r\n\tvar_Po" -"sition = position.xyz;\r\n\tvar_Normal = normal;\r\n\r\n #if defined(U" -"SE_NORMALMAP)\r\n\tvar_Tangent = tangent;\r\n\tvar_Bitangent = bitangent;" -"\r\n #endif\r\n#endif\r\n}\r\n"; - -static const char *fallbackLightallShader_fp = -"uniform sampler2D u_DiffuseMap;\r\n\r\n#if defined(USE_LIGHTMAP)\r\nuniform" -" sampler2D u_LightMap;\r\n#endif\r\n\r\n#if defined(USE_NORMALMAP)\r\nunifo" -"rm sampler2D u_NormalMap;\r\n#endif\r\n\r\n#if defined(USE_DELUXEMAP)\r\nun" -"iform sampler2D u_DeluxeMap;\r\n#endif\r\n\r\n#if defined(USE_SPECULARMAP)" -"\r\nuniform sampler2D u_SpecularMap;\r\n#endif\r\n\r\n#if defined(USE_SHADO" -"WMAP)\r\nuniform samplerCube u_ShadowMap;\r\n#endif\r\n\r\nuniform vec3 " -" u_ViewOrigin;\r\n\r\n#if defined(USE_LIGHT_VECTOR)\r\nuniform vec3 u" -"_DirectedLight;\r\nuniform vec3 u_AmbientLight;\r\nuniform vec4 u" -"_LightOrigin;\r\nuniform float u_LightRadius;\r\n#endif\r\n\r\n#if defi" -"ned(USE_SPECULARMAP)\r\nuniform float u_SpecularReflectance;\r\n#endif" -"\r\n\r\nvarying vec2 var_DiffuseTex;\r\n#if defined(USE_LIGHTMAP)\r\nv" -"arying vec2 var_LightTex;\r\n#endif\r\nvarying vec4 var_Color;\r" -"\n\r\nvarying vec3 var_Position;\r\n\r\n#if defined(USE_NORMALMAP)\r\n" -"varying vec3 var_Tangent;\r\nvarying vec3 var_Bitangent;\r\n#endi" -"f\r\n\r\nvarying vec3 var_Normal;\r\n\r\n\r\nfloat RayIntersectDisplac" -"eMap(vec2 dp, vec2 ds, sampler2D normalMap)\r\n{\r\n\tconst int linearSearc" -"hSteps = 5;\r\n\tconst int binarySearchSteps = 5;\r\n\r\n\tfloat depthStep " -"= 1.0 / float(linearSearchSteps);\r\n\r\n\t// current size of search window" -"\r\n\tfloat size = depthStep;\r\n\r\n\t// current depth position\r\n\tfloat" -" depth = 0.0;\r\n\r\n\t// best match found (starts with last position 1.0)" -"\r\n\tfloat bestDepth = 1.0;\r\n\r\n\t// search front to back for first poi" -"nt inside object\r\n\tfor(int i = 0; i < linearSearchSteps - 1; ++i)\r\n\t{" -"\r\n\t\tdepth += size;\r\n\t\t\r\n\t\tvec4 t = texture2D(normalMap, dp + ds" -" * depth);\r\n\r\n\t\tif(bestDepth > 0.996)\t\t// if no depth found yet\r\n" -"\t\t\tif(depth >= t.w)\r\n\t\t\t\tbestDepth = depth;\t// store best depth\r" -"\n\t}\r\n\r\n\tdepth = bestDepth;\r\n\t\r\n\t// recurse around first point " -"(depth) for closest match\r\n\tfor(int i = 0; i < binarySearchSteps; ++i)\r" -"\n\t{\r\n\t\tsize *= 0.5;\r\n\r\n\t\tvec4 t = texture2D(normalMap, dp + ds " -"* depth);\r\n\t\t\r\n\t\tif(depth >= t.w)\r\n\t\t{\r\n\t\t\tbestDepth = dep" -"th;\r\n\t\t\tdepth -= 2.0 * size;\r\n\t\t}\r\n\r\n\t\tdepth += size;\r\n\t}" -"\r\n\r\n\treturn bestDepth;\r\n}\r\n\r\nvoid main()\r\n{\r\n#if defined(USE" -"_LIGHTMAP)\r\n\tvec3 directedLight = texture2D(u_LightMap, var_LightTex).rg" -"b;\r\n #if defined(USE_DELUXEMAP)\r\n\tvec3 worldLight = 2.0 * texture2D(u" -"_DeluxeMap, var_LightTex).xyz - vec3(1.0);\r\n #endif\r\n#endif\r\n\r\n#if" -" defined(USE_LIGHT_VECTOR)\r\n\tvec3 worldLight = u_LightOrigin.xyz - (var_" -"Position * u_LightOrigin.w);\t\r\n #if defined(USE_INVSQRLIGHT)\r\n\tfloat" -" intensity = 1.0 / dot(worldLight, worldLight);\r\n #else\r\n\tfloat inten" -"sity = clamp((1.0 - dot(worldLight, worldLight) / (u_LightRadius * u_LightR" -"adius)) * 1.07, 0.0, 1.0);\r\n #endif\r\n #if defined(USE_SHADOWMAP)\r\n " -" \tvec3 dist3 = textureCube(u_ShadowMap, worldLight).rgb;\r\n\tfloat dist =" -" dot(dist3, vec3(1.0 / (256.0 * 256.0), 1.0 / 256.0, 1.0)) * u_LightRadius;" -"\r\n\r\n\tintensity *= max(sign(dist - length(worldLight)), 0.0);\r\n #end" -"if\r\n\tvec3 directedLight = u_DirectedLight * intensity;\r\n\tvec3 ambient" -"Light = u_AmbientLight;\r\n#endif\r\n\r\n#if !(defined(USE_LIGHTMAP) && de" -"fined(USE_DELUXEMAP)) && !defined(USE_LIGHT_VECTOR)\r\n\tvec3 worldLight = " -"var_Normal;\r\n#endif\r\n\r\n\tvec3 SampleToView = normalize(u_ViewOrigin -" -" var_Position);\r\n\tvec2 texOffset = vec2(0.0);\r\n\t\r\n\tfloat ambientDi" -"ff = 1.0;\r\n\r\n#if defined(USE_NORMALMAP)\r\n\tmat3 tangentToWorld = mat3" -"(var_Tangent.xyz, var_Bitangent.xyz, var_Normal.xyz);\r\n\r\n #if defined(" -"USE_PARALLAXMAP)\r\n\tvec3 offsetDir = normalize(SampleToView * tangentToWo" -"rld);\r\n #if 0\r\n\tfloat dist = 0.02 * texture2D(u_NormalMap, var_Diff" -"useTex).w - (0.02 / 2.0);\r\n #else\r\n\toffsetDir.xy *= 0.02 / offsetDi" -"r.z;\r\n\tfloat dist = RayIntersectDisplaceMap(var_DiffuseTex, offsetDir.xy" -", u_NormalMap);\r\n #endif\t\r\n\ttexOffset = offsetDir.xy * dist;\r\n " -"#endif\r\n \r\n\tvec3 normal = texture2D(u_NormalMap, var_DiffuseTex + tex" -"Offset).xyz;\r\n\tvec3 worldNormal = tangentToWorld * (2.0 * normal.xyz - v" -"ec3(1.0));\r\n #if defined(r_normalAmbient)\r\n\tambientDiff = 0.248965 * " -"normal.z + 0.069673;\r\n #endif\r\n#else\r\n\tvec3 worldNormal = var_Norma" -"l;\r\n#endif\r\n\r\n\tvec4 diffuse = texture2D(u_DiffuseMap, var_DiffuseTex" -" + texOffset);\r\n\t\r\n\tworldNormal = normalize(worldNormal);\r\n\tworldL" -"ight = normalize(worldLight);\r\n\r\n#if defined(USE_LIGHTMAP)\r\n #if def" -"ined(USE_DELUXEMAP)\r\n\tdirectedLight /= max(dot(normalize(var_Normal), wo" -"rldLight), 0.004);\r\n #endif\r\n \r\n #if defined(r_normalAmbient)\r\n" -"\tvec3 ambientLight = directedLight * r_normalAmbient;\r\n\tdirectedLight -" -"= ambientLight;\r\n #else\r\n\tvec3 ambientLight = vec3(0);\r\n #endif\r" -"\n#endif\r\n\r\n#if defined(r_normalAmbient) && (defined(USE_LIGHTMAP) || d" -"efined(USE_LIGHT_VECTOR))\r\n\tambientLight *= 3.138357;\r\n#endif\r\n\r\n#" -"if (defined(USE_LIGHTMAP) && defined(USE_DELUXEMAP)) || defined(USE_LIGHT_V" -"ECTOR)\r\n\tfloat NL = max(dot(worldNormal, worldLight), 0.0);\r\n#else" -"\r\n\tfloat NL = 1.0;\r\n#endif\r\n\r\n#if defined(USE_SPECULARMAP) && (def" -"ined(USE_LIGHTMAP) || defined(USE_LIGHT_VECTOR))\r\n\tvec4 specular = textu" -"re2D(u_SpecularMap, var_DiffuseTex + texOffset);\r\n\tfloat shininess = spe" -"cular.a * 255 + 1.0;\r\n\tfloat fzero = u_SpecularReflectance;\r\n\r\n\tvec" -"3 halfAngle = normalize(worldLight + SampleToView);\r\n\r\n\tfloat EH = max" -"(dot(SampleToView, halfAngle), 0.0);\r\n\tfloat NE = max(dot(worldNormal" -", SampleToView), 0.0001);\r\n\tfloat NH = max(dot(worldNormal, halfAngle)" -", 0.0);\r\n\r\n\tfloat factor = 0.1248582 * shininess + 0.2691817;\r\n\t" -"float fspec = fzero + (1.0 - fzero) * pow(1.0 - EH, 5);\r\n\r\n\tdiffuse.rg" -"b *= min((directedLight * NL + ambientLight) * (1.0 - fzero) , 1.0);\r\n\t" -"\r\n\tfloat directedSpec = factor * fspec * pow(NH, shininess) / max(NL, NE" -");\r\n\r\n #if defined(r_normalAmbient)\r\n #if defined(USE_NORMALMAP)" -"\r\n\tfloat ambientSpec = pow(normal.z, shininess);\r\n #else\r\n\tfloat" -" ambientSpec = 1.0f;\r\n #endif\r\n\r\n\tambientSpec *= factor * fzero *" -" 8.05438 / (shininess + 19.0);\r\n\tambientSpec += 0.04389 / (shininess * s" -"hininess);\r\n\t\r\n\tspecular.rgb *= min(directedSpec * directedLight + am" -"bientSpec * ambientLight, 1.0);\r\n #else\r\n\tspecular.rgb *= min(directe" -"dSpec * directedLight, 1.0);\r\n #endif\r\n#else\r\n #if (defined(USE_LIG" -"HTMAP) || defined(USE_LIGHT_VECTOR))\r\n\tdiffuse.rgb *= min(directedLight " -"* NL + ambientDiff * ambientLight, 1.0);\r\n #endif\r\n#endif\r\n\r\n\tgl_" -"FragColor = diffuse;\r\n\r\n#if defined(USE_SPECULARMAP) && (defined(USE_LI" -"GHTMAP) || defined(USE_LIGHT_VECTOR))\r\n\tgl_FragColor.rgb += specular.rgb" -";\r\n#endif\r\n\r\n\tgl_FragColor *= var_Color;\r\n}\r\n"; - -static const char *fallbackShadowfillShader_vp = -"attribute vec4 attr_Position;\r\nattribute vec3 attr_Normal;\r\nattribute" -" vec4 attr_TexCoord0;\r\n\r\n//#if defined(USE_VERTEX_ANIMATION)\r\nattrib" -"ute vec4 attr_Position2;\r\nattribute vec3 attr_Normal2;\r\n//#endif\r\n" -"\r\n//#if defined(USE_DEFORM_VERTEXES)\r\nuniform int u_DeformGen;\r\nu" -"niform float u_DeformParams[5];\r\n//#endif\r\n\r\nuniform float u_Tim" -"e;\r\nuniform mat4 u_ModelViewProjectionMatrix;\r\n\r\nuniform mat4 u_" -"ModelMatrix;\r\n\r\n//#if defined(USE_VERTEX_ANIMATION)\r\nuniform float " -"u_VertexLerp;\r\n//#endif\r\n\r\nvarying vec3 var_Position;\r\n\r\nfloat" -" triangle(float x)\r\n{\r\n\treturn max(1.0 - abs(x), 0);\r\n}\r\n\r\nfloat" -" sawtooth(float x)\r\n{\r\n\treturn x - floor(x);\r\n}\r\n\r\nvec4 DeformPo" -"sition(const vec4 pos, const vec3 normal, const vec2 st)\r\n{\r\n\tif (u_De" -"formGen == 0)\r\n\t{\r\n\t\treturn pos;\r\n\t}\r\n\r\n\tfloat base = u" -"_DeformParams[0];\r\n\tfloat amplitude = u_DeformParams[1];\r\n\tfloat phas" -"e = u_DeformParams[2];\r\n\tfloat frequency = u_DeformParams[3];\r\n\tf" -"loat spread = u_DeformParams[4];\r\n\t\t\r\n\tif (u_DeformGen <= DGEN_WA" -"VE_INVERSE_SAWTOOTH)\r\n\t{\r\n\t\tphase += (pos.x + pos.y + pos.z) * sprea" -"d;\r\n\t}\r\n\telse if (u_DeformGen == DGEN_BULGE)\r\n\t{\r\n\t\tphase *= M" -"_PI * 0.25 * st.x;\r\n\t}\r\n\r\n\tfloat value = phase + (u_Time * frequenc" -"y);\r\n\tfloat func;\r\n\r\n\tif (u_DeformGen == DGEN_WAVE_SIN)\r\n\t{\r\n" -"\t\tfunc = sin(value * 2.0 * M_PI);\r\n\t}\r\n\telse if (u_DeformGen == DGE" -"N_WAVE_SQUARE)\r\n\t{\r\n\t\tfunc = sign(sin(value * 2.0 * M_PI));\r\n\t}\r" -"\n\telse if (u_DeformGen == DGEN_WAVE_TRIANGLE)\r\n\t{\r\n\t\tfunc = triang" -"le(value);\r\n\t}\r\n\telse if (u_DeformGen == DGEN_WAVE_SAWTOOTH)\r\n\t{\r" -"\n\t\tfunc = sawtooth(value);\r\n\t}\r\n\telse if (u_DeformGen == DGEN_WAVE" -"_INVERSE_SAWTOOTH)\r\n\t{\r\n\t\tfunc = (1.0 - sawtooth(value));\r\n\t}\r\n" -"\telse if (u_DeformGen == DGEN_BULGE)\r\n\t{\r\n\t\tfunc = sin(value);\r\n" -"\t}\r\n\r\n\tvec4 deformed = pos;\r\n\tdeformed.xyz += normal * (base + fun" -"c * amplitude);\r\n\r\n\treturn deformed;\r\n\r\n}\r\n\r\n\r\nvoid main()\r" -"\n{\r\n\tvec4 position = mix(attr_Position, attr_Position2, u_VertexLerp);" -"\r\n\tvec3 normal = normalize(mix(attr_Normal, attr_Normal2, u_VertexLerp))" -";\r\n\r\n\tposition = DeformPosition(position, normal, attr_TexCoord0.st);" -"\r\n\r\n\tgl_Position = u_ModelViewProjectionMatrix * position;\r\n\t\r\n\t" -"var_Position = (u_ModelMatrix * position).xyz;\r\n}\r\n"; - -static const char *fallbackShadowfillShader_fp = -"uniform vec4 u_LightOrigin;\r\nuniform float u_LightRadius;\r\n\r\nvarying" -" vec3 var_Position;\r\n\r\nvoid main()\r\n{\r\n\tfloat depth = length(u_Li" -"ghtOrigin.xyz - var_Position) / u_LightRadius;\r\n#if 0\r\n\t// 32 bit prec" -"ision\r\n\tconst vec4 bitSh = vec4( 256 * 256 * 256, 256 * 256, 2" -"56, 1);\r\n\tconst vec4 bitMsk = vec4( 0, 1.0 / 256." -"0, 1.0 / 256.0, 1.0 / 256.0);\r\n\t\r\n\tvec4 comp;\r\n\tcomp = depth * bit" -"Sh;\r\n\tcomp.xyz = fract(comp.xyz);\r\n\tcomp -= comp.xxyz * bitMsk;\r\n\t" -"gl_FragColor = comp;\r\n#endif\r\n\r\n#if 1\r\n\t// 24 bit precision\r\n\tc" -"onst vec3 bitSh = vec3( 256 * 256, 256, 1);\r\n\tconst ve" -"c3 bitMsk = vec3( 0, 1.0 / 256.0, 1.0 / 256.0);\r\n\t\r\n\tvec3 comp" -";\r\n\tcomp = depth * bitSh;\r\n\tcomp.xy = fract(comp.xy);\r\n\tcomp -= co" -"mp.xxy * bitMsk;\r\n\tgl_FragColor = vec4(comp, 1.0);\r\n#endif\r\n\r\n#if " -"0\r\n\t// 8 bit precision\r\n\tgl_FragColor = vec4(depth, depth, depth, 1);" -"\r\n#endif\r\n}\r\n"; - -static const char *fallbackPshadowShader_vp = -"attribute vec4 attr_Position;\r\nattribute vec3 attr_Normal;\r\n\r\nuniform" -" mat4 u_ModelViewProjectionMatrix;\r\nvarying vec3 var_Position;\r\nvar" -"ying vec3 var_Normal;\r\n\r\n\r\nvoid main()\r\n{\r\n\tvec4 position = a" -"ttr_Position;\r\n\r\n\tgl_Position = u_ModelViewProjectionMatrix * position" -";\r\n\r\n\tvar_Position = position.xyz;\r\n\tvar_Normal = attr_Normal;" -"\r\n}\r\n"; - -static const char *fallbackPshadowShader_fp = -"uniform sampler2D u_ShadowMap;\r\n\r\nuniform vec3 u_LightForward;\r\n" -"uniform vec3 u_LightUp;\r\nuniform vec3 u_LightRight;\r\nuniform " -"vec4 u_LightOrigin;\r\nuniform float u_LightRadius;\r\nvarying vec" -"3 var_Position;\r\nvarying vec3 var_Normal;\r\n\r\nfloat sampleDi" -"stMap(sampler2D texMap, vec2 uv, float scale)\r\n{\r\n\tvec3 distv = textur" -"e2D(texMap, uv).xyz;\r\n\treturn dot(distv, vec3(1.0 / (256.0 * 256.0), 1.0" -" / 256.0, 1.0)) * scale;\r\n}\r\n\r\nvoid main()\r\n{\r\n\tvec2 st;\r\n\t\r" -"\n\tvec3 lightToPos = var_Position - u_LightOrigin.xyz;\r\n\t\r\n\tst.s = -" -"dot(u_LightRight, lightToPos);\r\n\tst.t = dot(u_LightUp, lightToPos);\r\n" -"\t\r\n\tst = st * 0.5 + vec2(0.5);\r\n\r\n#if defined(USE_SOLID_PSHADOWS)\r" -"\n\tfloat intensity = max(sign(u_LightRadius - length(lightToPos)), 0.0);\r" -"\n#else\r\n\tfloat intensity = clamp((1.0 - dot(lightToPos, lightToPos) / (" -"u_LightRadius * u_LightRadius)) * 2.0, 0.0, 1.0);\r\n#endif\r\n\t\r\n\tfloa" -"t lightDist = length(lightToPos);\r\n\tfloat dist;\r\n\r\n#if defined(USE_D" -"ISCARD)\r\n\tif (dot(u_LightForward, lightToPos) <= 0.0)\r\n\t{\r\n\t\tdisc" -"ard;\r\n\t}\r\n\r\n\tif (dot(var_Normal, lightToPos) > 0.0)\r\n\t{\r\n\t\td" -"iscard;\r\n\t}\r\n#else\r\n\tintensity *= max(sign(dot(u_LightForward, ligh" -"tToPos)), 0.0);\r\n\tintensity *= max(sign(-dot(var_Normal, lightToPos)), 0" -".0);\r\n#endif\r\n\t\r\n#if defined(USE_PCF)\r\n\tfloat part;\r\n\t\r\n\tdi" -"st = sampleDistMap(u_ShadowMap, st + vec2(-1.0/256.0, -1.0/256.0), u_LightR" -"adius);\r\n\tpart = max(sign(lightDist - dist), 0.0);\r\n\r\n\tdist = samp" -"leDistMap(u_ShadowMap, st + vec2( 1.0/256.0, -1.0/256.0), u_LightRadius);\r" -"\n\tpart += max(sign(lightDist - dist), 0.0);\r\n\r\n\tdist = sampleDistMap" -"(u_ShadowMap, st + vec2(-1.0/256.0, 1.0/256.0), u_LightRadius);\r\n\tpart " -"+= max(sign(lightDist - dist), 0.0);\r\n\r\n\tdist = sampleDistMap(u_Shadow" -"Map, st + vec2( 1.0/256.0, 1.0/256.0), u_LightRadius);\r\n\tpart += max(si" -"gn(lightDist - dist), 0.0);\r\n\r\n #if defined(USE_DISCARD)\r\n\tif (part " -"<= 0.0)\r\n\t{\r\n\t\tdiscard;\r\n\t}\r\n #endif\r\n\r\n\tintensity *= part" -" * 0.25;\r\n#else\r\n\tdist = sampleDistMap(u_ShadowMap, st, u_LightRadius)" -";\r\n\r\n #if defined(USE_DISCARD)\r\n\tif (lightDist - dist <= 0.0)\r\n\t{" -"\r\n\t\tdiscard;\r\n\t}\r\n #endif\r\n\t\t\t\r\n\t//intensity *= max(sign(2" -"54.0 / 255.0 - dist / u_LightRadius), 0.0);\r\n\tintensity *= max(sign(ligh" -"tDist - dist), 0.0);\r\n#endif\r\n\t\t\r\n\tgl_FragColor.rgb = vec3(0);\r\n" -"\tgl_FragColor.a = clamp(intensity, 0.0, 0.75);\r\n}\r\n"; - -static void GLSL_PrintInfoLog(GLhandleARB object, qboolean developerOnly) -{ - char *msg; - static char msgPart[1024]; - int maxLength = 0; - int i; - - qglGetObjectParameterivARB(object, GL_OBJECT_INFO_LOG_LENGTH_ARB, &maxLength); - - msg = ri.Malloc(maxLength); - - qglGetInfoLogARB(object, maxLength, &maxLength, msg); - - if(developerOnly) - { - ri.Printf(PRINT_DEVELOPER, "compile log:\n"); - } - else - { - ri.Printf(PRINT_ALL, "compile log:\n"); - } - - for(i = 0; i < maxLength; i += 1024) - { - Q_strncpyz(msgPart, msg + i, sizeof(msgPart)); - - if(developerOnly) - ri.Printf(PRINT_DEVELOPER, "%s\n", msgPart); - else - ri.Printf(PRINT_ALL, "%s\n", msgPart); - } - - ri.Free(msg); -} - -static void GLSL_PrintShaderSource(GLhandleARB object) -{ - char *msg; - static char msgPart[1024]; - int maxLength = 0; - int i; - - qglGetObjectParameterivARB(object, GL_OBJECT_SHADER_SOURCE_LENGTH_ARB, &maxLength); - - msg = ri.Malloc(maxLength); - - qglGetShaderSourceARB(object, maxLength, &maxLength, msg); - - for(i = 0; i < maxLength; i += 1024) - { - Q_strncpyz(msgPart, msg + i, sizeof(msgPart)); - ri.Printf(PRINT_ALL, "%s\n", msgPart); - } - - ri.Free(msg); -} - -static void GLSL_GetShaderHeader( GLenum shaderType, const GLcharARB *extra, char *dest, int size ) -{ - float fbufWidthScale, fbufHeightScale; - - dest[0] = '\0'; - - // HACK: abuse the GLSL preprocessor to turn GLSL 1.20 shaders into 1.30 ones - if(0) //(glConfig.driverType == GLDRV_OPENGL3) - { - Q_strcat(dest, size, "#version 130\n"); - - if(shaderType == GL_VERTEX_SHADER_ARB) - { - Q_strcat(dest, size, "#define attribute in\n"); - Q_strcat(dest, size, "#define varying out\n"); - } - else - { - Q_strcat(dest, size, "#define varying in\n"); - - Q_strcat(dest, size, "out vec4 out_Color;\n"); - Q_strcat(dest, size, "#define gl_FragColor out_Color\n"); - } - } - else - { - Q_strcat(dest, size, "#version 120\n"); - } - - // HACK: add some macros to avoid extra uniforms and save speed and code maintenance - //Q_strcat(dest, size, - // va("#ifndef r_SpecularExponent\n#define r_SpecularExponent %f\n#endif\n", r_specularExponent->value)); - //Q_strcat(dest, size, - // va("#ifndef r_SpecularScale\n#define r_SpecularScale %f\n#endif\n", r_specularScale->value)); - //Q_strcat(dest, size, - // va("#ifndef r_NormalScale\n#define r_NormalScale %f\n#endif\n", r_normalScale->value)); - - - Q_strcat(dest, size, "#ifndef M_PI\n#define M_PI 3.14159265358979323846f\n#endif\n"); - - //Q_strcat(dest, size, va("#ifndef MAX_SHADOWMAPS\n#define MAX_SHADOWMAPS %i\n#endif\n", MAX_SHADOWMAPS)); - - Q_strcat(dest, size, - va("#ifndef deformGen_t\n" - "#define deformGen_t\n" - "#define DGEN_WAVE_SIN %i\n" - "#define DGEN_WAVE_SQUARE %i\n" - "#define DGEN_WAVE_TRIANGLE %i\n" - "#define DGEN_WAVE_SAWTOOTH %i\n" - "#define DGEN_WAVE_INVERSE_SAWTOOTH %i\n" - "#define DGEN_BULGE %i\n" - "#define DGEN_MOVE %i\n" - "#endif\n", - DGEN_WAVE_SIN, - DGEN_WAVE_SQUARE, - DGEN_WAVE_TRIANGLE, - DGEN_WAVE_SAWTOOTH, - DGEN_WAVE_INVERSE_SAWTOOTH, - DGEN_BULGE, - DGEN_MOVE)); - - Q_strcat(dest, size, - va("#ifndef tcGen_t\n" - "#define tcGen_t\n" - "#define TCGEN_LIGHTMAP %i\n" - "#define TCGEN_TEXTURE %i\n" - "#define TCGEN_ENVIRONMENT_MAPPED %i\n" - "#define TCGEN_FOG %i\n" - "#define TCGEN_VECTOR %i\n" - "#endif\n", - TCGEN_LIGHTMAP, - TCGEN_TEXTURE, - TCGEN_ENVIRONMENT_MAPPED, - TCGEN_FOG, - TCGEN_VECTOR)); - - Q_strcat(dest, size, - va("#ifndef colorGen_t\n" - "#define colorGen_t\n" - "#define CGEN_LIGHTING_DIFFUSE %i\n" - "#endif\n", - CGEN_LIGHTING_DIFFUSE)); - - Q_strcat(dest, size, - va("#ifndef alphaGen_t\n" - "#define alphaGen_t\n" - "#define AGEN_LIGHTING_SPECULAR %i\n" - "#define AGEN_PORTAL %i\n" - "#define AGEN_FRESNEL %i\n" - "#endif\n", - AGEN_LIGHTING_SPECULAR, - AGEN_PORTAL, - AGEN_FRESNEL)); - - Q_strcat(dest, size, - va("#ifndef alphaTest_t\n" - "#define alphaTest_t\n" - "#define ATEST_GT_0 %i\n" - "#define ATEST_LT_128 %i\n" - "#define ATEST_GE_128 %i\n" - "#endif\n", - ATEST_GT_0, - ATEST_LT_128, - ATEST_GE_128)); - - Q_strcat(dest, size, - va("#ifndef texenv_t\n" - "#define texenv_t\n" - "#define TEXENV_MODULATE %i\n" - "#define TEXENV_ADD %i\n" - "#define TEXENV_REPLACE %i\n" - "#endif\n", - GL_MODULATE, - GL_ADD, - GL_REPLACE)); - - fbufWidthScale = 1.0f / ((float)glConfig.vidWidth); - fbufHeightScale = 1.0f / ((float)glConfig.vidHeight); - Q_strcat(dest, size, - va("#ifndef r_FBufScale\n#define r_FBufScale vec2(%f, %f)\n#endif\n", fbufWidthScale, fbufHeightScale)); - - if (extra) - { - Q_strcat(dest, size, extra); - } - - // OK we added a lot of stuff but if we do something bad in the GLSL shaders then we want the proper line - // so we have to reset the line counting - Q_strcat(dest, size, "#line 0\n"); -} - -static int GLSL_CompileGPUShader(GLhandleARB program, GLhandleARB *prevShader, const GLcharARB *buffer, int size, GLenum shaderType) -{ - GLint compiled; - GLhandleARB shader; - - shader = qglCreateShaderObjectARB(shaderType); - - qglShaderSourceARB(shader, 1, (const GLcharARB **)&buffer, &size); - - // compile shader - qglCompileShaderARB(shader); - - // check if shader compiled - qglGetObjectParameterivARB(shader, GL_OBJECT_COMPILE_STATUS_ARB, &compiled); - if(!compiled) - { - GLSL_PrintShaderSource(shader); - GLSL_PrintInfoLog(shader, qfalse); - ri.Error(ERR_DROP, "Couldn't compile shader"); - return 0; - } - - GLSL_PrintInfoLog(shader, qtrue); - //ri.Printf(PRINT_ALL, "%s\n", GLSL_PrintShaderSource(shader)); - - if (*prevShader) - { - qglDetachObjectARB(program, *prevShader); - qglDeleteObjectARB(*prevShader); - } - - // attach shader to program - qglAttachObjectARB(program, shader); - - *prevShader = shader; - - return 1; -} - - -static void GLSL_DumpText(const char *shaderText, int size, const char *name, GLenum shaderType) -{ - int i, l, inc; - ri.Printf(PRINT_ALL, "static const char *fallback%sShader_%s =\n\"", name, shaderType == GL_VERTEX_SHADER_ARB ? "vp" : "fp"); - l = 0; - - for (i = 0; i < size; i++) - { - switch (shaderText[i]) - { - case '\a': - case '\b': - case '\f': - case '\n': - case '\r': - case '\t': - case '\v': - case '"': - case '\\': - inc = 2; - break; - default: - inc = 1; - break; - } - - l += inc; - - if (l >= 76) - { - ri.Printf(PRINT_ALL, "\"\n\""); - l = inc; - } - - switch (shaderText[i]) - { - case '\a': - ri.Printf(PRINT_ALL, "\\a"); - break; - case '\b': - ri.Printf(PRINT_ALL, "\\b"); - break; - case '\f': - ri.Printf(PRINT_ALL, "\\f"); - break; - case '\n': - ri.Printf(PRINT_ALL, "\\n"); - break; - case '\r': - ri.Printf(PRINT_ALL, "\\r"); - break; - case '\t': - ri.Printf(PRINT_ALL, "\\t"); - break; - case '\v': - ri.Printf(PRINT_ALL, "\\v"); - break; - case '"': - ri.Printf(PRINT_ALL, "\\\""); - break; - case '\\': - ri.Printf(PRINT_ALL, "\\\\"); - break; - default: - ri.Printf(PRINT_ALL, "%c", shaderText[i]); - break; - } - } - ri.Printf(PRINT_ALL, "\";\n\n"); -} - -static int GLSL_LoadGPUShaderText(const char *name, const char *fallback, - GLenum shaderType, char *dest, int destSize, qboolean dump) -{ - char filename[MAX_QPATH]; - GLcharARB *buffer = NULL; - const GLcharARB *shaderText = NULL; - int size; - int result; - - if(shaderType == GL_VERTEX_SHADER_ARB) - { - Com_sprintf(filename, sizeof(filename), "glsl/%s_vp.glsl", name); - } - else - { - Com_sprintf(filename, sizeof(filename), "glsl/%s_fp.glsl", name); - } - - ri.Printf(PRINT_DEVELOPER, "...loading '%s'\n", filename); - size = ri.FS_ReadFile(filename, (void **)&buffer); - if(!buffer) - { - if (fallback) - { - ri.Printf(PRINT_DEVELOPER, "couldn't load, using fallback\n"); - shaderText = fallback; - size = strlen(shaderText); - } - else - { - ri.Printf(PRINT_DEVELOPER, "couldn't load!\n"); - return 0; - } - } - else - { - shaderText = buffer; - } - - if (dump) - GLSL_DumpText(shaderText, size, name, shaderType); - - if (size > destSize) - { - result = 0; - } - else - { - Q_strncpyz(dest, shaderText, size + 1); - result = 1; - } - - if (buffer) - { - ri.FS_FreeFile(buffer); - } - - return result; -} - -static void GLSL_LinkProgram(GLhandleARB program) -{ - GLint linked; - - qglLinkProgramARB(program); - - qglGetObjectParameterivARB(program, GL_OBJECT_LINK_STATUS_ARB, &linked); - if(!linked) - { - GLSL_PrintInfoLog(program, qfalse); - ri.Error(ERR_DROP, "\nshaders failed to link"); - } -} - -static void GLSL_ValidateProgram(GLhandleARB program) -{ - GLint validated; - - qglValidateProgramARB(program); - - qglGetObjectParameterivARB(program, GL_OBJECT_VALIDATE_STATUS_ARB, &validated); - if(!validated) - { - GLSL_PrintInfoLog(program, qfalse); - ri.Error(ERR_DROP, "\nshaders failed to validate"); - } -} - -static void GLSL_ShowProgramUniforms(GLhandleARB program) -{ - int i, count, size; - GLenum type; - char uniformName[1000]; - - // install the executables in the program object as part of current state. - qglUseProgramObjectARB(program); - - // check for GL Errors - - // query the number of active uniforms - qglGetObjectParameterivARB(program, GL_OBJECT_ACTIVE_UNIFORMS_ARB, &count); - - // Loop over each of the active uniforms, and set their value - for(i = 0; i < count; i++) - { - qglGetActiveUniformARB(program, i, sizeof(uniformName), NULL, &size, &type, uniformName); - - ri.Printf(PRINT_DEVELOPER, "active uniform: '%s'\n", uniformName); - } - - qglUseProgramObjectARB(0); -} - -static int GLSL_InitGPUShader2(shaderProgram_t * program, const char *name, int attribs, const char *vpCode, const char *fpCode, int numUniforms) -{ - ri.Printf(PRINT_DEVELOPER, "------- GPU shader -------\n"); - - if(strlen(name) >= MAX_QPATH) - { - ri.Error(ERR_DROP, "GLSL_InitGPUShader2: \"%s\" is too long\n", name); - } - - Q_strncpyz(program->name, name, sizeof(program->name)); - - program->program = qglCreateProgramObjectARB(); - program->attribs = attribs; - - if (!(GLSL_CompileGPUShader(program->program, &program->vertexShader, vpCode, strlen(vpCode), GL_VERTEX_SHADER_ARB))) - { - ri.Printf(PRINT_ALL, "GLSL_InitGPUShader2: Unable to load \"%s\" as GL_VERTEX_SHADER_ARB\n", name); - qglDeleteObjectARB(program->program); - return 0; - } - - if(fpCode) - { - if(!(GLSL_CompileGPUShader(program->program, &program->fragmentShader, fpCode, strlen(fpCode), GL_FRAGMENT_SHADER_ARB))) - { - ri.Printf(PRINT_ALL, "GLSL_InitGPUShader2: Unable to load \"%s\" as GL_FRAGMENT_SHADER_ARB\n", name); - qglDeleteObjectARB(program->program); - return 0; - } - } - - if(attribs & ATTR_POSITION) - qglBindAttribLocationARB(program->program, ATTR_INDEX_POSITION, "attr_Position"); - - if(attribs & ATTR_TEXCOORD) - qglBindAttribLocationARB(program->program, ATTR_INDEX_TEXCOORD0, "attr_TexCoord0"); - - if(attribs & ATTR_LIGHTCOORD) - qglBindAttribLocationARB(program->program, ATTR_INDEX_TEXCOORD1, "attr_TexCoord1"); - -// if(attribs & ATTR_TEXCOORD2) -// qglBindAttribLocationARB(program->program, ATTR_INDEX_TEXCOORD2, "attr_TexCoord2"); - -// if(attribs & ATTR_TEXCOORD3) -// qglBindAttribLocationARB(program->program, ATTR_INDEX_TEXCOORD3, "attr_TexCoord3"); - - if(attribs & ATTR_TANGENT) - qglBindAttribLocationARB(program->program, ATTR_INDEX_TANGENT, "attr_Tangent"); - - if(attribs & ATTR_BITANGENT) - qglBindAttribLocationARB(program->program, ATTR_INDEX_BITANGENT, "attr_Bitangent"); - - if(attribs & ATTR_NORMAL) - qglBindAttribLocationARB(program->program, ATTR_INDEX_NORMAL, "attr_Normal"); - - if(attribs & ATTR_COLOR) - qglBindAttribLocationARB(program->program, ATTR_INDEX_COLOR, "attr_Color"); - - if(attribs & ATTR_PAINTCOLOR) - qglBindAttribLocationARB(program->program, ATTR_INDEX_PAINTCOLOR, "attr_PaintColor"); - - if(attribs & ATTR_LIGHTDIRECTION) - qglBindAttribLocationARB(program->program, ATTR_INDEX_LIGHTDIRECTION, "attr_LightDirection"); - - if(attribs & ATTR_POSITION2) - qglBindAttribLocationARB(program->program, ATTR_INDEX_POSITION2, "attr_Position2"); - - if(attribs & ATTR_NORMAL2) - qglBindAttribLocationARB(program->program, ATTR_INDEX_NORMAL2, "attr_Normal2"); - - if(attribs & ATTR_TANGENT2) - qglBindAttribLocationARB(program->program, ATTR_INDEX_TANGENT2, "attr_Tangent2"); - - if(attribs & ATTR_BITANGENT2) - qglBindAttribLocationARB(program->program, ATTR_INDEX_BITANGENT2, "attr_Bitangent2"); - - GLSL_LinkProgram(program->program); - - program->numUniforms = numUniforms; - - { - int i, size; - - size = sizeof(*program->uniforms) * numUniforms; - program->uniforms = ri.Malloc(size); - for (i = 0; i < numUniforms; i++) - { - program->uniforms[i] = -1; - } - - size = sizeof(*program->uniformTypes) * numUniforms; - program->uniformTypes = ri.Malloc(size); - memset(program->uniformTypes, 0, size); - - size = sizeof(*program->uniformBufferOffsets) * numUniforms; - program->uniformBufferOffsets = ri.Malloc(size); - memset(program->uniformBufferOffsets, 0, size); - } - - return 1; -} - -static int GLSL_InitGPUShader(shaderProgram_t * program, const char *name, - int attribs, qboolean fragmentShader, const GLcharARB *extra, qboolean addHeader, - const char *fallback_vp, const char *fallback_fp, int numUniforms) -{ - char vpCode[32000]; - char fpCode[32000]; - char *postHeader; - int size; - int result; - - size = sizeof(vpCode); - if (addHeader) - { - GLSL_GetShaderHeader(GL_VERTEX_SHADER_ARB, extra, vpCode, size); - postHeader = &vpCode[strlen(vpCode)]; - size -= strlen(vpCode); - } - else - { - postHeader = &vpCode[0]; - } - - if (!GLSL_LoadGPUShaderText(name, fallback_vp, GL_VERTEX_SHADER_ARB, postHeader, size, qfalse)) - { - return 0; - } - - if (fragmentShader) - { - size = sizeof(fpCode); - if (addHeader) - { - GLSL_GetShaderHeader(GL_FRAGMENT_SHADER_ARB, extra, fpCode, size); - postHeader = &fpCode[strlen(fpCode)]; - size -= strlen(fpCode); - } - else - { - postHeader = &fpCode[0]; - } - - if (!GLSL_LoadGPUShaderText(name, fallback_fp, GL_FRAGMENT_SHADER_ARB, postHeader, size, qfalse)) - { - return 0; - } - } - - result = GLSL_InitGPUShader2(program, name, attribs, vpCode, fragmentShader ? fpCode : NULL, numUniforms); - - return result; -} - -// intentionally deceiving the user here, not actually setting the names but getting their indexes. -void GLSL_AddUniform(shaderProgram_t *program, int uniformNum, const char *name, int type) -{ - GLint *uniforms = program->uniforms; - - uniforms[uniformNum] = qglGetUniformLocationARB(program->program, name); - program->uniformTypes[uniformNum] = type; -} - -void GLSL_FinishGPUShader(shaderProgram_t *program) -{ - if (program->numUniforms) - { - int i, size; - - size = 0; - for (i = 0; i < program->numUniforms; i++) - { - if (program->uniforms[i] != -1) - { - program->uniformBufferOffsets[i] = size; - - switch(program->uniformTypes[i]) - { - case GLSL_INT: - size += sizeof(GLint); - break; - case GLSL_FLOAT: - size += sizeof(GLfloat); - break; - case GLSL_FLOAT5: - size += sizeof(vec_t) * 5; - break; - case GLSL_VEC2: - size += sizeof(vec_t) * 2; - break; - case GLSL_VEC3: - size += sizeof(vec_t) * 3; - break; - case GLSL_VEC4: - size += sizeof(vec_t) * 4; - break; - case GLSL_MAT16: - size += sizeof(vec_t) * 16; - break; - default: - break; - } - } - } - - program->uniformBuffer = ri.Malloc(size); - - } - - GLSL_ValidateProgram(program->program); - GLSL_ShowProgramUniforms(program->program); - GL_CheckErrors(); -} - -void GLSL_SetUniformInt(shaderProgram_t *program, int uniformNum, GLint value) -{ - GLint *uniforms = program->uniforms; - GLint *compare = (GLint *)(program->uniformBuffer + program->uniformBufferOffsets[uniformNum]); - - if (uniforms[uniformNum] == -1) - return; - - if (program->uniformTypes[uniformNum] != GLSL_INT) - { - ri.Printf( PRINT_WARNING, "GLSL_SetUniformInt: wrong type for uniform %i in program %s\n", uniformNum, program->name); - return; - } - - if (value == *compare) - { - return; - } - - *compare = value; - - qglUniform1iARB(uniforms[uniformNum], value); -} - -void GLSL_SetUniformFloat(shaderProgram_t *program, int uniformNum, GLfloat value) -{ - GLint *uniforms = program->uniforms; - GLfloat *compare = (GLfloat *)(program->uniformBuffer + program->uniformBufferOffsets[uniformNum]); - - if (uniforms[uniformNum] == -1) - return; - - if (program->uniformTypes[uniformNum] != GLSL_FLOAT) - { - ri.Printf( PRINT_WARNING, "GLSL_SetUniformFloat: wrong type for uniform %i in program %s\n", uniformNum, program->name); - return; - } - - if (value == *compare) - { - return; - } - - *compare = value; - - qglUniform1fARB(uniforms[uniformNum], value); -} - -void GLSL_SetUniformVec2(shaderProgram_t *program, int uniformNum, const vec2_t v) -{ - GLint *uniforms = program->uniforms; - vec_t *compare = (float *)(program->uniformBuffer + program->uniformBufferOffsets[uniformNum]); - - if (uniforms[uniformNum] == -1) - return; - - if (program->uniformTypes[uniformNum] != GLSL_VEC2) - { - ri.Printf( PRINT_WARNING, "GLSL_SetUniformVec2: wrong type for uniform %i in program %s\n", uniformNum, program->name); - return; - } - - if (v[0] == compare[0] && v[1] == compare[1]) - { - return; - } - - compare[0] = v[0]; - compare[1] = v[1]; - - qglUniform2fARB(uniforms[uniformNum], v[0], v[1]); -} - -void GLSL_SetUniformVec3(shaderProgram_t *program, int uniformNum, const vec3_t v) -{ - GLint *uniforms = program->uniforms; - vec_t *compare = (float *)(program->uniformBuffer + program->uniformBufferOffsets[uniformNum]); - - if (uniforms[uniformNum] == -1) - return; - - if (program->uniformTypes[uniformNum] != GLSL_VEC3) - { - ri.Printf( PRINT_WARNING, "GLSL_SetUniformVec3: wrong type for uniform %i in program %s\n", uniformNum, program->name); - return; - } - - if (VectorCompare(v, compare)) - { - return; - } - - VectorCopy(v, compare); - - qglUniform3fARB(uniforms[uniformNum], v[0], v[1], v[2]); -} - -void GLSL_SetUniformVec4(shaderProgram_t *program, int uniformNum, const vec4_t v) -{ - GLint *uniforms = program->uniforms; - vec_t *compare = (float *)(program->uniformBuffer + program->uniformBufferOffsets[uniformNum]); - - if (uniforms[uniformNum] == -1) - return; - - if (program->uniformTypes[uniformNum] != GLSL_VEC4) - { - ri.Printf( PRINT_WARNING, "GLSL_SetUniformVec4: wrong type for uniform %i in program %s\n", uniformNum, program->name); - return; - } - - if (VectorCompare4(v, compare)) - { - return; - } - - VectorCopy4(v, compare); - - qglUniform4fARB(uniforms[uniformNum], v[0], v[1], v[2], v[3]); -} - -void GLSL_SetUniformFloat5(shaderProgram_t *program, int uniformNum, const vec5_t v) -{ - GLint *uniforms = program->uniforms; - vec_t *compare = (float *)(program->uniformBuffer + program->uniformBufferOffsets[uniformNum]); - - if (uniforms[uniformNum] == -1) - { - ri.Printf( PRINT_ALL, "well shit.\n"); - return; - } - - if (program->uniformTypes[uniformNum] != GLSL_FLOAT5) - { - ri.Printf( PRINT_WARNING, "GLSL_SetUniformFloat5: wrong type for uniform %i in program %s\n", uniformNum, program->name); - return; - } - - if (VectorCompare5(v, compare)) - { - return; - } - - VectorCopy5(v, compare); - - qglUniform1fvARB(uniforms[uniformNum], 5, v); -} - -void GLSL_SetUniformMatrix16(shaderProgram_t *program, int uniformNum, const matrix_t matrix) -{ - GLint *uniforms = program->uniforms; - vec_t *compare = (float *)(program->uniformBuffer + program->uniformBufferOffsets[uniformNum]); - - if (uniforms[uniformNum] == -1) - return; - - if (program->uniformTypes[uniformNum] != GLSL_MAT16) - { - ri.Printf( PRINT_WARNING, "GLSL_SetUniformMatrix16: wrong type for uniform %i in program %s\n", uniformNum, program->name); - return; - } - - if (Matrix16Compare(matrix, compare)) - { - return; - } - - Matrix16Copy(matrix, compare); - - qglUniformMatrix4fvARB(uniforms[uniformNum], 1, GL_FALSE, matrix); -} - -void GLSL_DeleteGPUShader(shaderProgram_t *program) -{ - if(program->program) - { - if (program->vertexShader) - { - qglDetachObjectARB(program->program, program->vertexShader); - qglDeleteObjectARB(program->vertexShader); - } - - if (program->fragmentShader) - { - qglDetachObjectARB(program->program, program->fragmentShader); - qglDeleteObjectARB(program->fragmentShader); - } - - qglDeleteObjectARB(program->program); - - if (program->uniforms) - { - ri.Free(program->uniforms); - } - - if (program->uniformTypes) - { - ri.Free(program->uniformTypes); - } - - if (program->uniformBuffer) - { - ri.Free(program->uniformBuffer); - } - - if (program->uniformBufferOffsets) - { - ri.Free(program->uniformBufferOffsets); - } - - Com_Memset(program, 0, sizeof(*program)); - } -} - -void GLSL_InitGPUShaders(void) -{ - int startTime, endTime; - int i; - char extradefines[1024]; - int attribs; - int numGenShaders = 0, numLightShaders = 0, numEtcShaders = 0; - - ri.Printf(PRINT_ALL, "------- GLSL_InitGPUShaders -------\n"); - - // make sure the render thread is stopped - R_SyncRenderThread(); - - startTime = ri.Milliseconds(); - - for (i = 0; i < GENERICDEF_COUNT; i++) - { - attribs = ATTR_POSITION | ATTR_TEXCOORD | ATTR_LIGHTCOORD | ATTR_NORMAL | ATTR_COLOR; - extradefines[0] = '\0'; - - if (i & GENERICDEF_USE_DEFORM_VERTEXES) - Q_strcat(extradefines, 1024, "#define USE_DEFORM_VERTEXES\n"); - - if (i & GENERICDEF_USE_TCGEN) - Q_strcat(extradefines, 1024, "#define USE_TCGEN\n"); - - if (i & GENERICDEF_USE_VERTEX_ANIMATION) - { - Q_strcat(extradefines, 1024, "#define USE_VERTEX_ANIMATION\n"); - attribs |= ATTR_POSITION2 | ATTR_NORMAL2; - } - - if (i & GENERICDEF_USE_FOG) - Q_strcat(extradefines, 1024, "#define USE_FOG\n"); - - if (i & GENERICDEF_USE_RGBAGEN) - Q_strcat(extradefines, 1024, "#define USE_RGBAGEN\n"); - - if (i & GENERICDEF_USE_LIGHTMAP) - Q_strcat(extradefines, 1024, "#define USE_LIGHTMAP\n"); - - - if (!GLSL_InitGPUShader(&tr.genericShader[i], "generic", attribs, qtrue, extradefines, qtrue, fallbackGenericShader_vp, fallbackGenericShader_fp, GENERIC_UNIFORM_COUNT)) - { - ri.Error(ERR_FATAL, "Could not load generic shader!\n"); - } - - // There's actually no need to filter these out, since they'll - // redirect to -1 if nonexistent, but it's more understandable this way. - - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_MODELVIEWPROJECTIONMATRIX, "u_ModelViewProjectionMatrix", GLSL_MAT16); - - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_BASECOLOR, "u_BaseColor", GLSL_VEC4); - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_VERTCOLOR, "u_VertColor", GLSL_VEC4); - - if (i & GENERICDEF_USE_RGBAGEN) - { - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_COLORGEN, "u_ColorGen", GLSL_INT); - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_ALPHAGEN, "u_AlphaGen", GLSL_INT); - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_AMBIENTLIGHT, "u_AmbientLight", GLSL_VEC3); - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_DIRECTEDLIGHT, "u_DirectedLight", GLSL_VEC3); - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_LIGHTORIGIN, "u_LightOrigin", GLSL_VEC4); - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_PORTALRANGE, "u_PortalRange", GLSL_FLOAT); - } - - if (i & GENERICDEF_USE_TCGEN) - { - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_TCGEN0, "u_TCGen0", GLSL_INT); - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_TCGEN0VECTOR0, "u_TCGen0Vector0", GLSL_VEC3); - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_TCGEN0VECTOR1, "u_TCGen0Vector1", GLSL_VEC3); - } - - if (i & GENERICDEF_USE_FOG) - { - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_FOGCOLORMASK, "u_FogColorMask", GLSL_VEC4); - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_FOGDISTANCE, "u_FogDistance", GLSL_VEC4); - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_FOGDEPTH, "u_FogDepth", GLSL_VEC4); - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_FOGEYET, "u_FogEyeT", GLSL_FLOAT); - } - - if (i & GENERICDEF_USE_DEFORM_VERTEXES) - { - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_DEFORMGEN, "u_DeformGen", GLSL_INT); - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_DEFORMPARAMS, "u_DeformParams", GLSL_FLOAT5); - } - - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_TIME, "u_Time", GLSL_FLOAT); - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_VIEWORIGIN, "u_ViewOrigin", GLSL_VEC3); - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_DIFFUSETEXMATRIX, "u_DiffuseTexMatrix", GLSL_MAT16); - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_TEXTURE1ENV, "u_Texture1Env", GLSL_INT); - - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_DIFFUSEMAP, "u_DiffuseMap", GLSL_INT); - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_LIGHTMAP, "u_LightMap", GLSL_INT); - - - if (i & GENERICDEF_USE_VERTEX_ANIMATION) - { - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_VERTEXLERP, "u_VertexLerp", GLSL_FLOAT); - } - - GLSL_FinishGPUShader(&tr.genericShader[i]); - - qglUseProgramObjectARB(tr.genericShader[i].program); - GLSL_SetUniformInt(&tr.genericShader[i], GENERIC_UNIFORM_DIFFUSEMAP, TB_DIFFUSEMAP); - GLSL_SetUniformInt(&tr.genericShader[i], GENERIC_UNIFORM_LIGHTMAP, TB_LIGHTMAP); - qglUseProgramObjectARB(0); - - numGenShaders++; - } - - - attribs = ATTR_POSITION | ATTR_TEXCOORD; - - if (!GLSL_InitGPUShader(&tr.textureColorShader, "texturecolor", attribs, qtrue, NULL, qfalse, fallbackTextureColorShader_vp, fallbackTextureColorShader_fp, TEXTURECOLOR_UNIFORM_COUNT)) - { - ri.Error(ERR_FATAL, "Could not load texturecolor shader!\n"); - } - - GLSL_AddUniform(&tr.textureColorShader, TEXTURECOLOR_UNIFORM_MODELVIEWPROJECTIONMATRIX, "u_ModelViewProjectionMatrix", GLSL_MAT16); - GLSL_AddUniform(&tr.textureColorShader, TEXTURECOLOR_UNIFORM_COLOR, "u_Color", GLSL_VEC4); - GLSL_AddUniform(&tr.textureColorShader, TEXTURECOLOR_UNIFORM_DIFFUSEMAP, "u_DiffuseMap", GLSL_INT); - - GLSL_FinishGPUShader(&tr.textureColorShader); - - qglUseProgramObjectARB(tr.textureColorShader.program); - GLSL_SetUniformInt(&tr.textureColorShader, TEXTURECOLOR_UNIFORM_DIFFUSEMAP, TB_DIFFUSEMAP); - qglUseProgramObjectARB(0); - - numEtcShaders++; - - - attribs = ATTR_POSITION | ATTR_POSITION2 | ATTR_NORMAL | ATTR_NORMAL2 | ATTR_TEXCOORD; - - if (!GLSL_InitGPUShader(&tr.fogShader, "fogpass", attribs, qtrue, NULL, qtrue, fallbackFogPassShader_vp, fallbackFogPassShader_fp, FOGPASS_UNIFORM_COUNT)) - { - ri.Error(ERR_FATAL, "Could not load fogpass shader!\n"); - } - - GLSL_AddUniform(&tr.fogShader, FOGPASS_UNIFORM_FOGDISTANCE, "u_FogDistance", GLSL_VEC4); - GLSL_AddUniform(&tr.fogShader, FOGPASS_UNIFORM_FOGDEPTH, "u_FogDepth", GLSL_VEC4); - GLSL_AddUniform(&tr.fogShader, FOGPASS_UNIFORM_FOGEYET, "u_FogEyeT", GLSL_FLOAT); - GLSL_AddUniform(&tr.fogShader, FOGPASS_UNIFORM_DEFORMGEN, "u_DeformGen", GLSL_INT); - GLSL_AddUniform(&tr.fogShader, FOGPASS_UNIFORM_DEFORMPARAMS, "u_DeformParams", GLSL_FLOAT5); - GLSL_AddUniform(&tr.fogShader, FOGPASS_UNIFORM_TIME, "u_Time", GLSL_FLOAT); - GLSL_AddUniform(&tr.fogShader, FOGPASS_UNIFORM_COLOR, "u_Color", GLSL_VEC4); - GLSL_AddUniform(&tr.fogShader, FOGPASS_UNIFORM_MODELVIEWPROJECTIONMATRIX, "u_ModelViewProjectionMatrix", GLSL_MAT16); - GLSL_AddUniform(&tr.fogShader, FOGPASS_UNIFORM_VERTEXLERP, "u_VertexLerp", GLSL_FLOAT); - - GLSL_FinishGPUShader(&tr.fogShader); - - numEtcShaders++; - - - attribs = ATTR_POSITION | ATTR_NORMAL | ATTR_TEXCOORD; - - if (!GLSL_InitGPUShader(&tr.dlightallShader, "dlight", attribs, qtrue, NULL, qtrue, fallbackDlightShader_vp, fallbackDlightShader_fp, DLIGHT_UNIFORM_COUNT)) - { - ri.Error(ERR_FATAL, "Could not load dlight shader!\n"); - } - - GLSL_AddUniform(&tr.dlightallShader, DLIGHT_UNIFORM_DLIGHTINFO, "u_DlightInfo", GLSL_VEC4); - GLSL_AddUniform(&tr.dlightallShader, DLIGHT_UNIFORM_DEFORMGEN, "u_DeformGen", GLSL_INT); - GLSL_AddUniform(&tr.dlightallShader, DLIGHT_UNIFORM_DEFORMPARAMS, "u_DeformParams", GLSL_FLOAT5); - GLSL_AddUniform(&tr.dlightallShader, DLIGHT_UNIFORM_TIME, "u_Time", GLSL_FLOAT); - GLSL_AddUniform(&tr.dlightallShader, DLIGHT_UNIFORM_COLOR, "u_Color", GLSL_VEC4); - GLSL_AddUniform(&tr.dlightallShader, DLIGHT_UNIFORM_MODELVIEWPROJECTIONMATRIX, "u_ModelViewProjectionMatrix", GLSL_MAT16); - - GLSL_FinishGPUShader(&tr.dlightallShader); - - qglUseProgramObjectARB(tr.dlightallShader.program); - GLSL_SetUniformInt(&tr.dlightallShader, DLIGHT_UNIFORM_DIFFUSEMAP, TB_DIFFUSEMAP); - qglUseProgramObjectARB(0); - - numEtcShaders++; - - - for (i = 0; i < LIGHTDEF_COUNT; i++) - { - // skip impossible combos - if (!(i & LIGHTDEF_USE_LIGHTMAP) && (i & LIGHTDEF_USE_DELUXEMAP)) - continue; - - if (!(i & LIGHTDEF_USE_NORMALMAP) && (i & LIGHTDEF_USE_PARALLAXMAP)) - continue; -#if 0 - if ((i & LIGHTDEF_USE_LIGHTMAP) && (i & LIGHTDEF_ENTITY)) - continue; - - if ((i & LIGHTDEF_USE_DELUXEMAP) && (i & LIGHTDEF_ENTITY)) - continue; -#endif - if ((i & LIGHTDEF_USE_LIGHTMAP) && (i & LIGHTDEF_USE_LIGHT_VECTOR)) - continue; - - if ((i & LIGHTDEF_USE_DELUXEMAP) && (i & LIGHTDEF_USE_LIGHT_VECTOR)) - continue; - - attribs = ATTR_POSITION | ATTR_TEXCOORD | ATTR_COLOR | ATTR_NORMAL; - extradefines[0] = '\0'; - - if (r_normalAmbient->value > 0.003f) - Q_strcat(extradefines, 1024, va("#define r_normalAmbient %f\n", r_normalAmbient->value)); - - if (r_dlightMode->integer >= 2) - Q_strcat(extradefines, 1024, "#define USE_SHADOWMAP\n"); - - if (i & LIGHTDEF_USE_LIGHTMAP) - { - Q_strcat(extradefines, 1024, "#define USE_LIGHTMAP\n"); - attribs |= ATTR_LIGHTCOORD; - } - - if (i & LIGHTDEF_USE_LIGHT_VECTOR) - { - Q_strcat(extradefines, 1024, "#define USE_LIGHT_VECTOR\n"); - } - - if (i & LIGHTDEF_USE_NORMALMAP && r_normalMapping->integer) - { - Q_strcat(extradefines, 1024, "#define USE_NORMALMAP\n"); - attribs |= ATTR_TANGENT | ATTR_BITANGENT; - } - - if (i & LIGHTDEF_USE_SPECULARMAP && r_specularMapping->integer) - Q_strcat(extradefines, 1024, "#define USE_SPECULARMAP\n"); - - if (i & LIGHTDEF_USE_DELUXEMAP && r_deluxeMapping->integer) - { - Q_strcat(extradefines, 1024, "#define USE_DELUXEMAP\n"); - - if (r_deluxeMapping->integer == 2 && i & LIGHTDEF_USE_NORMALMAP) - { - Q_strcat(extradefines, 1024, "#define DELUXEMAP_IS_LOCAL\n"); - } - } - - if (i & LIGHTDEF_USE_PARALLAXMAP && !(i & LIGHTDEF_ENTITY) && r_parallaxMapping->integer) - Q_strcat(extradefines, 1024, "#define USE_PARALLAXMAP\n"); - - if (i & LIGHTDEF_TCGEN_ENVIRONMENT) - Q_strcat(extradefines, 1024, "#define TCGEN_ENVIRONMENT\n"); - - if (i & LIGHTDEF_ENTITY) - { - Q_strcat(extradefines, 1024, "#define USE_VERTEX_ANIMATION\n#define USE_MODELMATRIX\n"); - attribs |= ATTR_POSITION2 | ATTR_NORMAL2; - - if (i & LIGHTDEF_USE_NORMALMAP && r_normalMapping->integer) - { - attribs |= ATTR_TANGENT2 | ATTR_BITANGENT2; - } - } - - if (!GLSL_InitGPUShader(&tr.lightallShader[i], "lightall", attribs, qtrue, extradefines, qtrue, fallbackLightallShader_vp, fallbackLightallShader_fp, GENERIC_UNIFORM_COUNT)) - { - ri.Error(ERR_FATAL, "Could not load lightall shader!\n"); - } - - GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_MODELVIEWPROJECTIONMATRIX, "u_ModelViewProjectionMatrix", GLSL_MAT16); - GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_MODELMATRIX, "u_ModelMatrix", GLSL_MAT16); - GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_DIFFUSETEXMATRIX, "u_DiffuseTexMatrix", GLSL_MAT16); - //GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_NORMALTEXMATRIX, "u_NormalTexMatrix", GLSL_MAT16); - //GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_SPECULARTEXMATRIX, "u_SpecularTexMatrix", GLSL_MAT16); - GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_VIEWORIGIN, "u_ViewOrigin", GLSL_VEC3); - - GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_DIFFUSEMAP, "u_DiffuseMap", GLSL_INT); - GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_LIGHTMAP, "u_LightMap", GLSL_INT); - GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_NORMALMAP, "u_NormalMap", GLSL_INT); - GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_DELUXEMAP, "u_DeluxeMap", GLSL_INT); - GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_SPECULARMAP, "u_SpecularMap", GLSL_INT); - GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_SHADOWMAP, "u_ShadowMap", GLSL_INT); - - GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_AMBIENTLIGHT, "u_AmbientLight", GLSL_VEC3); - GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_DIRECTEDLIGHT, "u_DirectedLight", GLSL_VEC3); - GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_LIGHTORIGIN, "u_LightOrigin", GLSL_VEC4); - GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_LIGHTRADIUS, "u_LightRadius", GLSL_FLOAT); - - GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_SPECULARREFLECTANCE, "u_SpecularReflectance", GLSL_FLOAT); - - GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_BASECOLOR, "u_BaseColor", GLSL_VEC4); - GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_VERTCOLOR, "u_VertColor", GLSL_VEC4); - GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_VERTEXLERP, "u_VertexLerp", GLSL_FLOAT); - - GLSL_FinishGPUShader(&tr.lightallShader[i]); - - qglUseProgramObjectARB(tr.lightallShader[i].program); - GLSL_SetUniformInt(&tr.lightallShader[i], GENERIC_UNIFORM_DIFFUSEMAP, TB_DIFFUSEMAP); - GLSL_SetUniformInt(&tr.lightallShader[i], GENERIC_UNIFORM_LIGHTMAP, TB_LIGHTMAP); - GLSL_SetUniformInt(&tr.lightallShader[i], GENERIC_UNIFORM_NORMALMAP, TB_NORMALMAP); - GLSL_SetUniformInt(&tr.lightallShader[i], GENERIC_UNIFORM_DELUXEMAP, TB_DELUXEMAP); - GLSL_SetUniformInt(&tr.lightallShader[i], GENERIC_UNIFORM_SPECULARMAP, TB_SPECULARMAP); - GLSL_SetUniformInt(&tr.lightallShader[i], GENERIC_UNIFORM_SHADOWMAP, TB_SHADOWMAP); - qglUseProgramObjectARB(0); - - numLightShaders++; - } - - - attribs = ATTR_POSITION | ATTR_POSITION2 | ATTR_NORMAL | ATTR_NORMAL2 | ATTR_TEXCOORD; - - if (!GLSL_InitGPUShader(&tr.shadowmapShader, "shadowfill", attribs, qtrue, NULL, qtrue, fallbackShadowfillShader_vp, fallbackShadowfillShader_fp, GENERIC_UNIFORM_COUNT)) - { - ri.Error(ERR_FATAL, "Could not load depth shader!\n"); - } - - GLSL_AddUniform(&tr.shadowmapShader, GENERIC_UNIFORM_DEFORMGEN, "u_DeformGen", GLSL_INT); - GLSL_AddUniform(&tr.shadowmapShader, GENERIC_UNIFORM_DEFORMPARAMS, "u_DeformParams", GLSL_FLOAT5); - GLSL_AddUniform(&tr.shadowmapShader, GENERIC_UNIFORM_TIME, "u_Time", GLSL_FLOAT); - GLSL_AddUniform(&tr.shadowmapShader, GENERIC_UNIFORM_MODELVIEWPROJECTIONMATRIX, "u_ModelViewProjectionMatrix", GLSL_MAT16); - GLSL_AddUniform(&tr.shadowmapShader, GENERIC_UNIFORM_MODELMATRIX, "u_ModelMatrix", GLSL_MAT16); - GLSL_AddUniform(&tr.shadowmapShader, GENERIC_UNIFORM_VERTEXLERP, "u_VertexLerp", GLSL_FLOAT); - - GLSL_AddUniform(&tr.shadowmapShader, GENERIC_UNIFORM_LIGHTORIGIN, "u_LightOrigin", GLSL_VEC4); - GLSL_AddUniform(&tr.shadowmapShader, GENERIC_UNIFORM_LIGHTRADIUS, "u_LightRadius", GLSL_FLOAT); - - GLSL_FinishGPUShader(&tr.shadowmapShader); - - numEtcShaders++; - - - attribs = ATTR_POSITION | ATTR_NORMAL; - extradefines[0] = '\0'; - - Q_strcat(extradefines, 1024, "#define USE_PCF\n#define USE_DISCARD"); - - if (!GLSL_InitGPUShader(&tr.pshadowShader, "pshadow", attribs, qtrue, extradefines, qtrue, fallbackPshadowShader_vp, fallbackPshadowShader_fp, PSHADOW_UNIFORM_COUNT)) - { - ri.Error(ERR_FATAL, "Could not load pshadow shader!\n"); - } - - GLSL_AddUniform(&tr.pshadowShader, PSHADOW_UNIFORM_MODELVIEWPROJECTIONMATRIX, "u_ModelViewProjectionMatrix", GLSL_MAT16); - GLSL_AddUniform(&tr.pshadowShader, PSHADOW_UNIFORM_LIGHTFORWARD, "u_LightForward", GLSL_VEC3); - GLSL_AddUniform(&tr.pshadowShader, PSHADOW_UNIFORM_LIGHTUP, "u_LightUp", GLSL_VEC3); - GLSL_AddUniform(&tr.pshadowShader, PSHADOW_UNIFORM_LIGHTRIGHT, "u_LightRight", GLSL_VEC3); - GLSL_AddUniform(&tr.pshadowShader, PSHADOW_UNIFORM_LIGHTORIGIN, "u_LightOrigin", GLSL_VEC4); - GLSL_AddUniform(&tr.pshadowShader, PSHADOW_UNIFORM_LIGHTRADIUS, "u_LightRadius", GLSL_FLOAT); - - GLSL_FinishGPUShader(&tr.pshadowShader); - - qglUseProgramObjectARB(tr.pshadowShader.program); - GLSL_SetUniformInt(&tr.pshadowShader, PSHADOW_UNIFORM_SHADOWMAP, TB_DIFFUSEMAP); - qglUseProgramObjectARB(0); - - numEtcShaders++; - - endTime = ri.Milliseconds(); - - ri.Printf(PRINT_ALL, "loaded %i GLSL shaders (%i gen %i light %i etc) in %5.2f seconds\n", - numGenShaders + numLightShaders + numEtcShaders, numGenShaders, numLightShaders, - numEtcShaders, (endTime - startTime) / 1000.0); - - if (0) - { - GLSL_LoadGPUShaderText("Generic", NULL, GL_VERTEX_SHADER_ARB, NULL, 0, qtrue); - GLSL_LoadGPUShaderText("Generic", NULL, GL_FRAGMENT_SHADER_ARB, NULL, 0, qtrue); - - GLSL_LoadGPUShaderText("TextureColor", NULL, GL_VERTEX_SHADER_ARB, NULL, 0, qtrue); - GLSL_LoadGPUShaderText("TextureColor", NULL, GL_FRAGMENT_SHADER_ARB, NULL, 0, qtrue); - - GLSL_LoadGPUShaderText("FogPass", NULL, GL_VERTEX_SHADER_ARB, NULL, 0, qtrue); - GLSL_LoadGPUShaderText("FogPass", NULL, GL_FRAGMENT_SHADER_ARB, NULL, 0, qtrue); - - GLSL_LoadGPUShaderText("Dlight", NULL, GL_VERTEX_SHADER_ARB, NULL, 0, qtrue); - GLSL_LoadGPUShaderText("Dlight", NULL, GL_FRAGMENT_SHADER_ARB, NULL, 0, qtrue); - - GLSL_LoadGPUShaderText("Lightall", NULL, GL_VERTEX_SHADER_ARB, NULL, 0, qtrue); - GLSL_LoadGPUShaderText("Lightall", NULL, GL_FRAGMENT_SHADER_ARB, NULL, 0, qtrue); - - GLSL_LoadGPUShaderText("Shadowfill", NULL, GL_VERTEX_SHADER_ARB, NULL, 0, qtrue); - GLSL_LoadGPUShaderText("Shadowfill", NULL, GL_FRAGMENT_SHADER_ARB, NULL, 0, qtrue); - - GLSL_LoadGPUShaderText("Pshadow", NULL, GL_VERTEX_SHADER_ARB, NULL, 0, qtrue); - GLSL_LoadGPUShaderText("Pshadow", NULL, GL_FRAGMENT_SHADER_ARB, NULL, 0, qtrue); - } - -} - -void GLSL_ShutdownGPUShaders(void) -{ - int i; - - ri.Printf(PRINT_ALL, "------- GLSL_ShutdownGPUShaders -------\n"); - - qglDisableVertexAttribArrayARB(ATTR_INDEX_TEXCOORD0); - qglDisableVertexAttribArrayARB(ATTR_INDEX_TEXCOORD1); - qglDisableVertexAttribArrayARB(ATTR_INDEX_POSITION); - qglDisableVertexAttribArrayARB(ATTR_INDEX_POSITION2); - qglDisableVertexAttribArrayARB(ATTR_INDEX_NORMAL); - qglDisableVertexAttribArrayARB(ATTR_INDEX_TANGENT); - qglDisableVertexAttribArrayARB(ATTR_INDEX_BITANGENT); - qglDisableVertexAttribArrayARB(ATTR_INDEX_NORMAL2); - qglDisableVertexAttribArrayARB(ATTR_INDEX_TANGENT2); - qglDisableVertexAttribArrayARB(ATTR_INDEX_BITANGENT2); - qglDisableVertexAttribArrayARB(ATTR_INDEX_COLOR); - GLSL_BindNullProgram(); - - for ( i = 0; i < GENERICDEF_COUNT; i++) - { - GLSL_DeleteGPUShader(&tr.genericShader[i]); - } - - GLSL_DeleteGPUShader(&tr.textureColorShader); - GLSL_DeleteGPUShader(&tr.fogShader); - GLSL_DeleteGPUShader(&tr.dlightallShader); - - for ( i = 0; i < LIGHTDEF_COUNT; i++) - { - GLSL_DeleteGPUShader(&tr.lightallShader[i]); - } - - GLSL_DeleteGPUShader(&tr.shadowmapShader); - GLSL_DeleteGPUShader(&tr.pshadowShader); - - glState.currentProgram = 0; - qglUseProgramObjectARB(0); -} - - -void GLSL_BindProgram(shaderProgram_t * program) -{ - if(!program) - { - GLSL_BindNullProgram(); - return; - } - - if(r_logFile->integer) - { - // don't just call LogComment, or we will get a call to va() every frame! - GLimp_LogComment(va("--- GL_BindProgram( %s ) ---\n", program->name)); - } - - if(glState.currentProgram != program) - { - qglUseProgramObjectARB(program->program); - glState.currentProgram = program; - backEnd.pc.c_glslShaderBinds++; - } -} - - -void GLSL_BindNullProgram(void) -{ - if(r_logFile->integer) - { - GLimp_LogComment("--- GL_BindNullProgram ---\n"); - } - - if(glState.currentProgram) - { - qglUseProgramObjectARB(0); - glState.currentProgram = NULL; - } -} - - -void GLSL_VertexAttribsState(uint32_t stateBits) -{ - uint32_t diff; - - GLSL_VertexAttribPointers(stateBits); - - diff = stateBits ^ glState.vertexAttribsState; - if(!diff) - { - return; - } - - if(diff & ATTR_POSITION) - { - if(stateBits & ATTR_POSITION) - { - GLimp_LogComment("qglEnableVertexAttribArrayARB( ATTR_INDEX_POSITION )\n"); - qglEnableVertexAttribArrayARB(ATTR_INDEX_POSITION); - } - else - { - GLimp_LogComment("qglDisableVertexAttribArrayARB( ATTR_INDEX_POSITION )\n"); - qglDisableVertexAttribArrayARB(ATTR_INDEX_POSITION); - } - } - - if(diff & ATTR_TEXCOORD) - { - if(stateBits & ATTR_TEXCOORD) - { - GLimp_LogComment("qglEnableVertexAttribArrayARB( ATTR_INDEX_TEXCOORD )\n"); - qglEnableVertexAttribArrayARB(ATTR_INDEX_TEXCOORD0); - } - else - { - GLimp_LogComment("qglDisableVertexAttribArrayARB( ATTR_INDEX_TEXCOORD )\n"); - qglDisableVertexAttribArrayARB(ATTR_INDEX_TEXCOORD0); - } - } - - if(diff & ATTR_LIGHTCOORD) - { - if(stateBits & ATTR_LIGHTCOORD) - { - GLimp_LogComment("qglEnableVertexAttribArrayARB( ATTR_INDEX_LIGHTCOORD )\n"); - qglEnableVertexAttribArrayARB(ATTR_INDEX_TEXCOORD1); - } - else - { - GLimp_LogComment("qglDisableVertexAttribArrayARB( ATTR_INDEX_LIGHTCOORD )\n"); - qglDisableVertexAttribArrayARB(ATTR_INDEX_TEXCOORD1); - } - } - - if(diff & ATTR_NORMAL) - { - if(stateBits & ATTR_NORMAL) - { - GLimp_LogComment("qglEnableVertexAttribArrayARB( ATTR_INDEX_NORMAL )\n"); - qglEnableVertexAttribArrayARB(ATTR_INDEX_NORMAL); - } - else - { - GLimp_LogComment("qglDisableVertexAttribArrayARB( ATTR_INDEX_NORMAL )\n"); - qglDisableVertexAttribArrayARB(ATTR_INDEX_NORMAL); - } - } - - if(diff & ATTR_TANGENT) - { - if(stateBits & ATTR_TANGENT) - { - GLimp_LogComment("qglEnableVertexAttribArrayARB( ATTR_INDEX_TANGENT )\n"); - qglEnableVertexAttribArrayARB(ATTR_INDEX_TANGENT); - } - else - { - GLimp_LogComment("qglDisableVertexAttribArrayARB( ATTR_INDEX_TANGENT )\n"); - qglDisableVertexAttribArrayARB(ATTR_INDEX_TANGENT); - } - } - - if(diff & ATTR_BITANGENT) - { - if(stateBits & ATTR_BITANGENT) - { - GLimp_LogComment("qglEnableVertexAttribArrayARB( ATTR_INDEX_BITANGENT )\n"); - qglEnableVertexAttribArrayARB(ATTR_INDEX_BITANGENT); - } - else - { - GLimp_LogComment("qglDisableVertexAttribArrayARB( ATTR_INDEX_BITANGENT )\n"); - qglDisableVertexAttribArrayARB(ATTR_INDEX_BITANGENT); - } - } - - if(diff & ATTR_COLOR) - { - if(stateBits & ATTR_COLOR) - { - GLimp_LogComment("qglEnableVertexAttribArrayARB( ATTR_INDEX_COLOR )\n"); - qglEnableVertexAttribArrayARB(ATTR_INDEX_COLOR); - } - else - { - GLimp_LogComment("qglDisableVertexAttribArrayARB( ATTR_INDEX_COLOR )\n"); - qglDisableVertexAttribArrayARB(ATTR_INDEX_COLOR); - } - } - - if(diff & ATTR_POSITION2) - { - if(stateBits & ATTR_POSITION2) - { - GLimp_LogComment("qglEnableVertexAttribArrayARB( ATTR_INDEX_POSITION2 )\n"); - qglEnableVertexAttribArrayARB(ATTR_INDEX_POSITION2); - } - else - { - GLimp_LogComment("qglDisableVertexAttribArrayARB( ATTR_INDEX_POSITION2 )\n"); - qglDisableVertexAttribArrayARB(ATTR_INDEX_POSITION2); - } - } - - if(diff & ATTR_NORMAL2) - { - if(stateBits & ATTR_NORMAL2) - { - GLimp_LogComment("qglEnableVertexAttribArrayARB( ATTR_INDEX_NORMAL2 )\n"); - qglEnableVertexAttribArrayARB(ATTR_INDEX_NORMAL2); - } - else - { - GLimp_LogComment("qglDisableVertexAttribArrayARB( ATTR_INDEX_NORMAL2 )\n"); - qglDisableVertexAttribArrayARB(ATTR_INDEX_NORMAL2); - } - } - - if(diff & ATTR_TANGENT2) - { - if(stateBits & ATTR_TANGENT2) - { - GLimp_LogComment("qglEnableVertexAttribArrayARB( ATTR_INDEX_TANGENT2 )\n"); - qglEnableVertexAttribArrayARB(ATTR_INDEX_TANGENT2); - } - else - { - GLimp_LogComment("qglDisableVertexAttribArrayARB( ATTR_INDEX_TANGENT2 )\n"); - qglDisableVertexAttribArrayARB(ATTR_INDEX_TANGENT2); - } - } - - if(diff & ATTR_BITANGENT2) - { - if(stateBits & ATTR_BITANGENT2) - { - GLimp_LogComment("qglEnableVertexAttribArrayARB( ATTR_INDEX_BITANGENT2 )\n"); - qglEnableVertexAttribArrayARB(ATTR_INDEX_BITANGENT2); - } - else - { - GLimp_LogComment("qglDisableVertexAttribArrayARB( ATTR_INDEX_BITANGENT2 )\n"); - qglDisableVertexAttribArrayARB(ATTR_INDEX_BITANGENT2); - } - } - - glState.vertexAttribsState = stateBits; -} - -void GLSL_VertexAttribPointers(uint32_t attribBits) -{ - if(!glState.currentVBO) - { - ri.Error(ERR_FATAL, "GL_VertexAttribPointers: no VBO bound"); - return; - } - - // don't just call LogComment, or we will get a call to va() every frame! - GLimp_LogComment(va("--- GL_VertexAttribPointers( %s ) ---\n", glState.currentVBO->name)); - - if((attribBits & ATTR_POSITION) && !(glState.vertexAttribPointersSet & ATTR_POSITION)) - { - GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_POSITION )\n"); - - qglVertexAttribPointerARB(ATTR_INDEX_POSITION, 3, GL_FLOAT, 0, glState.currentVBO->stride_xyz, BUFFER_OFFSET(glState.currentVBO->ofs_xyz + glState.vertexAttribsNewFrame * glState.currentVBO->size_xyz)); - glState.vertexAttribPointersSet |= ATTR_POSITION; - } - - if((attribBits & ATTR_TEXCOORD) && !(glState.vertexAttribPointersSet & ATTR_TEXCOORD)) - { - GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_TEXCOORD )\n"); - - qglVertexAttribPointerARB(ATTR_INDEX_TEXCOORD0, 2, GL_FLOAT, 0, glState.currentVBO->stride_st, BUFFER_OFFSET(glState.currentVBO->ofs_st)); - glState.vertexAttribPointersSet |= ATTR_TEXCOORD; - } - - if((attribBits & ATTR_LIGHTCOORD) && !(glState.vertexAttribPointersSet & ATTR_LIGHTCOORD)) - { - GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_LIGHTCOORD )\n"); - - qglVertexAttribPointerARB(ATTR_INDEX_TEXCOORD1, 2, GL_FLOAT, 0, glState.currentVBO->stride_lightmap, BUFFER_OFFSET(glState.currentVBO->ofs_lightmap)); - glState.vertexAttribPointersSet |= ATTR_LIGHTCOORD; - } - - if((attribBits & ATTR_NORMAL) && !(glState.vertexAttribPointersSet & ATTR_NORMAL)) - { - GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_NORMAL )\n"); - - qglVertexAttribPointerARB(ATTR_INDEX_NORMAL, 3, GL_FLOAT, 0, glState.currentVBO->stride_normal, BUFFER_OFFSET(glState.currentVBO->ofs_normal + glState.vertexAttribsNewFrame * glState.currentVBO->size_normal)); - glState.vertexAttribPointersSet |= ATTR_NORMAL; - } - - if((attribBits & ATTR_TANGENT) && !(glState.vertexAttribPointersSet & ATTR_TANGENT)) - { - GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_TANGENT )\n"); - - qglVertexAttribPointerARB(ATTR_INDEX_TANGENT, 3, GL_FLOAT, 0, glState.currentVBO->stride_tangent, BUFFER_OFFSET(glState.currentVBO->ofs_tangent + glState.vertexAttribsNewFrame * glState.currentVBO->size_normal)); // FIXME - glState.vertexAttribPointersSet |= ATTR_TANGENT; - } - - if((attribBits & ATTR_BITANGENT) && !(glState.vertexAttribPointersSet & ATTR_BITANGENT)) - { - GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_BITANGENT )\n"); - - qglVertexAttribPointerARB(ATTR_INDEX_BITANGENT, 3, GL_FLOAT, 0, glState.currentVBO->stride_bitangent, BUFFER_OFFSET(glState.currentVBO->ofs_bitangent + glState.vertexAttribsNewFrame * glState.currentVBO->size_normal)); // FIXME - glState.vertexAttribPointersSet |= ATTR_BITANGENT; - } - - if((attribBits & ATTR_COLOR) && !(glState.vertexAttribPointersSet & ATTR_COLOR)) - { - GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_COLOR )\n"); - - qglVertexAttribPointerARB(ATTR_INDEX_COLOR, 4, GL_UNSIGNED_BYTE, 1, glState.currentVBO->stride_vertexcolor, BUFFER_OFFSET(glState.currentVBO->ofs_vertexcolor)); - glState.vertexAttribPointersSet |= ATTR_COLOR; - } - - if((attribBits & ATTR_POSITION2) && !(glState.vertexAttribPointersSet & ATTR_POSITION2)) - { - GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_POSITION2 )\n"); - - qglVertexAttribPointerARB(ATTR_INDEX_POSITION2, 3, GL_FLOAT, 0, glState.currentVBO->stride_xyz, BUFFER_OFFSET(glState.currentVBO->ofs_xyz + glState.vertexAttribsOldFrame * glState.currentVBO->size_xyz)); - glState.vertexAttribPointersSet |= ATTR_POSITION2; - } - - if((attribBits & ATTR_NORMAL2) && !(glState.vertexAttribPointersSet & ATTR_NORMAL2)) - { - GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_NORMAL2 )\n"); - - qglVertexAttribPointerARB(ATTR_INDEX_NORMAL2, 3, GL_FLOAT, 0, glState.currentVBO->stride_normal, BUFFER_OFFSET(glState.currentVBO->ofs_normal + glState.vertexAttribsOldFrame * glState.currentVBO->size_normal)); - glState.vertexAttribPointersSet |= ATTR_NORMAL2; - } - - if((attribBits & ATTR_TANGENT2) && !(glState.vertexAttribPointersSet & ATTR_TANGENT2)) - { - GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_TANGENT2 )\n"); - - qglVertexAttribPointerARB(ATTR_INDEX_TANGENT2, 3, GL_FLOAT, 0, glState.currentVBO->stride_tangent, BUFFER_OFFSET(glState.currentVBO->ofs_tangent + glState.vertexAttribsOldFrame * glState.currentVBO->size_normal)); // FIXME - glState.vertexAttribPointersSet |= ATTR_TANGENT2; - } - - if((attribBits & ATTR_BITANGENT2) && !(glState.vertexAttribPointersSet & ATTR_BITANGENT2)) - { - GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_BITANGENT2 )\n"); - - qglVertexAttribPointerARB(ATTR_INDEX_BITANGENT2, 3, GL_FLOAT, 0, glState.currentVBO->stride_bitangent, BUFFER_OFFSET(glState.currentVBO->ofs_bitangent + glState.vertexAttribsOldFrame * glState.currentVBO->size_normal)); // FIXME - glState.vertexAttribPointersSet |= ATTR_BITANGENT2; - } -} - -shaderProgram_t *GLSL_GetGenericShaderProgram(int stage) -{ - shaderStage_t *pStage = tess.xstages[stage]; - int shaderAttribs = 0; - - if (tess.fogNum && pStage->adjustColorsForFog) - { - shaderAttribs |= GENERICDEF_USE_FOG; - } - - if (pStage->bundle[1].image[0] && tess.shader->multitextureEnv) - { - shaderAttribs |= GENERICDEF_USE_LIGHTMAP; - } - - switch (pStage->rgbGen) - { - case CGEN_LIGHTING_DIFFUSE: - shaderAttribs |= GENERICDEF_USE_RGBAGEN; - break; - default: - break; - } - - switch (pStage->alphaGen) - { - case AGEN_LIGHTING_SPECULAR: - case AGEN_PORTAL: - case AGEN_FRESNEL: - shaderAttribs |= GENERICDEF_USE_RGBAGEN; - break; - default: - break; - } - - if (pStage->bundle[0].tcGen != TCGEN_TEXTURE) - { - shaderAttribs |= GENERICDEF_USE_TCGEN; - } - - if (tess.shader->numDeforms && !ShaderRequiresCPUDeforms(tess.shader)) - { - shaderAttribs |= GENERICDEF_USE_DEFORM_VERTEXES; - } - - if (glState.vertexAttribsInterpolation > 0.0f && backEnd.currentEntity && backEnd.currentEntity != &tr.worldEntity) - { - shaderAttribs |= GENERICDEF_USE_VERTEX_ANIMATION; - } - - return &tr.genericShader[shaderAttribs]; -} - diff --git a/code/renderer/tr_noise.c b/code/renderer/tr_noise.c deleted file mode 100644 index 40eafc33..00000000 --- a/code/renderer/tr_noise.c +++ /dev/null @@ -1,93 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -Quake III Arena source code 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_noise.c -#include "../qcommon/q_shared.h" -#include "../qcommon/qfiles.h" -#include "../qcommon/qcommon.h" - -#define NOISE_SIZE 256 -#define NOISE_MASK ( NOISE_SIZE - 1 ) - -#define VAL( a ) s_noise_perm[ ( a ) & ( NOISE_MASK )] -#define INDEX( x, y, z, t ) VAL( x + VAL( y + VAL( z + VAL( t ) ) ) ) - -static float s_noise_table[NOISE_SIZE]; -static int s_noise_perm[NOISE_SIZE]; - -static float GetNoiseValue( int x, int y, int z, int t ) -{ - int index = INDEX( ( int ) x, ( int ) y, ( int ) z, ( int ) t ); - - return s_noise_table[index]; -} - -void R_NoiseInit( void ) -{ - int i; - - for ( i = 0; i < NOISE_SIZE; i++ ) - { - s_noise_table[i] = ( float ) ( ( ( rand() / ( float ) RAND_MAX ) * 2.0 - 1.0 ) ); - s_noise_perm[i] = ( unsigned char ) ( rand() / ( float ) RAND_MAX * 255 ); - } -} - -float R_NoiseGet4f( float x, float y, float z, float t ) -{ - int i; - int ix, iy, iz, it; - float fx, fy, fz, ft; - float front[4]; - float back[4]; - float fvalue, bvalue, value[2], finalvalue; - - ix = ( int ) floor( x ); - fx = x - ix; - iy = ( int ) floor( y ); - fy = y - iy; - iz = ( int ) floor( z ); - fz = z - iz; - it = ( int ) floor( t ); - ft = t - it; - - for ( i = 0; i < 2; i++ ) - { - front[0] = GetNoiseValue( ix, iy, iz, it + i ); - front[1] = GetNoiseValue( ix+1, iy, iz, it + i ); - front[2] = GetNoiseValue( ix, iy+1, iz, it + i ); - front[3] = GetNoiseValue( ix+1, iy+1, iz, it + i ); - - back[0] = GetNoiseValue( ix, iy, iz + 1, it + i ); - back[1] = GetNoiseValue( ix+1, iy, iz + 1, it + i ); - back[2] = GetNoiseValue( ix, iy+1, iz + 1, it + i ); - back[3] = GetNoiseValue( ix+1, iy+1, iz + 1, it + i ); - - fvalue = LERP( LERP( front[0], front[1], fx ), LERP( front[2], front[3], fx ), fy ); - bvalue = LERP( LERP( back[0], back[1], fx ), LERP( back[2], back[3], fx ), fy ); - - value[i] = LERP( fvalue, bvalue, fz ); - } - - finalvalue = LERP( value[0], value[1], ft ); - - return finalvalue; -} diff --git a/code/renderer/tr_postprocess.c b/code/renderer/tr_postprocess.c deleted file mode 100644 index 40c01ccb..00000000 --- a/code/renderer/tr_postprocess.c +++ /dev/null @@ -1,494 +0,0 @@ -#include "tr_local.h" - -/* Color functions */ - -static void GLSL_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a) -{ - vec4_t clr; - MAKERGBA(clr, r, g, b, a); - GLSL_SetUniformVec4(glState.currentProgram, TEXTURECOLOR_UNIFORM_COLOR, clr); -} - -static void qglDefColor4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a) -{ - qglColor4f(r, g, b, a); -} - -/* Quad-drawing functions */ - -static void tessTexCoord2f(float s, float t) -{ - tess.texCoords[tess.numVertexes][0][0] = s; - tess.texCoords[tess.numVertexes][0][1] = t; - tess.texCoords[tess.numVertexes][0][2] = 0; - tess.texCoords[tess.numVertexes][0][3] = 1; -} - -static void tessVertex2f(float x, float y) -{ - tess.xyz[tess.numVertexes][0] = x; - tess.xyz[tess.numVertexes][1] = y; - tess.xyz[tess.numVertexes][2] = 0.f; - tess.xyz[tess.numVertexes][3] = 1.f; - ++tess.numVertexes; -} - -static void tessBeginQuads(void) -{ - tess.numIndexes = 0; - tess.numVertexes = 0; - tess.firstIndex = 0; -} - -static void tessEndQuads(void) -{ - int i; - - for (i=0; iinteger) - { - GLSL_VertexAttribsState(ATTR_POSITION | ATTR_TEXCOORD); - GLSL_SetUniformMatrix16(glState.currentProgram, TEXTURECOLOR_UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); - } - else - { - qglEnableClientState( GL_VERTEX_ARRAY ); - qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); - qglVertexPointer(3, GL_FLOAT, glState.currentVBO->stride_xyz, BUFFER_OFFSET(glState.currentVBO->ofs_xyz)); - qglTexCoordPointer( 2, GL_FLOAT, glState.currentVBO->stride_st, BUFFER_OFFSET(glState.currentVBO->ofs_st) ); - } - - qglDrawElements(GL_TRIANGLES, tess.numIndexes, GL_INDEX_TYPE, BUFFER_OFFSET(0)); - - //R_BindNullVBO(); - //R_BindNullIBO(); - - tess.numIndexes = 0; - tess.numVertexes = 0; - tess.firstIndex = 0; -} - -static void RB_DrawQuad_Imm(float x, float y, float w, float h, float s0, float t0, float s1, float t1) -{ - qglBegin (GL_QUADS); - { - qglTexCoord2f( s0, t1 ); - qglVertex2f( x, y ); - - qglTexCoord2f( s1, t1 ); - qglVertex2f( x + w, y ); - - qglTexCoord2f( s1, t0 ); - qglVertex2f( x + w, y + h ); - - qglTexCoord2f( s0, t0 ); - qglVertex2f( x, y + h ); - } - qglEnd(); -} - -static void RB_DrawQuad_Tess(float x, float y, float w, float h, float s0, float t0, float s1, float t1) -{ - tessBeginQuads(); - { - tessTexCoord2f( s0, t1 ); - tessVertex2f( x, y ); - - tessTexCoord2f( s1, t1 ); - tessVertex2f( x + w, y ); - - tessTexCoord2f( s1, t0 ); - tessVertex2f( x + w, y + h ); - - tessTexCoord2f( s0, t0 ); - tessVertex2f( x, y + h ); - } - tessEndQuads(); -} - -static void (*RB_DrawQuad) (float x, float y, float w, float h, float s0, float t0, float s1, float t1) = NULL; -static void (*RB_Color4f) (GLfloat r, GLfloat g, GLfloat b, GLfloat a) = NULL; - -static void RB_DrawScaledQuad(float x, float y, float w, float h, float xcenter, float ycenter, float scale) -{ - float iscale = 1.f / scale; - float s0 = xcenter * (1.f - iscale); - float t0 = ycenter * (1.f - iscale); - float s1 = iscale + s0; - float t1 = iscale + t0; - - RB_DrawQuad(x, y, w, h, s0, t0, s1, t1); -} - -static void RB_RadialBlur(int passes, float stretch, float x, float y, float w, float h, float xcenter, float ycenter, float alpha) -{ - const float inc = 1.f / passes; - const float mul = powf(stretch, inc); - float scale; - - - alpha *= inc; - RB_Color4f(alpha, alpha, alpha, 1.f); - - GL_State(GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); - RB_DrawQuad(x, y, w, h, 0.f, 0.f, 1.f, 1.f); - - GL_State(GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); - --passes; - scale = mul; - while (passes > 0) - { - RB_DrawScaledQuad(x, y, w, h, xcenter, ycenter, scale); - scale *= mul; - --passes; - } - - RB_Color4f(1.f, 1.f, 1.f, 1.f); -} - -static qboolean RB_UpdateSunFlareVis(void) -{ - GLuint sampleCount = 0; - if (!glRefConfig.occlusionQuery) - return qtrue; - - tr.sunFlareQueryIndex ^= 1; - if (!tr.sunFlareQueryActive[tr.sunFlareQueryIndex]) - return qtrue; - - /* debug code */ - if (0) - { - int iter; - for (iter=0 ; ; ++iter) - { - GLint available = 0; - qglGetQueryObjectivARB(tr.sunFlareQuery[tr.sunFlareQueryIndex], GL_QUERY_RESULT_AVAILABLE_ARB, &available); - if (available) - break; - } - - ri.Printf(PRINT_DEVELOPER, "Waited %d iterations\n", iter); - } - - qglGetQueryObjectuivARB(tr.sunFlareQuery[tr.sunFlareQueryIndex], GL_QUERY_RESULT_ARB, &sampleCount); - return sampleCount > 0; -} - -/* -================ -RB_GodRays - -================ -*/ - -static void RB_GodRays(void) -{ - vec3_t dir; - float dot; - const float cutoff = 0.25f; - qboolean colorize = qtrue; - - float w, h, w2, h2; - matrix_t mvp; - vec4_t pos, hpos; - - if (!backEnd.hasSunFlare) - return; - - VectorSubtract(backEnd.sunFlarePos, backEnd.viewParms.or.origin, dir); - VectorNormalize(dir); - - dot = DotProduct(dir, backEnd.viewParms.or.axis[0]); - if (dot < cutoff) - return; - - if (!RB_UpdateSunFlareVis()) - return; - - VectorCopy(backEnd.sunFlarePos, pos); - pos[3] = 1.f; - - // project sun point - Matrix16Multiply(backEnd.viewParms.projectionMatrix, backEnd.viewParms.world.modelMatrix, mvp); - Matrix16Transform(mvp, pos, hpos); - - // transform to UV coords - hpos[3] = 0.5f / hpos[3]; - - pos[0] = 0.5f + hpos[0] * hpos[3]; - pos[1] = 0.5f + hpos[1] * hpos[3]; - - // viewport dimensions - w = glConfig.vidWidth; - h = glConfig.vidHeight; - w2 = glConfig.vidWidth / 2; - h2 = glConfig.vidHeight / 2; - - // initialize quarter buffers - { - float mul = 1.f; - - RB_SetGL2D_Level(1); - - GL_State(GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); - RB_Color4f(mul, mul, mul, 1.f); - - // first, downsample the main framebuffers - R_FBO_Bind(tr.fbo.quarter[0]); - R_FBO_BindColorBuffer(tr.fbo.full[1], 0); - RB_DrawQuad(0.f, 0.f, w2, h2, 0.f, 0.f, 1.f, 1.f); - - if (colorize) - { - GL_State(GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_SRC_COLOR ); - R_FBO_BindColorBuffer(tr.fbo.full[0], 0); - mul = 1.f; - RB_Color4f(mul, mul, mul, 1.f); - RB_DrawQuad(0.f, 0.f, w2, h2, 0.f, 0.f, 1.f, 1.f); - } - } - - // radial blur passes, ping-ponging between the two quarter-size buffers - { - const float stretch_add = 2.f/3.f; - float stretch = 1.f + stretch_add; - int i; - for (i=0; i<2; ++i) - { - R_FBO_Bind(tr.fbo.quarter[(~i) & 1]); - R_FBO_BindColorBuffer(tr.fbo.quarter[i&1], 0); - RB_RadialBlur(5, stretch, 0.f, 0.f, w2, h2, pos[0], pos[1], 1.125f); - stretch += stretch_add; - } - } - - // add result back on top of the main buffer - { - float mul = 1.f; - R_FBO_BindColorBuffer(R_FBO_Bind(tr.fbo.full[0]), 0); - RB_SetGL2D_Level(0); - GL_State(GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); - - RB_Color4f(mul, mul, mul, 1.f); - RB_DrawQuad(0.f, 0.f, w, h, 0.f, 0.f, 1.f, 1.f); - } -} - -static void RB_BlurAxis(float w, float h, float strength, qboolean horizontal) -{ - float dx, dy; - float xmul, ymul; - float weights[3] = { - 0.227027027f, - 0.316216216f, - 0.070270270f, - }; - float offsets[3] = { - 0.f, - 1.3846153846f, - 3.2307692308f, - }; - - xmul = horizontal; - ymul = 1.f - xmul; - - xmul /= w; - ymul /= h; - - xmul *= strength; - ymul *= strength; - - GL_State(GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO | GLS_ALPHAMASK_FALSE ); - - RB_Color4f(weights[0], weights[0], weights[0], 0.f); - RB_DrawQuad(0.f, 0.f, w, h, 0.f, 0.f, 1.f, 1.f); - - GL_State(GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_ALPHAMASK_FALSE ); - - RB_Color4f(weights[1], weights[1], weights[1], 0.f); - dx = offsets[1] * xmul; - dy = offsets[1] * ymul; - RB_DrawQuad(0.f, 0.f, w, h, dx, dy, 1.f+dx, 1.f+dy); - RB_DrawQuad(0.f, 0.f, w, h, -dx, -dy, 1.f-dx, 1.f-dy); - - RB_Color4f(weights[2], weights[2], weights[2], 0.f); - dx = offsets[2] * xmul; - dy = offsets[2] * ymul; - RB_DrawQuad(0.f, 0.f, w, h, dx, dy, 1.f+dx, 1.f+dy); - RB_DrawQuad(0.f, 0.f, w, h, -dx, -dy, 1.f-dx, 1.f-dy); -} - -static void RB_HBlur(float w, float h, float strength) -{ - RB_BlurAxis(w, h, strength, qtrue); -} - -static void RB_VBlur(float w, float h, float strength) -{ - RB_BlurAxis(w, h, strength, qfalse); -} - -static void RB_Blur(void) -{ - float w, h, w2, h2, w4, h4; - float mul = 1.f; - float factor = Com_Clamp(0.f, 1.f, backEnd.refdef.blurFactor); -// int i; - - if (factor <= 0.f) - return; - - // viewport dimensions - w = glConfig.vidWidth; - h = glConfig.vidHeight; - w2 = glConfig.vidWidth / 2; - h2 = glConfig.vidHeight / 2; - w4 = glConfig.vidWidth / 4; - h4 = glConfig.vidHeight / 4; - - RB_SetGL2D_Level(1); - - GL_State(GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); - RB_Color4f(mul, mul, mul, 1.f); - - // first, downsample the main framebuffers - R_FBO_Bind(tr.fbo.quarter[0]); - R_FBO_BindColorBuffer(tr.fbo.full[0], 0); - RB_DrawQuad(0.f, 0.f, w2, h2, 0.f, 0.f, 1.f, 1.f); - - RB_SetGL2D_Level(2); - GL_State(GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); - RB_Color4f(mul, mul, mul, 1.f); - - R_FBO_Bind(tr.fbo.tiny[0]); - - R_FBO_BindColorBuffer(tr.fbo.quarter[0], 0); - GL_State(GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); - mul = 1.f; - RB_Color4f(mul, mul, mul, 1.f); - RB_DrawQuad(0.f, 0.f, w4, h4, 0.f, 0.f, 1.f, 1.f); - - GL_State(GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO | GLS_REDMASK_FALSE | GLS_BLUEMASK_FALSE | GLS_GREENMASK_FALSE ); - GL_Bind(tr.whiteImage); - mul = 1.f; - RB_Color4f(mul, mul, mul, 1.f); - RB_DrawQuad(0.f, 0.f, w4, h4, 0.f, 0.f, 1.f, 1.f); - - //for (i=0; i<2; ++i) - { - R_FBO_Bind(tr.fbo.tiny[1]); - R_FBO_BindColorBuffer(tr.fbo.tiny[0], 0); - RB_HBlur(w4, h4, factor); - - R_FBO_Bind(tr.fbo.tiny[0]); - R_FBO_BindColorBuffer(tr.fbo.tiny[1], 0); - RB_VBlur(w4, h4, factor); - } - - RB_SetGL2D_Level(0); - R_FBO_BindColorBuffer(R_FBO_Bind(tr.fbo.full[0]), 0); - GL_State(GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); - mul = 1.f; - RB_Color4f(mul, mul, mul, factor); - RB_DrawQuad(0.f, 0.f, w, h, 0.f, 0.f, 1.f, 1.f); - - GL_State(GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); -} - -void RB_FBO_Set2D(void) -{ - RB_DrawQuad = NULL; - RB_Color4f = NULL; - - // initialize our function pointers and perform any necessary setup - if (glRefConfig.vertexBufferObject && r_arb_vertex_buffer_object->integer) - { - RB_DrawQuad = &RB_DrawQuad_Tess; - if (glRefConfig.glsl && r_arb_shader_objects->integer) - { - shaderProgram_t *sp = &tr.textureColorShader; - - GLSL_BindProgram(sp); - - GLSL_SetUniformMatrix16(sp, TEXTURECOLOR_UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); - GLSL_SetUniformInt(sp, TEXTURECOLOR_UNIFORM_DIFFUSEMAP, 0); - - RB_Color4f = &GLSL_Color4f; - } - else - { - RB_Color4f = &qglDefColor4f; - } - } - else - { - RB_DrawQuad = &RB_DrawQuad_Imm; - RB_Color4f = &qglDefColor4f; - } - - RB_SetGL2D(); - - GL_SelectTexture(1); - GL_Bind(tr.whiteImage); - GL_SelectTexture(0); - - RB_Color4f(1.f, 1.f, 1.f, 1.f); -} - - -/* -================ -RB_FBO_Blit -================ -*/ - -void RB_FBO_Blit(void) -{ - fbo_t* fbo = R_FBO_Bind(NULL); - if (!fbo) - return; - - RB_FBO_Set2D(); - - R_FBO_BindColorBuffer(fbo, 0); - GL_State(GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); - - if (glRefConfig.glslOverbright) - { - float mul = 1.f / tr.identityLight; - RB_Color4f(mul, mul, mul, 1.f); - } - - RB_DrawQuad(0.f, 0.f, glConfig.vidWidth, glConfig.vidHeight, 0.f, 0.f, 1.f, 1.f); - - R_FBO_Bind(fbo); -} - -/* -================ -RB_PostProcess -================ -*/ - -void RB_PostProcess(void) -{ - if (!glState.currentFBO || backEnd.refdef.rdflags & RDF_NOWORLDMODEL) - return; - - RB_FBO_Set2D(); - RB_GodRays(); - RB_Blur(); -} diff --git a/code/renderer/tr_vbo.c b/code/renderer/tr_vbo.c deleted file mode 100644 index b485df83..00000000 --- a/code/renderer/tr_vbo.c +++ /dev/null @@ -1,867 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2007-2009 Robert Beckebans - -This file is part of XreaL source code. - -XreaL source code is free software; you can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the License, -or (at your option) any later version. - -XreaL source code 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with XreaL source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// tr_vbo.c -#include "tr_local.h" - -/* -============ -R_CreateVBO -============ -*/ -VBO_t *R_CreateVBO(const char *name, byte * vertexes, int vertexesSize, vboUsage_t usage) -{ - VBO_t *vbo; - int glUsage; - - switch (usage) - { - case VBO_USAGE_STATIC: - glUsage = GL_STATIC_DRAW_ARB; - break; - - case VBO_USAGE_DYNAMIC: - glUsage = GL_DYNAMIC_DRAW_ARB; - break; - - default: - Com_Error(ERR_FATAL, "bad vboUsage_t given: %i", usage); - return NULL; - } - - if(strlen(name) >= MAX_QPATH) - { - ri.Error(ERR_DROP, "R_CreateVBO: \"%s\" is too long\n", name); - } - - if ( tr.numVBOs == MAX_VBOS ) { - ri.Error( ERR_DROP, "R_CreateVBO: MAX_VBOS hit\n"); - } - - // make sure the render thread is stopped - R_SyncRenderThread(); - - vbo = tr.vbos[tr.numVBOs] = ri.Hunk_Alloc(sizeof(*vbo), h_low); - tr.numVBOs++; - - memset(vbo, 0, sizeof(*vbo)); - - Q_strncpyz(vbo->name, name, sizeof(vbo->name)); - - vbo->vertexesSize = vertexesSize; - - qglGenBuffersARB(1, &vbo->vertexesVBO); - - qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo->vertexesVBO); - qglBufferDataARB(GL_ARRAY_BUFFER_ARB, vertexesSize, vertexes, glUsage); - - qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - - glState.currentVBO = NULL; - - GL_CheckErrors(); - - return vbo; -} - -/* -============ -R_CreateVBO2 -============ -*/ -VBO_t *R_CreateVBO2(const char *name, int numVertexes, srfVert_t * verts, unsigned int stateBits, vboUsage_t usage) -{ - VBO_t *vbo; - int i; - - byte *data; - int dataSize; - int dataOfs; - - int glUsage; - - switch (usage) - { - case VBO_USAGE_STATIC: - glUsage = GL_STATIC_DRAW_ARB; - break; - - case VBO_USAGE_DYNAMIC: - glUsage = GL_DYNAMIC_DRAW_ARB; - break; - - default: - Com_Error(ERR_FATAL, "bad vboUsage_t given: %i", usage); - return NULL; - } - - if(!numVertexes) - return NULL; - - if(strlen(name) >= MAX_QPATH) - { - ri.Error(ERR_DROP, "R_CreateVBO2: \"%s\" is too long\n", name); - } - - if ( tr.numVBOs == MAX_VBOS ) { - ri.Error( ERR_DROP, "R_CreateVBO2: MAX_VBOS hit\n"); - } - - // make sure the render thread is stopped - R_SyncRenderThread(); - - vbo = tr.vbos[tr.numVBOs] = ri.Hunk_Alloc(sizeof(*vbo), h_low); - tr.numVBOs++; - - memset(vbo, 0, sizeof(*vbo)); - - Q_strncpyz(vbo->name, name, sizeof(vbo->name)); - - if (usage == VBO_USAGE_STATIC) - { - // since these vertex attributes are never altered, interleave them - vbo->ofs_xyz = 0; - dataSize = sizeof(verts[0].xyz); - - if(stateBits & ATTR_NORMAL) - { - vbo->ofs_normal = dataSize; - dataSize += sizeof(verts[0].normal); - } - - if(stateBits & ATTR_TANGENT) - { - vbo->ofs_tangent = dataSize; - dataSize += sizeof(verts[0].tangent); - } - - if(stateBits & ATTR_BITANGENT) - { - vbo->ofs_bitangent = dataSize; - dataSize += sizeof(verts[0].bitangent); - } - - if(stateBits & ATTR_TEXCOORD) - { - vbo->ofs_st = dataSize; - dataSize += sizeof(verts[0].st); - } - - if(stateBits & ATTR_LIGHTCOORD) - { - vbo->ofs_lightmap = dataSize; - dataSize += sizeof(verts[0].lightmap); - } - - if(stateBits & ATTR_COLOR) - { - vbo->ofs_vertexcolor = dataSize; - dataSize += sizeof(verts[0].vertexColors); - } - - vbo->stride_xyz = dataSize; - vbo->stride_normal = dataSize; - vbo->stride_tangent = dataSize; - vbo->stride_bitangent = dataSize; - vbo->stride_st = dataSize; - vbo->stride_lightmap = dataSize; - vbo->stride_vertexcolor = dataSize; - - // create VBO - dataSize *= numVertexes; - data = ri.Hunk_AllocateTempMemory(dataSize); - dataOfs = 0; - - //ri.Printf(PRINT_ALL, "CreateVBO: %d, %d %d %d %d %d, %d %d %d %d %d\n", dataSize, vbo->ofs_xyz, vbo->ofs_normal, vbo->ofs_st, vbo->ofs_lightmap, vbo->ofs_vertexcolor, - //vbo->stride_xyz, vbo->stride_normal, vbo->stride_st, vbo->stride_lightmap, vbo->stride_vertexcolor); - - for (i = 0; i < numVertexes; i++) - { - // xyz - memcpy(data + dataOfs, &verts[i].xyz, sizeof(verts[i].xyz)); - dataOfs += sizeof(verts[i].xyz); - - // normal - if(stateBits & ATTR_NORMAL) - { - memcpy(data + dataOfs, &verts[i].normal, sizeof(verts[i].normal)); - dataOfs += sizeof(verts[i].normal); - } - - // tangent - if(stateBits & ATTR_TANGENT) - { - memcpy(data + dataOfs, &verts[i].tangent, sizeof(verts[i].tangent)); - dataOfs += sizeof(verts[i].tangent); - } - - // bitangent - if(stateBits & ATTR_BITANGENT) - { - memcpy(data + dataOfs, &verts[i].bitangent, sizeof(verts[i].bitangent)); - dataOfs += sizeof(verts[i].bitangent); - } - - // vertex texcoords - if(stateBits & ATTR_TEXCOORD) - { - memcpy(data + dataOfs, &verts[i].st, sizeof(verts[i].st)); - dataOfs += sizeof(verts[i].st); - } - - // feed vertex lightmap texcoords - if(stateBits & ATTR_LIGHTCOORD) - { - memcpy(data + dataOfs, &verts[i].lightmap, sizeof(verts[i].lightmap)); - dataOfs += sizeof(verts[i].lightmap); - } - - // feed vertex colors - if(stateBits & ATTR_COLOR) - { - memcpy(data + dataOfs, &verts[i].vertexColors, sizeof(verts[i].vertexColors)); - dataOfs += sizeof(verts[i].vertexColors); - } - } - } - else - { - // since these vertex attributes may be changed, put them in flat arrays - dataSize = sizeof(verts[0].xyz); - - if(stateBits & ATTR_NORMAL) - { - dataSize += sizeof(verts[0].normal); - } - - if(stateBits & ATTR_TANGENT) - { - dataSize += sizeof(verts[0].tangent); - } - - if(stateBits & ATTR_BITANGENT) - { - dataSize += sizeof(verts[0].bitangent); - } - - if(stateBits & ATTR_TEXCOORD) - { - dataSize += sizeof(verts[0].st); - } - - if(stateBits & ATTR_LIGHTCOORD) - { - dataSize += sizeof(verts[0].lightmap); - } - - if(stateBits & ATTR_COLOR) - { - dataSize += sizeof(verts[0].vertexColors); - } - - // create VBO - dataSize *= numVertexes; - data = ri.Hunk_AllocateTempMemory(dataSize); - dataOfs = 0; - - vbo->ofs_xyz = 0; - vbo->ofs_normal = 0; - vbo->ofs_tangent = 0; - vbo->ofs_bitangent = 0; - vbo->ofs_st = 0; - vbo->ofs_lightmap = 0; - vbo->ofs_vertexcolor = 0; - - vbo->stride_xyz = sizeof(verts[0].xyz); - vbo->stride_normal = sizeof(verts[0].normal); - vbo->stride_tangent = sizeof(verts[0].tangent); - vbo->stride_bitangent = sizeof(verts[0].bitangent); - vbo->stride_vertexcolor = sizeof(verts[0].vertexColors); - vbo->stride_st = sizeof(verts[0].st); - vbo->stride_lightmap = sizeof(verts[0].lightmap); - - //ri.Printf(PRINT_ALL, "2CreateVBO: %d, %d %d %d %d %d, %d %d %d %d %d\n", dataSize, vbo->ofs_xyz, vbo->ofs_normal, vbo->ofs_st, vbo->ofs_lightmap, vbo->ofs_vertexcolor, - //vbo->stride_xyz, vbo->stride_normal, vbo->stride_st, vbo->stride_lightmap, vbo->stride_vertexcolor); - - // xyz - for (i = 0; i < numVertexes; i++) - { - memcpy(data + dataOfs, &verts[i].xyz, sizeof(verts[i].xyz)); - dataOfs += sizeof(verts[i].xyz); - } - - // normal - if(stateBits & ATTR_NORMAL) - { - vbo->ofs_normal = dataOfs; - for (i = 0; i < numVertexes; i++) - { - memcpy(data + dataOfs, &verts[i].normal, sizeof(verts[i].normal)); - dataOfs += sizeof(verts[i].normal); - } - } - - // tangent - if(stateBits & ATTR_TANGENT) - { - vbo->ofs_tangent = dataOfs; - for (i = 0; i < numVertexes; i++) - { - memcpy(data + dataOfs, &verts[i].tangent, sizeof(verts[i].tangent)); - dataOfs += sizeof(verts[i].tangent); - } - } - - // bitangent - if(stateBits & ATTR_BITANGENT) - { - vbo->ofs_bitangent = dataOfs; - for (i = 0; i < numVertexes; i++) - { - memcpy(data + dataOfs, &verts[i].bitangent, sizeof(verts[i].bitangent)); - dataOfs += sizeof(verts[i].bitangent); - } - } - - // vertex texcoords - if(stateBits & ATTR_TEXCOORD) - { - vbo->ofs_st = dataOfs; - for (i = 0; i < numVertexes; i++) - { - memcpy(data + dataOfs, &verts[i].st, sizeof(verts[i].st)); - dataOfs += sizeof(verts[i].st); - } - } - - // feed vertex lightmap texcoords - if(stateBits & ATTR_LIGHTCOORD) - { - vbo->ofs_lightmap = dataOfs; - for (i = 0; i < numVertexes; i++) - { - memcpy(data + dataOfs, &verts[i].lightmap, sizeof(verts[i].lightmap)); - dataOfs += sizeof(verts[i].lightmap); - } - } - - // feed vertex colors - if(stateBits & ATTR_COLOR) - { - vbo->ofs_vertexcolor = dataOfs; - for (i = 0; i < numVertexes; i++) - { - memcpy(data + dataOfs, &verts[i].vertexColors, sizeof(verts[i].vertexColors)); - dataOfs += sizeof(verts[i].vertexColors); - } - } - } - - - vbo->vertexesSize = dataSize; - - qglGenBuffersARB(1, &vbo->vertexesVBO); - - qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo->vertexesVBO); - qglBufferDataARB(GL_ARRAY_BUFFER_ARB, dataSize, data, glUsage); - - qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - - glState.currentVBO = NULL; - - GL_CheckErrors(); - - ri.Hunk_FreeTempMemory(data); - - return vbo; -} - - -/* -============ -R_CreateIBO -============ -*/ -IBO_t *R_CreateIBO(const char *name, byte * indexes, int indexesSize, vboUsage_t usage) -{ - IBO_t *ibo; - int glUsage; - - switch (usage) - { - case VBO_USAGE_STATIC: - glUsage = GL_STATIC_DRAW_ARB; - break; - - case VBO_USAGE_DYNAMIC: - glUsage = GL_DYNAMIC_DRAW_ARB; - break; - - default: - Com_Error(ERR_FATAL, "bad vboUsage_t given: %i", usage); - return NULL; - } - - if(strlen(name) >= MAX_QPATH) - { - ri.Error(ERR_DROP, "R_CreateIBO: \"%s\" is too long\n", name); - } - - if ( tr.numIBOs == MAX_IBOS ) { - ri.Error( ERR_DROP, "R_CreateIBO: MAX_IBOS hit\n"); - } - - // make sure the render thread is stopped - R_SyncRenderThread(); - - ibo = tr.ibos[tr.numIBOs] = ri.Hunk_Alloc(sizeof(*ibo), h_low); - tr.numIBOs++; - - Q_strncpyz(ibo->name, name, sizeof(ibo->name)); - - ibo->indexesSize = indexesSize; - - qglGenBuffersARB(1, &ibo->indexesVBO); - - qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, ibo->indexesVBO); - qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, indexesSize, indexes, glUsage); - - qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); - - glState.currentIBO = NULL; - - GL_CheckErrors(); - - return ibo; -} - -/* -============ -R_CreateIBO2 -============ -*/ -IBO_t *R_CreateIBO2(const char *name, int numTriangles, srfTriangle_t * triangles, vboUsage_t usage) -{ - IBO_t *ibo; - int i, j; - - byte *indexes; - int indexesSize; - int indexesOfs; - - srfTriangle_t *tri; - glIndex_t index; - int glUsage; - - switch (usage) - { - case VBO_USAGE_STATIC: - glUsage = GL_STATIC_DRAW_ARB; - break; - - case VBO_USAGE_DYNAMIC: - glUsage = GL_DYNAMIC_DRAW_ARB; - break; - - default: - Com_Error(ERR_FATAL, "bad vboUsage_t given: %i", usage); - return NULL; - } - - if(!numTriangles) - return NULL; - - if(strlen(name) >= MAX_QPATH) - { - ri.Error(ERR_DROP, "R_CreateIBO2: \"%s\" is too long\n", name); - } - - if ( tr.numIBOs == MAX_IBOS ) { - ri.Error( ERR_DROP, "R_CreateIBO2: MAX_IBOS hit\n"); - } - - // make sure the render thread is stopped - R_SyncRenderThread(); - - ibo = tr.ibos[tr.numIBOs] = ri.Hunk_Alloc(sizeof(*ibo), h_low); - tr.numIBOs++; - - Q_strncpyz(ibo->name, name, sizeof(ibo->name)); - - indexesSize = numTriangles * 3 * sizeof(int); - indexes = ri.Hunk_AllocateTempMemory(indexesSize); - indexesOfs = 0; - - for(i = 0, tri = triangles; i < numTriangles; i++, tri++) - { - for(j = 0; j < 3; j++) - { - index = tri->indexes[j]; - memcpy(indexes + indexesOfs, &index, sizeof(glIndex_t)); - indexesOfs += sizeof(glIndex_t); - } - } - - ibo->indexesSize = indexesSize; - - qglGenBuffersARB(1, &ibo->indexesVBO); - - qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, ibo->indexesVBO); - qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, indexesSize, indexes, glUsage); - - qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); - - glState.currentIBO = NULL; - - GL_CheckErrors(); - - ri.Hunk_FreeTempMemory(indexes); - - return ibo; -} - -/* -============ -R_BindVBO -============ -*/ -void R_BindVBO(VBO_t * vbo) -{ - if(!vbo) - { - //R_BindNullVBO(); - ri.Error(ERR_DROP, "R_BindNullVBO: NULL vbo"); - return; - } - - if(r_logFile->integer) - { - // don't just call LogComment, or we will get a call to va() every frame! - GLimp_LogComment(va("--- R_BindVBO( %s ) ---\n", vbo->name)); - } - - if(glState.currentVBO != vbo) - { - glState.currentVBO = vbo; - glState.vertexAttribPointersSet = 0; - - glState.vertexAttribsInterpolation = 0; - glState.vertexAttribsOldFrame = 0; - glState.vertexAttribsNewFrame = 0; - - qglBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo->vertexesVBO); - - backEnd.pc.c_vboVertexBuffers++; - } -} - -/* -============ -R_BindNullVBO -============ -*/ -void R_BindNullVBO(void) -{ - GLimp_LogComment("--- R_BindNullVBO ---\n"); - - if(glState.currentVBO) - { - qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - glState.currentVBO = NULL; - } - - GL_CheckErrors(); -} - -/* -============ -R_BindIBO -============ -*/ -void R_BindIBO(IBO_t * ibo) -{ - if(!ibo) - { - //R_BindNullIBO(); - ri.Error(ERR_DROP, "R_BindIBO: NULL ibo"); - return; - } - - if(r_logFile->integer) - { - // don't just call LogComment, or we will get a call to va() every frame! - GLimp_LogComment(va("--- R_BindIBO( %s ) ---\n", ibo->name)); - } - - if(glState.currentIBO != ibo) - { - qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, ibo->indexesVBO); - - glState.currentIBO = ibo; - - backEnd.pc.c_vboIndexBuffers++; - } -} - -/* -============ -R_BindNullIBO -============ -*/ -void R_BindNullIBO(void) -{ - GLimp_LogComment("--- R_BindNullIBO ---\n"); - - if(glState.currentIBO) - { - qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); - glState.currentIBO = NULL; - glState.vertexAttribPointersSet = 0; - } -} - -/* -============ -R_InitVBOs -============ -*/ -void R_InitVBOs(void) -{ - int dataSize; - byte *data; - - ri.Printf(PRINT_ALL, "------- R_InitVBOs -------\n"); - - tr.numVBOs = 0; - tr.numIBOs = 0; - - dataSize = sizeof(tess.xyz[0]); - dataSize += sizeof(tess.normal[0]); - dataSize += sizeof(tess.tangent[0]); - dataSize += sizeof(tess.bitangent[0]); - dataSize += sizeof(tess.vertexColors[0]); - dataSize += sizeof(tess.texCoords[0][0]) * 2; - dataSize *= SHADER_MAX_VERTEXES; - - data = ri.Malloc(dataSize); - memset(data, 0, dataSize); - - tess.vbo = R_CreateVBO("tessVertexArray_VBO", data, dataSize, VBO_USAGE_DYNAMIC); - - ri.Free(data); - - tess.vbo->ofs_xyz = 0; - tess.vbo->ofs_normal = tess.vbo->ofs_xyz + sizeof(tess.xyz[0]) * SHADER_MAX_VERTEXES; - tess.vbo->ofs_tangent = tess.vbo->ofs_normal + sizeof(tess.normal[0]) * SHADER_MAX_VERTEXES; - tess.vbo->ofs_bitangent = tess.vbo->ofs_tangent + sizeof(tess.tangent[0]) * SHADER_MAX_VERTEXES; - // these next two are actually interleaved - tess.vbo->ofs_st = tess.vbo->ofs_bitangent + sizeof(tess.bitangent[0]) * SHADER_MAX_VERTEXES; - tess.vbo->ofs_lightmap = tess.vbo->ofs_st + sizeof(tess.texCoords[0][0]); - - tess.vbo->ofs_vertexcolor = tess.vbo->ofs_st + sizeof(tess.texCoords[0][0]) * 2 * SHADER_MAX_VERTEXES; - - tess.vbo->stride_xyz = sizeof(tess.xyz[0]); - tess.vbo->stride_normal = sizeof(tess.normal[0]); - tess.vbo->stride_tangent = sizeof(tess.tangent[0]); - tess.vbo->stride_bitangent = sizeof(tess.bitangent[0]); - tess.vbo->stride_vertexcolor = sizeof(tess.vertexColors[0]); - tess.vbo->stride_st = sizeof(tess.texCoords[0][0]) * 2; - tess.vbo->stride_lightmap = sizeof(tess.texCoords[0][0]) * 2; - - dataSize = sizeof(tess.indexes[0]) * SHADER_MAX_INDEXES; - - data = ri.Malloc(dataSize); - memset(data, 0, dataSize); - - tess.ibo = R_CreateIBO("tessVertexArray_IBO", data, dataSize, VBO_USAGE_DYNAMIC); - - ri.Free(data); - - R_BindNullVBO(); - R_BindNullIBO(); - - GL_CheckErrors(); -} - -/* -============ -R_ShutdownVBOs -============ -*/ -void R_ShutdownVBOs(void) -{ - int i; - VBO_t *vbo; - IBO_t *ibo; - - ri.Printf(PRINT_ALL, "------- R_ShutdownVBOs -------\n"); - - R_BindNullVBO(); - R_BindNullIBO(); - - - for(i = 0; i < tr.numVBOs; i++) - { - vbo = tr.vbos[i]; - - if(vbo->vertexesVBO) - { - qglDeleteBuffersARB(1, &vbo->vertexesVBO); - } - - //ri.Free(vbo); - } - - for(i = 0; i < tr.numIBOs; i++) - { - ibo = tr.ibos[i]; - - if(ibo->indexesVBO) - { - qglDeleteBuffersARB(1, &ibo->indexesVBO); - } - - //ri.Free(ibo); - } - - tr.numVBOs = 0; - tr.numIBOs = 0; -} - -/* -============ -R_VBOList_f -============ -*/ -void R_VBOList_f(void) -{ - int i; - VBO_t *vbo; - IBO_t *ibo; - int vertexesSize = 0; - int indexesSize = 0; - - ri.Printf(PRINT_ALL, " size name\n"); - ri.Printf(PRINT_ALL, "----------------------------------------------------------\n"); - - for(i = 0; i < tr.numVBOs; i++) - { - vbo = tr.vbos[i]; - - ri.Printf(PRINT_ALL, "%d.%02d MB %s\n", vbo->vertexesSize / (1024 * 1024), - (vbo->vertexesSize % (1024 * 1024)) * 100 / (1024 * 1024), vbo->name); - - vertexesSize += vbo->vertexesSize; - } - - for(i = 0; i < tr.numIBOs; i++) - { - ibo = tr.ibos[i]; - - ri.Printf(PRINT_ALL, "%d.%02d MB %s\n", ibo->indexesSize / (1024 * 1024), - (ibo->indexesSize % (1024 * 1024)) * 100 / (1024 * 1024), ibo->name); - - indexesSize += ibo->indexesSize; - } - - ri.Printf(PRINT_ALL, " %i total VBOs\n", tr.numVBOs); - ri.Printf(PRINT_ALL, " %d.%02d MB total vertices memory\n", vertexesSize / (1024 * 1024), - (vertexesSize % (1024 * 1024)) * 100 / (1024 * 1024)); - - ri.Printf(PRINT_ALL, " %i total IBOs\n", tr.numIBOs); - ri.Printf(PRINT_ALL, " %d.%02d MB total triangle indices memory\n", indexesSize / (1024 * 1024), - (indexesSize % (1024 * 1024)) * 100 / (1024 * 1024)); -} - - -/* -============== -RB_UpdateVBOs - -Adapted from Tess_UpdateVBOs from xreal - -Tr3B: update the default VBO to replace the client side vertex arrays -============== -*/ -void RB_UpdateVBOs(unsigned int attribBits) -{ - GLimp_LogComment("--- RB_UpdateVBOs ---\n"); - - backEnd.pc.c_dynamicVboDraws++; - - // update the default VBO - if(tess.numVertexes > 0 && tess.numVertexes <= SHADER_MAX_VERTEXES) - { - R_BindVBO(tess.vbo); - - if(attribBits & ATTR_BITS) - { - if(attribBits & ATTR_POSITION) - { - qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_xyz, tess.numVertexes * sizeof(tess.xyz[0]), tess.xyz); - } - - if(attribBits & ATTR_TEXCOORD || attribBits & ATTR_LIGHTCOORD) - { - // these are interleaved, so we update both if either need it - qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_st, tess.numVertexes * sizeof(tess.texCoords[0][0]) * 2, tess.texCoords); - } - - if(attribBits & ATTR_NORMAL) - { - qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_normal, tess.numVertexes * sizeof(tess.normal[0]), tess.normal); - } - - if(attribBits & ATTR_TANGENT) - { - qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_tangent, tess.numVertexes * sizeof(tess.tangent[0]), tess.tangent); - } - - if(attribBits & ATTR_BITANGENT) - { - qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_bitangent, tess.numVertexes * sizeof(tess.bitangent[0]), tess.bitangent); - } - - if(attribBits & ATTR_COLOR) - { - qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_vertexcolor, tess.numVertexes * sizeof(tess.vertexColors[0]), tess.vertexColors); - } - } - else - { - qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_xyz, tess.numVertexes * sizeof(tess.xyz[0]), tess.xyz); - qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_st, tess.numVertexes * sizeof(tess.texCoords[0][0]) * 2, tess.texCoords); - qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_normal, tess.numVertexes * sizeof(tess.normal[0]), tess.normal); - qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_tangent, tess.numVertexes * sizeof(tess.tangent[0]), tess.tangent); - qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_bitangent, tess.numVertexes * sizeof(tess.bitangent[0]), tess.bitangent); - qglBufferSubDataARB(GL_ARRAY_BUFFER_ARB, tess.vbo->ofs_vertexcolor, tess.numVertexes * sizeof(tess.vertexColors[0]), tess.vertexColors); - } - - } - - // update the default IBO - if(tess.numIndexes > 0 && tess.numIndexes <= SHADER_MAX_INDEXES) - { - R_BindIBO(tess.ibo); - - qglBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, tess.numIndexes * sizeof(tess.indexes[0]), tess.indexes); - } -} diff --git a/code/renderer/iqm.h b/code/renderercommon/iqm.h similarity index 100% rename from code/renderer/iqm.h rename to code/renderercommon/iqm.h diff --git a/code/rend2/qgl.h b/code/renderercommon/qgl.h similarity index 99% rename from code/rend2/qgl.h rename to code/renderercommon/qgl.h index 6013a87c..9dc1b8c1 100644 --- a/code/rend2/qgl.h +++ b/code/renderercommon/qgl.h @@ -39,6 +39,344 @@ extern void (APIENTRYP qglMultiTexCoord2fARB) (GLenum target, GLfloat s, GLfloat extern void (APIENTRYP qglLockArraysEXT) (GLint first, GLsizei count); extern void (APIENTRYP qglUnlockArraysEXT) (void); + +//=========================================================================== + +#define qglAccum glAccum +#define qglAlphaFunc glAlphaFunc +#define qglAreTexturesResident glAreTexturesResident +#define qglArrayElement glArrayElement +#define qglBegin glBegin +#define qglBindTexture glBindTexture +#define qglBitmap glBitmap +#define qglBlendFunc glBlendFunc +#define qglCallList glCallList +#define qglCallLists glCallLists +#define qglClear glClear +#define qglClearAccum glClearAccum +#define qglClearColor glClearColor +#define qglClearDepth glClearDepth +#define qglClearIndex glClearIndex +#define qglClearStencil glClearStencil +#define qglClipPlane glClipPlane +#define qglColor3b glColor3b +#define qglColor3bv glColor3bv +#define qglColor3d glColor3d +#define qglColor3dv glColor3dv +#define qglColor3f glColor3f +#define qglColor3fv glColor3fv +#define qglColor3i glColor3i +#define qglColor3iv glColor3iv +#define qglColor3s glColor3s +#define qglColor3sv glColor3sv +#define qglColor3ub glColor3ub +#define qglColor3ubv glColor3ubv +#define qglColor3ui glColor3ui +#define qglColor3uiv glColor3uiv +#define qglColor3us glColor3us +#define qglColor3usv glColor3usv +#define qglColor4b glColor4b +#define qglColor4bv glColor4bv +#define qglColor4d glColor4d +#define qglColor4dv glColor4dv +#define qglColor4f glColor4f +#define qglColor4fv glColor4fv +#define qglColor4i glColor4i +#define qglColor4iv glColor4iv +#define qglColor4s glColor4s +#define qglColor4sv glColor4sv +#define qglColor4ub glColor4ub +#define qglColor4ubv glColor4ubv +#define qglColor4ui glColor4ui +#define qglColor4uiv glColor4uiv +#define qglColor4us glColor4us +#define qglColor4usv glColor4usv +#define qglColorMask glColorMask +#define qglColorMaterial glColorMaterial +#define qglColorPointer glColorPointer +#define qglCopyPixels glCopyPixels +#define qglCopyTexImage1D glCopyTexImage1D +#define qglCopyTexImage2D glCopyTexImage2D +#define qglCopyTexSubImage1D glCopyTexSubImage1D +#define qglCopyTexSubImage2D glCopyTexSubImage2D +#define qglCullFace glCullFace +#define qglDeleteLists glDeleteLists +#define qglDeleteTextures glDeleteTextures +#define qglDepthFunc glDepthFunc +#define qglDepthMask glDepthMask +#define qglDepthRange glDepthRange +#define qglDisable glDisable +#define qglDisableClientState glDisableClientState +#define qglDrawArrays glDrawArrays +#define qglDrawBuffer glDrawBuffer +#define qglDrawElements glDrawElements +#define qglDrawPixels glDrawPixels +#define qglEdgeFlag glEdgeFlag +#define qglEdgeFlagPointer glEdgeFlagPointer +#define qglEdgeFlagv glEdgeFlagv +#define qglEnable glEnable +#define qglEnableClientState glEnableClientState +#define qglEnd glEnd +#define qglEndList glEndList +#define qglEvalCoord1d glEvalCoord1d +#define qglEvalCoord1dv glEvalCoord1dv +#define qglEvalCoord1f glEvalCoord1f +#define qglEvalCoord1fv glEvalCoord1fv +#define qglEvalCoord2d glEvalCoord2d +#define qglEvalCoord2dv glEvalCoord2dv +#define qglEvalCoord2f glEvalCoord2f +#define qglEvalCoord2fv glEvalCoord2fv +#define qglEvalMesh1 glEvalMesh1 +#define qglEvalMesh2 glEvalMesh2 +#define qglEvalPoint1 glEvalPoint1 +#define qglEvalPoint2 glEvalPoint2 +#define qglFeedbackBuffer glFeedbackBuffer +#define qglFinish glFinish +#define qglFlush glFlush +#define qglFogf glFogf +#define qglFogfv glFogfv +#define qglFogi glFogi +#define qglFogiv glFogiv +#define qglFrontFace glFrontFace +#define qglFrustum glFrustum +#define qglGenLists glGenLists +#define qglGenTextures glGenTextures +#define qglGetBooleanv glGetBooleanv +#define qglGetClipPlane glGetClipPlane +#define qglGetDoublev glGetDoublev +#define qglGetError glGetError +#define qglGetFloatv glGetFloatv +#define qglGetIntegerv glGetIntegerv +#define qglGetLightfv glGetLightfv +#define qglGetLightiv glGetLightiv +#define qglGetMapdv glGetMapdv +#define qglGetMapfv glGetMapfv +#define qglGetMapiv glGetMapiv +#define qglGetMaterialfv glGetMaterialfv +#define qglGetMaterialiv glGetMaterialiv +#define qglGetPixelMapfv glGetPixelMapfv +#define qglGetPixelMapuiv glGetPixelMapuiv +#define qglGetPixelMapusv glGetPixelMapusv +#define qglGetPointerv glGetPointerv +#define qglGetPolygonStipple glGetPolygonStipple +#define qglGetString glGetString +#define qglGetTexGendv glGetTexGendv +#define qglGetTexGenfv glGetTexGenfv +#define qglGetTexGeniv glGetTexGeniv +#define qglGetTexImage glGetTexImage +#define qglGetTexLevelParameterfv glGetTexLevelParameterfv +#define qglGetTexLevelParameteriv glGetTexLevelParameteriv +#define qglGetTexParameterfv glGetTexParameterfv +#define qglGetTexParameteriv glGetTexParameteriv +#define qglHint glHint +#define qglIndexMask glIndexMask +#define qglIndexPointer glIndexPointer +#define qglIndexd glIndexd +#define qglIndexdv glIndexdv +#define qglIndexf glIndexf +#define qglIndexfv glIndexfv +#define qglIndexi glIndexi +#define qglIndexiv glIndexiv +#define qglIndexs glIndexs +#define qglIndexsv glIndexsv +#define qglIndexub glIndexub +#define qglIndexubv glIndexubv +#define qglInitNames glInitNames +#define qglInterleavedArrays glInterleavedArrays +#define qglIsEnabled glIsEnabled +#define qglIsList glIsList +#define qglIsTexture glIsTexture +#define qglLightModelf glLightModelf +#define qglLightModelfv glLightModelfv +#define qglLightModeli glLightModeli +#define qglLightModeliv glLightModeliv +#define qglLightf glLightf +#define qglLightfv glLightfv +#define qglLighti glLighti +#define qglLightiv glLightiv +#define qglLineStipple glLineStipple +#define qglLineWidth glLineWidth +#define qglListBase glListBase +#define qglLoadIdentity glLoadIdentity +#define qglLoadMatrixd glLoadMatrixd +#define qglLoadMatrixf glLoadMatrixf +#define qglLoadName glLoadName +#define qglLogicOp glLogicOp +#define qglMap1d glMap1d +#define qglMap1f glMap1f +#define qglMap2d glMap2d +#define qglMap2f glMap2f +#define qglMapGrid1d glMapGrid1d +#define qglMapGrid1f glMapGrid1f +#define qglMapGrid2d glMapGrid2d +#define qglMapGrid2f glMapGrid2f +#define qglMaterialf glMaterialf +#define qglMaterialfv glMaterialfv +#define qglMateriali glMateriali +#define qglMaterialiv glMaterialiv +#define qglMatrixMode glMatrixMode +#define qglMultMatrixd glMultMatrixd +#define qglMultMatrixf glMultMatrixf +#define qglNewList glNewList +#define qglNormal3b glNormal3b +#define qglNormal3bv glNormal3bv +#define qglNormal3d glNormal3d +#define qglNormal3dv glNormal3dv +#define qglNormal3f glNormal3f +#define qglNormal3fv glNormal3fv +#define qglNormal3i glNormal3i +#define qglNormal3iv glNormal3iv +#define qglNormal3s glNormal3s +#define qglNormal3sv glNormal3sv +#define qglNormalPointer glNormalPointer +#define qglOrtho glOrtho +#define qglPassThrough glPassThrough +#define qglPixelMapfv glPixelMapfv +#define qglPixelMapuiv glPixelMapuiv +#define qglPixelMapusv glPixelMapusv +#define qglPixelStoref glPixelStoref +#define qglPixelStorei glPixelStorei +#define qglPixelTransferf glPixelTransferf +#define qglPixelTransferi glPixelTransferi +#define qglPixelZoom glPixelZoom +#define qglPointSize glPointSize +#define qglPolygonMode glPolygonMode +#define qglPolygonOffset glPolygonOffset +#define qglPolygonStipple glPolygonStipple +#define qglPopAttrib glPopAttrib +#define qglPopClientAttrib glPopClientAttrib +#define qglPopMatrix glPopMatrix +#define qglPopName glPopName +#define qglPrioritizeTextures glPrioritizeTextures +#define qglPushAttrib glPushAttrib +#define qglPushClientAttrib glPushClientAttrib +#define qglPushMatrix glPushMatrix +#define qglPushName glPushName +#define qglRasterPos2d glRasterPos2d +#define qglRasterPos2dv glRasterPos2dv +#define qglRasterPos2f glRasterPos2f +#define qglRasterPos2fv glRasterPos2fv +#define qglRasterPos2i glRasterPos2i +#define qglRasterPos2iv glRasterPos2iv +#define qglRasterPos2s glRasterPos2s +#define qglRasterPos2sv glRasterPos2sv +#define qglRasterPos3d glRasterPos3d +#define qglRasterPos3dv glRasterPos3dv +#define qglRasterPos3f glRasterPos3f +#define qglRasterPos3fv glRasterPos3fv +#define qglRasterPos3i glRasterPos3i +#define qglRasterPos3iv glRasterPos3iv +#define qglRasterPos3s glRasterPos3s +#define qglRasterPos3sv glRasterPos3sv +#define qglRasterPos4d glRasterPos4d +#define qglRasterPos4dv glRasterPos4dv +#define qglRasterPos4f glRasterPos4f +#define qglRasterPos4fv glRasterPos4fv +#define qglRasterPos4i glRasterPos4i +#define qglRasterPos4iv glRasterPos4iv +#define qglRasterPos4s glRasterPos4s +#define qglRasterPos4sv glRasterPos4sv +#define qglReadBuffer glReadBuffer +#define qglReadPixels glReadPixels +#define qglRectd glRectd +#define qglRectdv glRectdv +#define qglRectf glRectf +#define qglRectfv glRectfv +#define qglRecti glRecti +#define qglRectiv glRectiv +#define qglRects glRects +#define qglRectsv glRectsv +#define qglRenderMode glRenderMode +#define qglRotated glRotated +#define qglRotatef glRotatef +#define qglScaled glScaled +#define qglScalef glScalef +#define qglScissor glScissor +#define qglSelectBuffer glSelectBuffer +#define qglShadeModel glShadeModel +#define qglStencilFunc glStencilFunc +#define qglStencilMask glStencilMask +#define qglStencilOp glStencilOp +#define qglTexCoord1d glTexCoord1d +#define qglTexCoord1dv glTexCoord1dv +#define qglTexCoord1f glTexCoord1f +#define qglTexCoord1fv glTexCoord1fv +#define qglTexCoord1i glTexCoord1i +#define qglTexCoord1iv glTexCoord1iv +#define qglTexCoord1s glTexCoord1s +#define qglTexCoord1sv glTexCoord1sv +#define qglTexCoord2d glTexCoord2d +#define qglTexCoord2dv glTexCoord2dv +#define qglTexCoord2f glTexCoord2f +#define qglTexCoord2fv glTexCoord2fv +#define qglTexCoord2i glTexCoord2i +#define qglTexCoord2iv glTexCoord2iv +#define qglTexCoord2s glTexCoord2s +#define qglTexCoord2sv glTexCoord2sv +#define qglTexCoord3d glTexCoord3d +#define qglTexCoord3dv glTexCoord3dv +#define qglTexCoord3f glTexCoord3f +#define qglTexCoord3fv glTexCoord3fv +#define qglTexCoord3i glTexCoord3i +#define qglTexCoord3iv glTexCoord3iv +#define qglTexCoord3s glTexCoord3s +#define qglTexCoord3sv glTexCoord3sv +#define qglTexCoord4d glTexCoord4d +#define qglTexCoord4dv glTexCoord4dv +#define qglTexCoord4f glTexCoord4f +#define qglTexCoord4fv glTexCoord4fv +#define qglTexCoord4i glTexCoord4i +#define qglTexCoord4iv glTexCoord4iv +#define qglTexCoord4s glTexCoord4s +#define qglTexCoord4sv glTexCoord4sv +#define qglTexCoordPointer glTexCoordPointer +#define qglTexEnvf glTexEnvf +#define qglTexEnvfv glTexEnvfv +#define qglTexEnvi glTexEnvi +#define qglTexEnviv glTexEnviv +#define qglTexGend glTexGend +#define qglTexGendv glTexGendv +#define qglTexGenf glTexGenf +#define qglTexGenfv glTexGenfv +#define qglTexGeni glTexGeni +#define qglTexGeniv glTexGeniv +#define qglTexImage1D glTexImage1D +#define qglTexImage2D glTexImage2D +#define qglTexParameterf glTexParameterf +#define qglTexParameterfv glTexParameterfv +#define qglTexParameteri glTexParameteri +#define qglTexParameteriv glTexParameteriv +#define qglTexSubImage1D glTexSubImage1D +#define qglTexSubImage2D glTexSubImage2D +#define qglTranslated glTranslated +#define qglTranslatef glTranslatef +#define qglVertex2d glVertex2d +#define qglVertex2dv glVertex2dv +#define qglVertex2f glVertex2f +#define qglVertex2fv glVertex2fv +#define qglVertex2i glVertex2i +#define qglVertex2iv glVertex2iv +#define qglVertex2s glVertex2s +#define qglVertex2sv glVertex2sv +#define qglVertex3d glVertex3d +#define qglVertex3dv glVertex3dv +#define qglVertex3f glVertex3f +#define qglVertex3fv glVertex3fv +#define qglVertex3i glVertex3i +#define qglVertex3iv glVertex3iv +#define qglVertex3s glVertex3s +#define qglVertex3sv glVertex3sv +#define qglVertex4d glVertex4d +#define qglVertex4dv glVertex4dv +#define qglVertex4f glVertex4f +#define qglVertex4fv glVertex4fv +#define qglVertex4i glVertex4i +#define qglVertex4iv glVertex4iv +#define qglVertex4s glVertex4s +#define qglVertex4sv glVertex4sv +#define qglVertexPointer glVertexPointer +#define qglViewport glViewport + // GL_EXT_draw_range_elements extern void (APIENTRY * qglDrawRangeElementsEXT) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices); @@ -415,341 +753,4 @@ extern HGLRC(APIENTRY * qwglCreateContextAttribsARB) (HDC hdC, HGLRC hS extern GLXContext (APIENTRY * qglXCreateContextAttribsARB) (Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list); #endif -//=========================================================================== - -#define qglAccum glAccum -#define qglAlphaFunc glAlphaFunc -#define qglAreTexturesResident glAreTexturesResident -#define qglArrayElement glArrayElement -#define qglBegin glBegin -#define qglBindTexture glBindTexture -#define qglBitmap glBitmap -#define qglBlendFunc glBlendFunc -#define qglCallList glCallList -#define qglCallLists glCallLists -#define qglClear glClear -#define qglClearAccum glClearAccum -#define qglClearColor glClearColor -#define qglClearDepth glClearDepth -#define qglClearIndex glClearIndex -#define qglClearStencil glClearStencil -#define qglClipPlane glClipPlane -#define qglColor3b glColor3b -#define qglColor3bv glColor3bv -#define qglColor3d glColor3d -#define qglColor3dv glColor3dv -#define qglColor3f glColor3f -#define qglColor3fv glColor3fv -#define qglColor3i glColor3i -#define qglColor3iv glColor3iv -#define qglColor3s glColor3s -#define qglColor3sv glColor3sv -#define qglColor3ub glColor3ub -#define qglColor3ubv glColor3ubv -#define qglColor3ui glColor3ui -#define qglColor3uiv glColor3uiv -#define qglColor3us glColor3us -#define qglColor3usv glColor3usv -#define qglColor4b glColor4b -#define qglColor4bv glColor4bv -#define qglColor4d glColor4d -#define qglColor4dv glColor4dv -#define qglColor4f glColor4f -#define qglColor4fv glColor4fv -#define qglColor4i glColor4i -#define qglColor4iv glColor4iv -#define qglColor4s glColor4s -#define qglColor4sv glColor4sv -#define qglColor4ub glColor4ub -#define qglColor4ubv glColor4ubv -#define qglColor4ui glColor4ui -#define qglColor4uiv glColor4uiv -#define qglColor4us glColor4us -#define qglColor4usv glColor4usv -#define qglColorMask glColorMask -#define qglColorMaterial glColorMaterial -#define qglColorPointer glColorPointer -#define qglCopyPixels glCopyPixels -#define qglCopyTexImage1D glCopyTexImage1D -#define qglCopyTexImage2D glCopyTexImage2D -#define qglCopyTexSubImage1D glCopyTexSubImage1D -#define qglCopyTexSubImage2D glCopyTexSubImage2D -#define qglCullFace glCullFace -#define qglDeleteLists glDeleteLists -#define qglDeleteTextures glDeleteTextures -#define qglDepthFunc glDepthFunc -#define qglDepthMask glDepthMask -#define qglDepthRange glDepthRange -#define qglDisable glDisable -#define qglDisableClientState glDisableClientState -#define qglDrawArrays glDrawArrays -#define qglDrawBuffer glDrawBuffer -#define qglDrawElements glDrawElements -#define qglDrawPixels glDrawPixels -#define qglEdgeFlag glEdgeFlag -#define qglEdgeFlagPointer glEdgeFlagPointer -#define qglEdgeFlagv glEdgeFlagv -#define qglEnable glEnable -#define qglEnableClientState glEnableClientState -#define qglEnd glEnd -#define qglEndList glEndList -#define qglEvalCoord1d glEvalCoord1d -#define qglEvalCoord1dv glEvalCoord1dv -#define qglEvalCoord1f glEvalCoord1f -#define qglEvalCoord1fv glEvalCoord1fv -#define qglEvalCoord2d glEvalCoord2d -#define qglEvalCoord2dv glEvalCoord2dv -#define qglEvalCoord2f glEvalCoord2f -#define qglEvalCoord2fv glEvalCoord2fv -#define qglEvalMesh1 glEvalMesh1 -#define qglEvalMesh2 glEvalMesh2 -#define qglEvalPoint1 glEvalPoint1 -#define qglEvalPoint2 glEvalPoint2 -#define qglFeedbackBuffer glFeedbackBuffer -#define qglFinish glFinish -#define qglFlush glFlush -#define qglFogf glFogf -#define qglFogfv glFogfv -#define qglFogi glFogi -#define qglFogiv glFogiv -#define qglFrontFace glFrontFace -#define qglFrustum glFrustum -#define qglGenLists glGenLists -#define qglGenTextures glGenTextures -#define qglGetBooleanv glGetBooleanv -#define qglGetClipPlane glGetClipPlane -#define qglGetDoublev glGetDoublev -#define qglGetError glGetError -#define qglGetFloatv glGetFloatv -#define qglGetIntegerv glGetIntegerv -#define qglGetLightfv glGetLightfv -#define qglGetLightiv glGetLightiv -#define qglGetMapdv glGetMapdv -#define qglGetMapfv glGetMapfv -#define qglGetMapiv glGetMapiv -#define qglGetMaterialfv glGetMaterialfv -#define qglGetMaterialiv glGetMaterialiv -#define qglGetPixelMapfv glGetPixelMapfv -#define qglGetPixelMapuiv glGetPixelMapuiv -#define qglGetPixelMapusv glGetPixelMapusv -#define qglGetPointerv glGetPointerv -#define qglGetPolygonStipple glGetPolygonStipple -#define qglGetString glGetString -#define qglGetTexGendv glGetTexGendv -#define qglGetTexGenfv glGetTexGenfv -#define qglGetTexGeniv glGetTexGeniv -#define qglGetTexImage glGetTexImage -#define qglGetTexLevelParameterfv glGetTexLevelParameterfv -#define qglGetTexLevelParameteriv glGetTexLevelParameteriv -#define qglGetTexParameterfv glGetTexParameterfv -#define qglGetTexParameteriv glGetTexParameteriv -#define qglHint glHint -#define qglIndexMask glIndexMask -#define qglIndexPointer glIndexPointer -#define qglIndexd glIndexd -#define qglIndexdv glIndexdv -#define qglIndexf glIndexf -#define qglIndexfv glIndexfv -#define qglIndexi glIndexi -#define qglIndexiv glIndexiv -#define qglIndexs glIndexs -#define qglIndexsv glIndexsv -#define qglIndexub glIndexub -#define qglIndexubv glIndexubv -#define qglInitNames glInitNames -#define qglInterleavedArrays glInterleavedArrays -#define qglIsEnabled glIsEnabled -#define qglIsList glIsList -#define qglIsTexture glIsTexture -#define qglLightModelf glLightModelf -#define qglLightModelfv glLightModelfv -#define qglLightModeli glLightModeli -#define qglLightModeliv glLightModeliv -#define qglLightf glLightf -#define qglLightfv glLightfv -#define qglLighti glLighti -#define qglLightiv glLightiv -#define qglLineStipple glLineStipple -#define qglLineWidth glLineWidth -#define qglListBase glListBase -#define qglLoadIdentity glLoadIdentity -#define qglLoadMatrixd glLoadMatrixd -#define qglLoadMatrixf glLoadMatrixf -#define qglLoadName glLoadName -#define qglLogicOp glLogicOp -#define qglMap1d glMap1d -#define qglMap1f glMap1f -#define qglMap2d glMap2d -#define qglMap2f glMap2f -#define qglMapGrid1d glMapGrid1d -#define qglMapGrid1f glMapGrid1f -#define qglMapGrid2d glMapGrid2d -#define qglMapGrid2f glMapGrid2f -#define qglMaterialf glMaterialf -#define qglMaterialfv glMaterialfv -#define qglMateriali glMateriali -#define qglMaterialiv glMaterialiv -#define qglMatrixMode glMatrixMode -#define qglMultMatrixd glMultMatrixd -#define qglMultMatrixf glMultMatrixf -#define qglNewList glNewList -#define qglNormal3b glNormal3b -#define qglNormal3bv glNormal3bv -#define qglNormal3d glNormal3d -#define qglNormal3dv glNormal3dv -#define qglNormal3f glNormal3f -#define qglNormal3fv glNormal3fv -#define qglNormal3i glNormal3i -#define qglNormal3iv glNormal3iv -#define qglNormal3s glNormal3s -#define qglNormal3sv glNormal3sv -#define qglNormalPointer glNormalPointer -#define qglOrtho glOrtho -#define qglPassThrough glPassThrough -#define qglPixelMapfv glPixelMapfv -#define qglPixelMapuiv glPixelMapuiv -#define qglPixelMapusv glPixelMapusv -#define qglPixelStoref glPixelStoref -#define qglPixelStorei glPixelStorei -#define qglPixelTransferf glPixelTransferf -#define qglPixelTransferi glPixelTransferi -#define qglPixelZoom glPixelZoom -#define qglPointSize glPointSize -#define qglPolygonMode glPolygonMode -#define qglPolygonOffset glPolygonOffset -#define qglPolygonStipple glPolygonStipple -#define qglPopAttrib glPopAttrib -#define qglPopClientAttrib glPopClientAttrib -#define qglPopMatrix glPopMatrix -#define qglPopName glPopName -#define qglPrioritizeTextures glPrioritizeTextures -#define qglPushAttrib glPushAttrib -#define qglPushClientAttrib glPushClientAttrib -#define qglPushMatrix glPushMatrix -#define qglPushName glPushName -#define qglRasterPos2d glRasterPos2d -#define qglRasterPos2dv glRasterPos2dv -#define qglRasterPos2f glRasterPos2f -#define qglRasterPos2fv glRasterPos2fv -#define qglRasterPos2i glRasterPos2i -#define qglRasterPos2iv glRasterPos2iv -#define qglRasterPos2s glRasterPos2s -#define qglRasterPos2sv glRasterPos2sv -#define qglRasterPos3d glRasterPos3d -#define qglRasterPos3dv glRasterPos3dv -#define qglRasterPos3f glRasterPos3f -#define qglRasterPos3fv glRasterPos3fv -#define qglRasterPos3i glRasterPos3i -#define qglRasterPos3iv glRasterPos3iv -#define qglRasterPos3s glRasterPos3s -#define qglRasterPos3sv glRasterPos3sv -#define qglRasterPos4d glRasterPos4d -#define qglRasterPos4dv glRasterPos4dv -#define qglRasterPos4f glRasterPos4f -#define qglRasterPos4fv glRasterPos4fv -#define qglRasterPos4i glRasterPos4i -#define qglRasterPos4iv glRasterPos4iv -#define qglRasterPos4s glRasterPos4s -#define qglRasterPos4sv glRasterPos4sv -#define qglReadBuffer glReadBuffer -#define qglReadPixels glReadPixels -#define qglRectd glRectd -#define qglRectdv glRectdv -#define qglRectf glRectf -#define qglRectfv glRectfv -#define qglRecti glRecti -#define qglRectiv glRectiv -#define qglRects glRects -#define qglRectsv glRectsv -#define qglRenderMode glRenderMode -#define qglRotated glRotated -#define qglRotatef glRotatef -#define qglScaled glScaled -#define qglScalef glScalef -#define qglScissor glScissor -#define qglSelectBuffer glSelectBuffer -#define qglShadeModel glShadeModel -#define qglStencilFunc glStencilFunc -#define qglStencilMask glStencilMask -#define qglStencilOp glStencilOp -#define qglTexCoord1d glTexCoord1d -#define qglTexCoord1dv glTexCoord1dv -#define qglTexCoord1f glTexCoord1f -#define qglTexCoord1fv glTexCoord1fv -#define qglTexCoord1i glTexCoord1i -#define qglTexCoord1iv glTexCoord1iv -#define qglTexCoord1s glTexCoord1s -#define qglTexCoord1sv glTexCoord1sv -#define qglTexCoord2d glTexCoord2d -#define qglTexCoord2dv glTexCoord2dv -#define qglTexCoord2f glTexCoord2f -#define qglTexCoord2fv glTexCoord2fv -#define qglTexCoord2i glTexCoord2i -#define qglTexCoord2iv glTexCoord2iv -#define qglTexCoord2s glTexCoord2s -#define qglTexCoord2sv glTexCoord2sv -#define qglTexCoord3d glTexCoord3d -#define qglTexCoord3dv glTexCoord3dv -#define qglTexCoord3f glTexCoord3f -#define qglTexCoord3fv glTexCoord3fv -#define qglTexCoord3i glTexCoord3i -#define qglTexCoord3iv glTexCoord3iv -#define qglTexCoord3s glTexCoord3s -#define qglTexCoord3sv glTexCoord3sv -#define qglTexCoord4d glTexCoord4d -#define qglTexCoord4dv glTexCoord4dv -#define qglTexCoord4f glTexCoord4f -#define qglTexCoord4fv glTexCoord4fv -#define qglTexCoord4i glTexCoord4i -#define qglTexCoord4iv glTexCoord4iv -#define qglTexCoord4s glTexCoord4s -#define qglTexCoord4sv glTexCoord4sv -#define qglTexCoordPointer glTexCoordPointer -#define qglTexEnvf glTexEnvf -#define qglTexEnvfv glTexEnvfv -#define qglTexEnvi glTexEnvi -#define qglTexEnviv glTexEnviv -#define qglTexGend glTexGend -#define qglTexGendv glTexGendv -#define qglTexGenf glTexGenf -#define qglTexGenfv glTexGenfv -#define qglTexGeni glTexGeni -#define qglTexGeniv glTexGeniv -#define qglTexImage1D glTexImage1D -#define qglTexImage2D glTexImage2D -#define qglTexParameterf glTexParameterf -#define qglTexParameterfv glTexParameterfv -#define qglTexParameteri glTexParameteri -#define qglTexParameteriv glTexParameteriv -#define qglTexSubImage1D glTexSubImage1D -#define qglTexSubImage2D glTexSubImage2D -#define qglTranslated glTranslated -#define qglTranslatef glTranslatef -#define qglVertex2d glVertex2d -#define qglVertex2dv glVertex2dv -#define qglVertex2f glVertex2f -#define qglVertex2fv glVertex2fv -#define qglVertex2i glVertex2i -#define qglVertex2iv glVertex2iv -#define qglVertex2s glVertex2s -#define qglVertex2sv glVertex2sv -#define qglVertex3d glVertex3d -#define qglVertex3dv glVertex3dv -#define qglVertex3f glVertex3f -#define qglVertex3fv glVertex3fv -#define qglVertex3i glVertex3i -#define qglVertex3iv glVertex3iv -#define qglVertex3s glVertex3s -#define qglVertex3sv glVertex3sv -#define qglVertex4d glVertex4d -#define qglVertex4dv glVertex4dv -#define qglVertex4f glVertex4f -#define qglVertex4fv glVertex4fv -#define qglVertex4i glVertex4i -#define qglVertex4iv glVertex4iv -#define qglVertex4s glVertex4s -#define qglVertex4sv glVertex4sv -#define qglVertexPointer glVertexPointer -#define qglViewport glViewport - #endif diff --git a/code/renderercommon/tr_common.h b/code/renderercommon/tr_common.h new file mode 100644 index 00000000..31de1a8f --- /dev/null +++ b/code/renderercommon/tr_common.h @@ -0,0 +1,157 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake III Arena source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake III Arena source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +#ifndef TR_COMMON_H +#define TR_COMMON_H + +#include "../qcommon/q_shared.h" +#include "../renderercommon/tr_public.h" +#include "qgl.h" + +typedef enum +{ + IMGTYPE_COLORALPHA, // for color, lightmap, diffuse, and specular + IMGTYPE_NORMAL, + IMGTYPE_NORMALHEIGHT, + IMGTYPE_DELUXE, // normals are swizzled, deluxe are not +} imgType_t; + +typedef enum +{ + IMGFLAG_NONE = 0x0000, + IMGFLAG_MIPMAP = 0x0001, + IMGFLAG_PICMIP = 0x0002, + IMGFLAG_CUBEMAP = 0x0004, + IMGFLAG_NO_COMPRESSION = 0x0010, + IMGFLAG_NOLIGHTSCALE = 0x0020, + IMGFLAG_CLAMPTOEDGE = 0x0040, + IMGFLAG_SRGB = 0x0080, + IMGFLAG_GENNORMALMAP = 0x0100, +} imgFlags_t; + +typedef struct image_s { + char imgName[MAX_QPATH]; // game path, including extension + int width, height; // source image + int uploadWidth, uploadHeight; // after power of two and picmip but not including clamp to MAX_TEXTURE_SIZE + GLuint texnum; // gl texture binding + + int frameUsed; // for texture usage in frame statistics + + int internalFormat; + int TMU; // only needed for voodoo2 + + imgType_t type; + imgFlags_t flags; + + struct image_s* next; +} image_t; + +// any change in the LIGHTMAP_* defines here MUST be reflected in +// R_FindShader() in tr_bsp.c +#define LIGHTMAP_2D -4 // shader is for 2D rendering +#define LIGHTMAP_BY_VERTEX -3 // pre-lit triangle models +#define LIGHTMAP_WHITEIMAGE -2 +#define LIGHTMAP_NONE -1 + +extern refimport_t ri; +extern glconfig_t glConfig; // outside of TR since it shouldn't be cleared during ref re-init + +// These variables should live inside glConfig but can't because of +// compatibility issues to the original ID vms. If you release a stand-alone +// game and your mod uses tr_types.h from this build you can safely move them +// to the glconfig_t struct. +extern qboolean textureFilterAnisotropic; +extern int maxAnisotropy; +extern float displayAspect; + +// +// cvars +// +extern cvar_t *r_stencilbits; // number of desired stencil bits +extern cvar_t *r_depthbits; // number of desired depth bits +extern cvar_t *r_colorbits; // number of desired color bits, only relevant for fullscreen +extern cvar_t *r_texturebits; // number of desired texture bits +extern cvar_t *r_ext_multisample; + // 0 = use framebuffer depth + // 16 = use 16-bit textures + // 32 = use 32-bit textures + // all else = error + +extern cvar_t *r_mode; // video mode +extern cvar_t *r_noborder; +extern cvar_t *r_fullscreen; +extern cvar_t *r_ignorehwgamma; // overrides hardware gamma capabilities +extern cvar_t *r_drawBuffer; +extern cvar_t *r_swapInterval; + +extern cvar_t *r_allowExtensions; // global enable/disable of OpenGL extensions +extern cvar_t *r_ext_compressed_textures; // these control use of specific extensions +extern cvar_t *r_ext_multitexture; +extern cvar_t *r_ext_compiled_vertex_array; +extern cvar_t *r_ext_texture_env_add; + +extern cvar_t *r_ext_texture_filter_anisotropic; +extern cvar_t *r_ext_max_anisotropy; + +extern cvar_t *r_stereoEnabled; + +extern cvar_t *r_saveFontData; + +qboolean R_GetModeInfo( int *width, int *height, float *windowAspect, int mode ); + +float R_NoiseGet4f( float x, float y, float z, float t ); +void R_NoiseInit( void ); + +image_t *R_FindImageFile( const char *name, imgType_t type, imgFlags_t flags ); +image_t *R_CreateImage( const char *name, byte *pic, int width, int height, imgType_t type, imgFlags_t flags, int internalFormat ); + +void R_IssuePendingRenderCommands( void ); +qhandle_t RE_RegisterShaderLightMap( const char *name, int lightmapIndex ); +qhandle_t RE_RegisterShader( const char *name ); +qhandle_t RE_RegisterShaderNoMip( const char *name ); +qhandle_t RE_RegisterShaderFromImage(const char *name, int lightmapIndex, image_t *image, qboolean mipRawImage); + +// font stuff +void R_InitFreeType( void ); +void R_DoneFreeType( void ); +void RE_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font); + +/* +==================================================================== + +IMPLEMENTATION SPECIFIC FUNCTIONS + +==================================================================== +*/ + +void GLimp_Init( void ); +void GLimp_Shutdown( void ); +void GLimp_EndFrame( void ); + +void GLimp_LogComment( char *comment ); +void GLimp_Minimize(void); + +void GLimp_SetGamma( unsigned char red[256], + unsigned char green[256], + unsigned char blue[256] ); + + +#endif diff --git a/code/rend2/tr_font.c b/code/renderercommon/tr_font.c similarity index 98% rename from code/rend2/tr_font.c rename to code/renderercommon/tr_font.c index 87465e52..4b641bac 100644 --- a/code/rend2/tr_font.c +++ b/code/renderercommon/tr_font.c @@ -68,15 +68,15 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // uncheck the exclude from build check box in the FreeType2 area of the Renderer project. -#include "tr_local.h" +#include "tr_common.h" #include "../qcommon/qcommon.h" #ifdef BUILD_FREETYPE #include +#include FT_FREETYPE_H #include FT_ERRORS_H #include FT_SYSTEM_H #include FT_IMAGE_H -#include FT_FREETYPE_H #include FT_OUTLINE_H #define _FLOOR(x) ((x) & -64) @@ -356,8 +356,7 @@ void RE_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font) { pointSize = 12; } - // make sure the render thread is stopped - R_SyncRenderThread(); + R_IssuePendingRenderCommands(); if (registeredFontCount >= MAX_FONTS) { ri.Printf(PRINT_WARNING, "RE_RegisterFont: Too many fonts registered already.\n"); @@ -402,6 +401,7 @@ void RE_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font) { font->glyphs[i].glyph = RE_RegisterShaderNoMip(font->glyphs[i].shaderName); } Com_Memcpy(®isteredFont[registeredFontCount++], font, sizeof(fontInfo_t)); + ri.FS_FreeFile(faceData); return; } @@ -436,12 +436,12 @@ void RE_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font) { // make a 256x256 image buffer, once it is full, register it, clean it and keep going // until all glyphs are rendered - out = ri.Malloc(1024*1024); + out = ri.Malloc(256*256); if (out == NULL) { ri.Printf(PRINT_WARNING, "RE_RegisterFont: ri.Malloc failure during output image creation.\n"); return; } - Com_Memset(out, 0, 1024*1024); + Com_Memset(out, 0, 256*256); maxHeight = 0; @@ -493,18 +493,19 @@ void RE_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font) { } //Com_sprintf (name, sizeof(name), "fonts/fontImage_%i_%i", imageNumber++, pointSize); - image = R_CreateImage(name, imageBuff, 256, 256, qfalse, qfalse, GL_CLAMP_TO_EDGE); + image = R_CreateImage(name, imageBuff, 256, 256, IMGTYPE_COLORALPHA, IMGFLAG_CLAMPTOEDGE, 0 ); h = RE_RegisterShaderFromImage(name, LIGHTMAP_2D, image, qfalse); for (j = lastStart; j < i; j++) { font->glyphs[j].glyph = h; Q_strncpyz(font->glyphs[j].shaderName, name, sizeof(font->glyphs[j].shaderName)); } lastStart = i; - Com_Memset(out, 0, 1024*1024); + Com_Memset(out, 0, 256*256); xOut = 0; yOut = 0; ri.Free(imageBuff); - i++; + if(i == GLYPH_END) + i++; } else { Com_Memcpy(&font->glyphs[i], glyph, sizeof(glyphInfo_t)); i++; diff --git a/code/renderer/tr_image_bmp.c b/code/renderercommon/tr_image_bmp.c similarity index 97% rename from code/renderer/tr_image_bmp.c rename to code/renderercommon/tr_image_bmp.c index 81da4724..594b308d 100644 --- a/code/renderer/tr_image_bmp.c +++ b/code/renderercommon/tr_image_bmp.c @@ -20,11 +20,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ -#include "../qcommon/q_shared.h" -#include "../qcommon/qfiles.h" -#include "../qcommon/qcommon.h" -#include "tr_public.h" -extern refimport_t ri; +#include "tr_common.h" typedef struct { @@ -123,7 +119,6 @@ void R_LoadBMP( const char *name, byte **pic, int *width, int *height ) ri.Error( ERR_DROP, "LoadBMP: header too short (%s)", name ); Com_Memcpy( bmpHeader.palette, buf_p, sizeof( bmpHeader.palette ) ); - buf_p += sizeof(bmpHeader.palette); } if (buffer.b + bmpHeader.bitmapDataOffset > end) diff --git a/code/renderer/tr_image_jpg.c b/code/renderercommon/tr_image_jpg.c similarity index 98% rename from code/renderer/tr_image_jpg.c rename to code/renderercommon/tr_image_jpg.c index 0d34163d..bd81c048 100644 --- a/code/renderer/tr_image_jpg.c +++ b/code/renderercommon/tr_image_jpg.c @@ -20,11 +20,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ -#include "../qcommon/q_shared.h" -#include "../qcommon/qfiles.h" -#include "../qcommon/qcommon.h" -#include "tr_public.h" -extern refimport_t ri; +#include "tr_common.h" /* * Include file for users of JPEG library. @@ -46,7 +42,7 @@ extern refimport_t ri; # endif #endif -static void R_JPGErrorExit(j_common_ptr cinfo) +static void __attribute__((__noreturn__)) R_JPGErrorExit(j_common_ptr cinfo) { char buffer[JMSG_LENGTH_MAX]; diff --git a/code/renderer/tr_image_pcx.c b/code/renderercommon/tr_image_pcx.c similarity index 96% rename from code/renderer/tr_image_pcx.c rename to code/renderercommon/tr_image_pcx.c index d0521a55..6bc15dea 100644 --- a/code/renderer/tr_image_pcx.c +++ b/code/renderercommon/tr_image_pcx.c @@ -21,11 +21,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ -#include "../qcommon/q_shared.h" -#include "../qcommon/qfiles.h" -#include "../qcommon/qcommon.h" -#include "tr_public.h" -extern refimport_t ri; +#include "tr_common.h" /* ======================================================================== diff --git a/code/renderer/tr_image_png.c b/code/renderercommon/tr_image_png.c similarity index 99% rename from code/renderer/tr_image_png.c rename to code/renderercommon/tr_image_png.c index 8c2557e1..532454c5 100644 --- a/code/renderer/tr_image_png.c +++ b/code/renderercommon/tr_image_png.c @@ -19,11 +19,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. =========================================================================== */ -#include "../qcommon/q_shared.h" -#include "../qcommon/qfiles.h" -#include "../qcommon/qcommon.h" -#include "tr_public.h" -extern refimport_t ri; +#include "tr_common.h" #include "../qcommon/puff.h" @@ -544,7 +540,6 @@ static uint32_t DecompressIDATs(struct BufferedFile *BF, uint8_t **Buffer) */ DecompressedData = NULL; - DecompressedDataLength = 0; *Buffer = DecompressedData; CompressedData = NULL; diff --git a/code/renderer/tr_image_tga.c b/code/renderercommon/tr_image_tga.c similarity index 97% rename from code/renderer/tr_image_tga.c rename to code/renderercommon/tr_image_tga.c index b10801e7..bcfd0467 100644 --- a/code/renderer/tr_image_tga.c +++ b/code/renderercommon/tr_image_tga.c @@ -20,11 +20,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ -#include "../qcommon/q_shared.h" -#include "../qcommon/qfiles.h" -#include "../qcommon/qcommon.h" -#include "tr_public.h" -extern refimport_t ri; +#include "tr_common.h" /* ======================================================================== @@ -196,11 +192,6 @@ void R_LoadTGA ( const char *name, byte **pic, int *width, int *height) else if (targa_header.image_type==10) { // Runlength encoded RGB images unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j; - red = 0; - green = 0; - blue = 0; - alphabyte = 0xff; - for(row=rows-1; row>=0; row--) { pixbuf = targa_rgba + row*columns*4; for(column=0; columnframeUsed = tr.frameCount; + if ( image ) { + image->frameUsed = tr.frameCount; + } glState.currenttextures[glState.currenttmu] = texnum; qglBindTexture (GL_TEXTURE_2D, texnum); } @@ -215,7 +217,7 @@ void GL_State( unsigned long stateBits ) // if ( diff & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) { - GLenum srcFactor, dstFactor; + GLenum srcFactor = GL_ONE, dstFactor = GL_ONE; if ( stateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) { @@ -249,7 +251,6 @@ void GL_State( unsigned long stateBits ) srcFactor = GL_SRC_ALPHA_SATURATE; break; default: - srcFactor = GL_ONE; // to get warning to shut up ri.Error( ERR_DROP, "GL_State: invalid src blend state bits" ); break; } @@ -281,7 +282,6 @@ void GL_State( unsigned long stateBits ) dstFactor = GL_ONE_MINUS_DST_ALPHA; break; default: - dstFactor = GL_ONE; // to get warning to shut up ri.Error( ERR_DROP, "GL_State: invalid dst blend state bits" ); break; } @@ -545,8 +545,8 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { // change the tess parameters if needed // a "entityMergable" shader is a shader that can have surfaces from seperate // entities merged into a single batch, like smoke and blood puff sprites - if (shader != oldShader || fogNum != oldFogNum || dlighted != oldDlighted - || ( entityNum != oldEntityNum && !shader->entityMergable ) ) { + if ( shader != NULL && ( shader != oldShader || fogNum != oldFogNum || dlighted != oldDlighted + || ( entityNum != oldEntityNum && !shader->entityMergable ) ) ) { if (oldShader != NULL) { RB_EndSurface(); } @@ -668,9 +668,10 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { qglDepthRange (0, 1); } -#if 0 - RB_DrawSun(); -#endif + if (r_drawSun->integer) { + RB_DrawSun(0.1, tr.sunShader); + } + // darken down any stencil shadows RB_ShadowFinish(); @@ -682,7 +683,7 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { /* ============================================================================ -RENDER BACK END THREAD FUNCTIONS +RENDER BACK END FUNCTIONS ============================================================================ */ @@ -734,7 +735,7 @@ void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte * if ( !tr.registered ) { return; } - R_SyncRenderThread(); + R_IssuePendingRenderCommands(); // we definately want to sync every frame for the cinematics qglFinish(); @@ -1111,9 +1112,6 @@ const void *RB_SwapBuffers( const void *data ) { /* ==================== RB_ExecuteRenderCommands - -This function will be called synchronously if running without -smp extensions, or asynchronously by another thread. ==================== */ void RB_ExecuteRenderCommands( const void *data ) { @@ -1121,12 +1119,6 @@ void RB_ExecuteRenderCommands( const void *data ) { t1 = ri.Milliseconds (); - if ( !r_smp->integer || data == backEndData[0]->commands.cmds ) { - backEnd.smpFrame = 0; - } else { - backEnd.smpFrame = 1; - } - while ( 1 ) { data = PADP(data, sizeof(void *)); @@ -1160,7 +1152,7 @@ void RB_ExecuteRenderCommands( const void *data ) { break; case RC_END_OF_LIST: default: - // stop rendering on this thread + // stop rendering t2 = ri.Milliseconds (); backEnd.pc.msec = t2 - t1; return; @@ -1168,30 +1160,3 @@ void RB_ExecuteRenderCommands( const void *data ) { } } - - -/* -================ -RB_RenderThread -================ -*/ -void RB_RenderThread( void ) { - const void *data; - - // wait for either a rendering command or a quit command - while ( 1 ) { - // sleep until we have work to do - data = GLimp_RendererSleep(); - - if ( !data ) { - return; // all done, renderer is shutting down - } - - renderThreadActive = qtrue; - - RB_ExecuteRenderCommands( data ); - - renderThreadActive = qfalse; - } -} - diff --git a/code/renderer/tr_bsp.c b/code/renderergl1/tr_bsp.c similarity index 99% rename from code/renderer/tr_bsp.c rename to code/renderergl1/tr_bsp.c index d4168bed..7ca4d977 100644 --- a/code/renderer/tr_bsp.c +++ b/code/renderergl1/tr_bsp.c @@ -147,7 +147,7 @@ static void R_LoadLightmaps( lump_t *l ) { buf = fileBase + l->fileofs; // we are about to upload textures - R_SyncRenderThread(); + R_IssuePendingRenderCommands(); // create all the lightmaps tr.numLightmaps = len / (LIGHTMAP_SIZE * LIGHTMAP_SIZE * 3); @@ -203,7 +203,8 @@ static void R_LoadLightmaps( lump_t *l ) { } } tr.lightmaps[i] = R_CreateImage( va("*lightmap%d",i), image, - LIGHTMAP_SIZE, LIGHTMAP_SIZE, qfalse, qfalse, GL_CLAMP_TO_EDGE ); + LIGHTMAP_SIZE, LIGHTMAP_SIZE, IMGTYPE_COLORALPHA, + IMGFLAG_NOLIGHTSCALE | IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, 0 ); } if ( r_lightmap->integer == 2 ) { @@ -272,11 +273,11 @@ static shader_t *ShaderForShaderNum( int shaderNum, int lightmapNum ) { shader_t *shader; dshader_t *dsh; - shaderNum = LittleLong( shaderNum ); - if ( shaderNum < 0 || shaderNum >= s_worldData.numShaders ) { - ri.Error( ERR_DROP, "ShaderForShaderNum: bad num %i", shaderNum ); + int _shaderNum = LittleLong( shaderNum ); + if ( _shaderNum < 0 || _shaderNum >= s_worldData.numShaders ) { + ri.Error( ERR_DROP, "ShaderForShaderNum: bad num %i", _shaderNum ); } - dsh = &s_worldData.shaders[ shaderNum ]; + dsh = &s_worldData.shaders[ _shaderNum ]; if ( r_vertexLight->integer || glConfig.hardwareType == GLHW_PERMEDIA2 ) { lightmapNum = LIGHTMAP_BY_VERTEX; diff --git a/code/renderer/tr_cmds.c b/code/renderergl1/tr_cmds.c similarity index 84% rename from code/renderer/tr_cmds.c rename to code/renderergl1/tr_cmds.c index fe3fd133..00b819ac 100644 --- a/code/renderer/tr_cmds.c +++ b/code/renderergl1/tr_cmds.c @@ -21,11 +21,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "tr_local.h" -volatile renderCommandList_t *renderCommandList; - -volatile qboolean renderThreadActive; - - /* ===================== R_PerformanceCounters @@ -75,49 +70,15 @@ void R_PerformanceCounters( void ) { } -/* -==================== -R_InitCommandBuffers -==================== -*/ -void R_InitCommandBuffers( void ) { - glConfig.smpActive = qfalse; - if ( r_smp->integer ) { - ri.Printf( PRINT_ALL, "Trying SMP acceleration...\n" ); - if ( GLimp_SpawnRenderThread( RB_RenderThread ) ) { - ri.Printf( PRINT_ALL, "...succeeded.\n" ); - glConfig.smpActive = qtrue; - } else { - ri.Printf( PRINT_ALL, "...failed.\n" ); - } - } -} - -/* -==================== -R_ShutdownCommandBuffers -==================== -*/ -void R_ShutdownCommandBuffers( void ) { - // kill the rendering thread - if ( glConfig.smpActive ) { - GLimp_WakeRenderer( NULL ); - glConfig.smpActive = qfalse; - } -} - /* ==================== R_IssueRenderCommands ==================== */ -int c_blockedOnRender; -int c_blockedOnMain; - void R_IssueRenderCommands( qboolean runPerformanceCounters ) { renderCommandList_t *cmdList; - cmdList = &backEndData[tr.smpFrame]->commands; + cmdList = &backEndData->commands; assert(cmdList); // add an end-of-list command *(int *)(cmdList->cmds + cmdList->used) = RC_END_OF_LIST; @@ -125,26 +86,6 @@ void R_IssueRenderCommands( qboolean runPerformanceCounters ) { // clear it out, in case this is a sync and not a buffer flip cmdList->used = 0; - if ( glConfig.smpActive ) { - // if the render thread is not idle, wait for it - if ( renderThreadActive ) { - c_blockedOnRender++; - if ( r_showSmp->integer ) { - ri.Printf( PRINT_ALL, "R" ); - } - } else { - c_blockedOnMain++; - if ( r_showSmp->integer ) { - ri.Printf( PRINT_ALL, "." ); - } - } - - // sleep until the renderer has completed - GLimp_FrontEndSleep(); - } - - // at this point, the back end thread is idle, so it is ok - // to look at its performance counters if ( runPerformanceCounters ) { R_PerformanceCounters(); } @@ -152,49 +93,36 @@ void R_IssueRenderCommands( qboolean runPerformanceCounters ) { // actually start the commands going if ( !r_skipBackEnd->integer ) { // let it start on the new batch - if ( !glConfig.smpActive ) { - RB_ExecuteRenderCommands( cmdList->cmds ); - } else { - GLimp_WakeRenderer( cmdList ); - } + RB_ExecuteRenderCommands( cmdList->cmds ); } } /* ==================== -R_SyncRenderThread +R_IssuePendingRenderCommands Issue any pending commands and wait for them to complete. -After exiting, the render thread will have completed its work -and will remain idle and the main thread is free to issue -OpenGL calls until R_IssueRenderCommands is called. ==================== */ -void R_SyncRenderThread( void ) { +void R_IssuePendingRenderCommands( void ) { if ( !tr.registered ) { return; } R_IssueRenderCommands( qfalse ); - - if ( !glConfig.smpActive ) { - return; - } - GLimp_FrontEndSleep(); } /* ============ R_GetCommandBuffer -make sure there is enough command space, waiting on the -render thread if needed. +make sure there is enough command space ============ */ void *R_GetCommandBuffer( int bytes ) { renderCommandList_t *cmdList; - cmdList = &backEndData[tr.smpFrame]->commands; + cmdList = &backEndData->commands; bytes = PAD(bytes, sizeof(void *)); // always leave room for the end of list command @@ -377,7 +305,7 @@ void RE_BeginFrame( stereoFrame_t stereoFrame ) { } else { - R_SyncRenderThread(); + R_IssuePendingRenderCommands(); qglEnable( GL_STENCIL_TEST ); qglStencilMask( ~0U ); qglClearStencil( 0U ); @@ -390,7 +318,7 @@ void RE_BeginFrame( stereoFrame_t stereoFrame ) { { // this is only reached if it was on and is now off if ( r_measureOverdraw->modified ) { - R_SyncRenderThread(); + R_IssuePendingRenderCommands(); qglDisable( GL_STENCIL_TEST ); } r_measureOverdraw->modified = qfalse; @@ -400,7 +328,7 @@ void RE_BeginFrame( stereoFrame_t stereoFrame ) { // texturemode stuff // if ( r_textureMode->modified ) { - R_SyncRenderThread(); + R_IssuePendingRenderCommands(); GL_TextureMode( r_textureMode->string ); r_textureMode->modified = qfalse; } @@ -411,7 +339,7 @@ void RE_BeginFrame( stereoFrame_t stereoFrame ) { if ( r_gamma->modified ) { r_gamma->modified = qfalse; - R_SyncRenderThread(); + R_IssuePendingRenderCommands(); R_SetColorMappings(); } @@ -420,7 +348,7 @@ void RE_BeginFrame( stereoFrame_t stereoFrame ) { { int err; - R_SyncRenderThread(); + R_IssuePendingRenderCommands(); if ((err = qglGetError()) != GL_NO_ERROR) ri.Error(ERR_FATAL, "RE_BeginFrame() - glGetError() failed (0x%x)!", err); } @@ -534,9 +462,7 @@ void RE_EndFrame( int *frontEndMsec, int *backEndMsec ) { R_IssueRenderCommands( qtrue ); - // use the other buffers next frame, because another CPU - // may still be rendering into the current ones - R_ToggleSmpFrame(); + R_InitNextFrame(); if ( frontEndMsec ) { *frontEndMsec = tr.frontEndMsec; diff --git a/code/renderer/tr_curve.c b/code/renderergl1/tr_curve.c similarity index 100% rename from code/renderer/tr_curve.c rename to code/renderergl1/tr_curve.c diff --git a/code/renderer/tr_flares.c b/code/renderergl1/tr_flares.c similarity index 99% rename from code/renderer/tr_flares.c rename to code/renderergl1/tr_flares.c index e6a757c7..1d0a9175 100644 --- a/code/renderer/tr_flares.c +++ b/code/renderergl1/tr_flares.c @@ -79,7 +79,7 @@ typedef struct flare_s { vec3_t color; } flare_t; -#define MAX_FLARES 128 +#define MAX_FLARES 256 flare_t r_flareStructs[MAX_FLARES]; flare_t *r_activeFlares, *r_inactiveFlares; @@ -352,8 +352,8 @@ void RB_RenderFlare( flare_t *f ) { VectorScale(f->color, f->drawIntensity * intensity, color); -// Calculations for fogging - if(tr.world && f->fogNum < tr.world->numfogs) + // Calculations for fogging + if(tr.world && f->fogNum > 0 && f->fogNum < tr.world->numfogs) { tess.numVertexes = 1; VectorCopy(f->origin, tess.xyz[0]); diff --git a/code/renderer/tr_image.c b/code/renderergl1/tr_image.c similarity index 88% rename from code/renderer/tr_image.c rename to code/renderergl1/tr_image.c index f5112010..14cf9890 100644 --- a/code/renderer/tr_image.c +++ b/code/renderergl1/tr_image.c @@ -113,7 +113,7 @@ void GL_TextureMode( const char *string ) { // change all the existing mipmap texture objects for ( i = 0 ; i < tr.numImages ; i++ ) { glt = tr.images[ i ]; - if ( glt->mipmap ) { + if ( glt->flags & IMGFLAG_MIPMAP ) { GL_Bind (glt); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min); qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max); @@ -146,71 +146,141 @@ R_ImageList_f =============== */ void R_ImageList_f( void ) { - int i; - image_t *image; - int texels; - const char *yesno[] = { - "no ", "yes" - }; + int i; + int estTotalSize = 0; - ri.Printf (PRINT_ALL, "\n -w-- -h-- -mm- -TMU- -if-- wrap --name-------\n"); - texels = 0; + ri.Printf(PRINT_ALL, "\n -w-- -h-- type -size- --name-------\n"); - for ( i = 0 ; i < tr.numImages ; i++ ) { - image = tr.images[ i ]; + for ( i = 0 ; i < tr.numImages ; i++ ) + { + image_t *image = tr.images[i]; + char *format = "???? "; + char *sizeSuffix; + int estSize; + int displaySize; - texels += image->uploadWidth*image->uploadHeight; - ri.Printf (PRINT_ALL, "%4i: %4i %4i %s %d ", - i, image->uploadWidth, image->uploadHeight, yesno[image->mipmap], image->TMU ); - switch ( image->internalFormat ) { - case 1: - ri.Printf( PRINT_ALL, "I " ); - break; - case 2: - ri.Printf( PRINT_ALL, "IA " ); - break; - case 3: - ri.Printf( PRINT_ALL, "RGB " ); - break; - case 4: - ri.Printf( PRINT_ALL, "RGBA " ); - break; - case GL_RGBA8: - ri.Printf( PRINT_ALL, "RGBA8" ); - break; - case GL_RGB8: - ri.Printf( PRINT_ALL, "RGB8" ); - break; - case GL_RGB4_S3TC: - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - ri.Printf( PRINT_ALL, "S3TC " ); - break; - case GL_RGBA4: - ri.Printf( PRINT_ALL, "RGBA4" ); - break; - case GL_RGB5: - ri.Printf( PRINT_ALL, "RGB5 " ); - break; - default: - ri.Printf( PRINT_ALL, "???? " ); + estSize = image->uploadHeight * image->uploadWidth; + + switch(image->internalFormat) + { + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: + format = "sDXT1"; + // 64 bits per 16 pixels, so 4 bits per pixel + estSize /= 2; + break; + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: + format = "sDXT5"; + // 128 bits per 16 pixels, so 1 byte per pixel + break; + case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB: + format = "sBPTC"; + // 128 bits per 16 pixels, so 1 byte per pixel + break; + case GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT: + format = "LATC "; + // 128 bits per 16 pixels, so 1 byte per pixel + break; + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + format = "DXT1 "; + // 64 bits per 16 pixels, so 4 bits per pixel + estSize /= 2; + break; + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: + format = "DXT5 "; + // 128 bits per 16 pixels, so 1 byte per pixel + break; + case GL_COMPRESSED_RGBA_BPTC_UNORM_ARB: + format = "BPTC "; + // 128 bits per 16 pixels, so 1 byte per pixel + break; + case GL_RGB4_S3TC: + format = "S3TC "; + // same as DXT1? + estSize /= 2; + break; + case GL_RGBA4: + case GL_RGBA8: + case GL_RGBA: + format = "RGBA "; + // 4 bytes per pixel + estSize *= 4; + break; + case GL_LUMINANCE8: + case GL_LUMINANCE16: + case GL_LUMINANCE: + format = "L "; + // 1 byte per pixel? + break; + case GL_RGB5: + case GL_RGB8: + case GL_RGB: + format = "RGB "; + // 3 bytes per pixel? + estSize *= 3; + break; + case GL_LUMINANCE8_ALPHA8: + case GL_LUMINANCE16_ALPHA16: + case GL_LUMINANCE_ALPHA: + format = "LA "; + // 2 bytes per pixel? + estSize *= 2; + break; + case GL_SRGB_EXT: + case GL_SRGB8_EXT: + format = "sRGB "; + // 3 bytes per pixel? + estSize *= 3; + break; + case GL_SRGB_ALPHA_EXT: + case GL_SRGB8_ALPHA8_EXT: + format = "sRGBA"; + // 4 bytes per pixel? + estSize *= 4; + break; + case GL_SLUMINANCE_EXT: + case GL_SLUMINANCE8_EXT: + format = "sL "; + // 1 byte per pixel? + break; + case GL_SLUMINANCE_ALPHA_EXT: + case GL_SLUMINANCE8_ALPHA8_EXT: + format = "sLA "; + // 2 byte per pixel? + estSize *= 2; + break; } - switch ( image->wrapClampMode ) { - case GL_REPEAT: - ri.Printf( PRINT_ALL, "rept " ); - break; - case GL_CLAMP_TO_EDGE: - ri.Printf( PRINT_ALL, "clmp " ); - break; - default: - ri.Printf( PRINT_ALL, "%4i ", image->wrapClampMode ); - break; + // mipmap adds about 50% + if (image->flags & IMGFLAG_MIPMAP) + estSize += estSize / 2; + + sizeSuffix = "b "; + displaySize = estSize; + + if (displaySize > 1024) + { + displaySize /= 1024; + sizeSuffix = "kb"; } - - ri.Printf( PRINT_ALL, " %s\n", image->imgName ); + + if (displaySize > 1024) + { + displaySize /= 1024; + sizeSuffix = "Mb"; + } + + if (displaySize > 1024) + { + displaySize /= 1024; + sizeSuffix = "Gb"; + } + + ri.Printf(PRINT_ALL, "%4i: %4ix%4i %s %4i%s %s\n", i, image->uploadWidth, image->uploadHeight, format, displaySize, sizeSuffix, image->imgName); + estTotalSize += estSize; } + ri.Printf (PRINT_ALL, " ---------\n"); - ri.Printf (PRINT_ALL, " %i total texels (not including mipmaps)\n", texels); + ri.Printf (PRINT_ALL, " approx %i bytes\n", estTotalSize); ri.Printf (PRINT_ALL, " %i total images\n\n", tr.numImages ); } @@ -256,7 +326,6 @@ static void ResampleTexture( unsigned *in, int inwidth, int inheight, unsigned * for (i=0 ; i> 1; for (j=0 ; j= MAX_QPATH ) { ri.Error (ERR_DROP, "R_CreateImage: \"%s\" is too long", name); @@ -794,14 +864,17 @@ image_t *R_CreateImage( const char *name, const byte *pic, int width, int height image->texnum = 1024 + tr.numImages; tr.numImages++; - image->mipmap = mipmap; - image->allowPicmip = allowPicmip; + image->type = type; + image->flags = flags; strcpy (image->imgName, name); image->width = width; image->height = height; - image->wrapClampMode = glWrapClampMode; + if (flags & IMGFLAG_CLAMPTOEDGE) + glWrapClampMode = GL_CLAMP_TO_EDGE; + else + glWrapClampMode = GL_REPEAT; // lightmaps are always allocated on TMU 1 if ( qglActiveTextureARB && isLightmap ) { @@ -817,8 +890,8 @@ image_t *R_CreateImage( const char *name, const byte *pic, int width, int height GL_Bind(image); Upload32( (unsigned *)pic, image->width, image->height, - image->mipmap, - allowPicmip, + image->flags & IMGFLAG_MIPMAP, + image->flags & IMGFLAG_PICMIP, isLightmap, &image->internalFormat, &image->uploadWidth, @@ -953,7 +1026,8 @@ Finds or loads the given image. Returns NULL if it fails, not a default image. ============== */ -image_t *R_FindImageFile( const char *name, qboolean mipmap, qboolean allowPicmip, int glWrapClampMode ) { +image_t *R_FindImageFile( const char *name, imgType_t type, imgFlags_t flags ) +{ image_t *image; int width, height; byte *pic; @@ -972,14 +1046,8 @@ image_t *R_FindImageFile( const char *name, qboolean mipmap, qboolean allowPicmi if ( !strcmp( name, image->imgName ) ) { // the white image can be used with any set of parms, but other mismatches are errors if ( strcmp( name, "*white" ) ) { - if ( image->mipmap != mipmap ) { - ri.Printf( PRINT_DEVELOPER, "WARNING: reused image %s with mixed mipmap parm\n", name ); - } - if ( image->allowPicmip != allowPicmip ) { - ri.Printf( PRINT_DEVELOPER, "WARNING: reused image %s with mixed allowPicmip parm\n", name ); - } - if ( image->wrapClampMode != glWrapClampMode ) { - ri.Printf( PRINT_ALL, "WARNING: reused image %s with mixed glWrapClampMode parm\n", name ); + if ( image->flags != flags ) { + ri.Printf( PRINT_DEVELOPER, "WARNING: reused image %s with mixed flags (%i vs %i)\n", name, image->flags, flags ); } } return image; @@ -994,7 +1062,7 @@ image_t *R_FindImageFile( const char *name, qboolean mipmap, qboolean allowPicmi return NULL; } - image = R_CreateImage( ( char * ) name, pic, width, height, mipmap, allowPicmip, glWrapClampMode ); + image = R_CreateImage( ( char * ) name, pic, width, height, type, flags, 0 ); ri.Free( pic ); return image; } @@ -1030,7 +1098,7 @@ static void R_CreateDlightImage( void ) { data[y][x][3] = 255; } } - tr.dlightImage = R_CreateImage("*dlight", (byte *)data, DLIGHT_SIZE, DLIGHT_SIZE, qfalse, qfalse, GL_CLAMP_TO_EDGE ); + tr.dlightImage = R_CreateImage("*dlight", (byte *)data, DLIGHT_SIZE, DLIGHT_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_CLAMPTOEDGE, 0 ); } @@ -1117,7 +1185,7 @@ static void R_CreateFogImage( void ) { // standard openGL clamping doesn't really do what we want -- it includes // the border color at the edges. OpenGL 1.2 has clamp-to-edge, which does // what we want. - tr.fogImage = R_CreateImage("*fog", (byte *)data, FOG_S, FOG_T, qfalse, qfalse, GL_CLAMP_TO_EDGE ); + tr.fogImage = R_CreateImage("*fog", (byte *)data, FOG_S, FOG_T, IMGTYPE_COLORALPHA, IMGFLAG_CLAMPTOEDGE, 0 ); ri.Hunk_FreeTempMemory( data ); borderColor[0] = 1.0; @@ -1161,7 +1229,7 @@ static void R_CreateDefaultImage( void ) { data[x][DEFAULT_SIZE-1][2] = data[x][DEFAULT_SIZE-1][3] = 255; } - tr.defaultImage = R_CreateImage("*default", (byte *)data, DEFAULT_SIZE, DEFAULT_SIZE, qtrue, qfalse, GL_REPEAT ); + tr.defaultImage = R_CreateImage("*default", (byte *)data, DEFAULT_SIZE, DEFAULT_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_MIPMAP, 0); } /* @@ -1177,7 +1245,7 @@ void R_CreateBuiltinImages( void ) { // we use a solid white image instead of disabling texturing Com_Memset( data, 255, sizeof( data ) ); - tr.whiteImage = R_CreateImage("*white", (byte *)data, 8, 8, qfalse, qfalse, GL_REPEAT ); + tr.whiteImage = R_CreateImage("*white", (byte *)data, 8, 8, IMGTYPE_COLORALPHA, IMGFLAG_NONE, 0); // with overbright bits active, we need an image which is some fraction of full color, // for default lightmaps, etc @@ -1190,12 +1258,12 @@ void R_CreateBuiltinImages( void ) { } } - tr.identityLightImage = R_CreateImage("*identityLight", (byte *)data, 8, 8, qfalse, qfalse, GL_REPEAT ); + tr.identityLightImage = R_CreateImage("*identityLight", (byte *)data, 8, 8, IMGTYPE_COLORALPHA, IMGFLAG_NONE, 0); for(x=0;x<32;x++) { // scratchimage is usually used for cinematic drawing - tr.scratchImage[x] = R_CreateImage("*scratch", (byte *)data, DEFAULT_SIZE, DEFAULT_SIZE, qfalse, qtrue, GL_CLAMP_TO_EDGE ); + tr.scratchImage[x] = R_CreateImage("*scratch", (byte *)data, DEFAULT_SIZE, DEFAULT_SIZE, IMGTYPE_COLORALPHA, IMGFLAG_PICMIP | IMGFLAG_CLAMPTOEDGE, 0); } R_CreateDlightImage(); @@ -1495,8 +1563,7 @@ qhandle_t RE_RegisterSkin( const char *name ) { Q_strncpyz( skin->name, name, sizeof( skin->name ) ); skin->numSurfaces = 0; - // make sure the render thread is stopped - R_SyncRenderThread(); + R_IssuePendingRenderCommands(); // If not a .skin file, load as a single shader if ( strcmp( name + strlen( name ) - 5, ".skin" ) ) { diff --git a/code/renderer/tr_init.c b/code/renderergl1/tr_init.c similarity index 96% rename from code/renderer/tr_init.c rename to code/renderergl1/tr_init.c index 8eed609d..8ab50cd7 100644 --- a/code/renderer/tr_init.c +++ b/code/renderergl1/tr_init.c @@ -55,8 +55,6 @@ cvar_t *r_znear; cvar_t *r_zproj; cvar_t *r_stereoSeparation; -cvar_t *r_smp; -cvar_t *r_showSmp; cvar_t *r_skipBackEnd; cvar_t *r_stereoEnabled; @@ -211,9 +209,6 @@ static void InitOpenGL( void ) } } - // init command buffers and SMP - R_InitCommandBuffers(); - // set default state GL_SetDefaultState(); } @@ -877,6 +872,16 @@ void GL_SetDefaultState( void ) qglEnable( GL_SCISSOR_TEST ); qglDisable( GL_CULL_FACE ); qglDisable( GL_BLEND ); + + qglColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE ); + qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); + qglClearDepth( 1.0 ); + + qglDrawBuffer( GL_FRONT ); + qglClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_ACCUM_BUFFER_BIT|GL_STENCIL_BUFFER_BIT ); + + qglDrawBuffer( GL_BACK ); + qglClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_ACCUM_BUFFER_BIT|GL_STENCIL_BUFFER_BIT ); } /* @@ -990,9 +995,6 @@ void GfxInfo_f( void ) { ri.Printf( PRINT_ALL, "HACK: riva128 approximations\n" ); } - if ( glConfig.smpActive ) { - ri.Printf( PRINT_ALL, "Using dual processor acceleration\n" ); - } if ( r_finish->integer ) { ri.Printf( PRINT_ALL, "Forcing glFinish\n" ); } @@ -1035,7 +1037,7 @@ void R_Register( void ) ri.Cvar_CheckRange( r_ext_multisample, 0, 4, qtrue ); r_overBrightBits = ri.Cvar_Get ("r_overBrightBits", "1", CVAR_ARCHIVE | CVAR_LATCH ); r_ignorehwgamma = ri.Cvar_Get( "r_ignorehwgamma", "0", CVAR_ARCHIVE | CVAR_LATCH); - r_mode = ri.Cvar_Get( "r_mode", "-2", CVAR_ARCHIVE | CVAR_LATCH ); + r_mode = ri.Cvar_Get( "r_mode", "3", CVAR_ARCHIVE | CVAR_LATCH ); r_fullscreen = ri.Cvar_Get( "r_fullscreen", "1", CVAR_ARCHIVE ); r_noborder = ri.Cvar_Get("r_noborder", "0", CVAR_ARCHIVE); r_customwidth = ri.Cvar_Get( "r_customwidth", "1600", CVAR_ARCHIVE | CVAR_LATCH ); @@ -1045,7 +1047,6 @@ void R_Register( void ) r_vertexLight = ri.Cvar_Get( "r_vertexLight", "0", CVAR_ARCHIVE | CVAR_LATCH ); r_uiFullScreen = ri.Cvar_Get( "r_uifullscreen", "0", 0); r_subdivisions = ri.Cvar_Get ("r_subdivisions", "4", CVAR_ARCHIVE | CVAR_LATCH); - r_smp = ri.Cvar_Get( "r_smp", "0", CVAR_ARCHIVE | CVAR_LATCH); r_stereoEnabled = ri.Cvar_Get( "r_stereoEnabled", "0", CVAR_ARCHIVE | CVAR_LATCH); r_ignoreFastPath = ri.Cvar_Get( "r_ignoreFastPath", "1", CVAR_ARCHIVE | CVAR_LATCH ); r_greyscale = ri.Cvar_Get("r_greyscale", "0", CVAR_ARCHIVE | CVAR_LATCH); @@ -1112,7 +1113,6 @@ void R_Register( void ) r_flareFade = ri.Cvar_Get ("r_flareFade", "7", CVAR_CHEAT); r_flareCoeff = ri.Cvar_Get ("r_flareCoeff", FLARE_STDCOEFF, CVAR_CHEAT); - r_showSmp = ri.Cvar_Get ("r_showSmp", "0", CVAR_CHEAT); r_skipBackEnd = ri.Cvar_Get ("r_skipBackEnd", "0", CVAR_CHEAT); r_measureOverdraw = ri.Cvar_Get( "r_measureOverdraw", "0", CVAR_CHEAT ); @@ -1228,19 +1228,11 @@ void R_Init( void ) { if (max_polyverts < MAX_POLYVERTS) max_polyverts = MAX_POLYVERTS; - ptr = ri.Hunk_Alloc( sizeof( *backEndData[0] ) + sizeof(srfPoly_t) * max_polys + sizeof(polyVert_t) * max_polyverts, h_low); - backEndData[0] = (backEndData_t *) ptr; - backEndData[0]->polys = (srfPoly_t *) ((char *) ptr + sizeof( *backEndData[0] )); - backEndData[0]->polyVerts = (polyVert_t *) ((char *) ptr + sizeof( *backEndData[0] ) + sizeof(srfPoly_t) * max_polys); - if ( r_smp->integer ) { - ptr = ri.Hunk_Alloc( sizeof( *backEndData[1] ) + sizeof(srfPoly_t) * max_polys + sizeof(polyVert_t) * max_polyverts, h_low); - backEndData[1] = (backEndData_t *) ptr; - backEndData[1]->polys = (srfPoly_t *) ((char *) ptr + sizeof( *backEndData[1] )); - backEndData[1]->polyVerts = (polyVert_t *) ((char *) ptr + sizeof( *backEndData[1] ) + sizeof(srfPoly_t) * max_polys); - } else { - backEndData[1] = NULL; - } - R_ToggleSmpFrame(); + ptr = ri.Hunk_Alloc( sizeof( *backEndData ) + sizeof(srfPoly_t) * max_polys + sizeof(polyVert_t) * max_polyverts, h_low); + backEndData = (backEndData_t *) ptr; + backEndData->polys = (srfPoly_t *) ((char *) ptr + sizeof( *backEndData )); + backEndData->polyVerts = (polyVert_t *) ((char *) ptr + sizeof( *backEndData ) + sizeof(srfPoly_t) * max_polys); + R_InitNextFrame(); InitOpenGL(); @@ -1286,8 +1278,7 @@ void RE_Shutdown( qboolean destroyWindow ) { if ( tr.registered ) { - R_SyncRenderThread(); - R_ShutdownCommandBuffers(); + R_IssuePendingRenderCommands(); R_DeleteTextures(); } @@ -1296,6 +1287,9 @@ void RE_Shutdown( qboolean destroyWindow ) { // shut down platform specific OpenGL stuff if ( destroyWindow ) { GLimp_Shutdown(); + + Com_Memset( &glConfig, 0, sizeof( glConfig ) ); + Com_Memset( &glState, 0, sizeof( glState ) ); } tr.registered = qfalse; @@ -1310,7 +1304,7 @@ Touch all images to make sure they are resident ============= */ void RE_EndRegistration( void ) { - R_SyncRenderThread(); + R_IssuePendingRenderCommands(); if (!ri.Sys_LowPhysicalMemory()) { RB_ShowImages(); } @@ -1324,7 +1318,7 @@ GetRefAPI @@@@@@@@@@@@@@@@@@@@@ */ #ifdef USE_RENDERER_DLOPEN -Q_EXPORT refexport_t QDECL *GetRefAPI ( int apiVersion, refimport_t *rimp ) { +Q_EXPORT refexport_t* QDECL GetRefAPI ( int apiVersion, refimport_t *rimp ) { #else refexport_t *GetRefAPI ( int apiVersion, refimport_t *rimp ) { #endif diff --git a/code/renderer/tr_light.c b/code/renderergl1/tr_light.c similarity index 98% rename from code/renderer/tr_light.c rename to code/renderergl1/tr_light.c index 89153854..fc6af6a9 100644 --- a/code/renderer/tr_light.c +++ b/code/renderergl1/tr_light.c @@ -95,11 +95,11 @@ void R_DlightBmodel( bmodel_t *bmodel ) { surf = bmodel->firstSurface + i; if ( *surf->data == SF_FACE ) { - ((srfSurfaceFace_t *)surf->data)->dlightBits[ tr.smpFrame ] = mask; + ((srfSurfaceFace_t *)surf->data)->dlightBits = mask; } else if ( *surf->data == SF_GRID ) { - ((srfGridMesh_t *)surf->data)->dlightBits[ tr.smpFrame ] = mask; + ((srfGridMesh_t *)surf->data)->dlightBits = mask; } else if ( *surf->data == SF_TRIANGLES ) { - ((srfTriangles_t *)surf->data)->dlightBits[ tr.smpFrame ] = mask; + ((srfTriangles_t *)surf->data)->dlightBits = mask; } } } diff --git a/code/renderer/tr_local.h b/code/renderergl1/tr_local.h similarity index 89% rename from code/renderer/tr_local.h rename to code/renderergl1/tr_local.h index bd666a54..dd292bc6 100644 --- a/code/renderer/tr_local.h +++ b/code/renderergl1/tr_local.h @@ -27,18 +27,14 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "../qcommon/q_shared.h" #include "../qcommon/qfiles.h" #include "../qcommon/qcommon.h" -#include "tr_public.h" -#include "qgl.h" -#include "iqm.h" +#include "../renderercommon/tr_public.h" +#include "../renderercommon/tr_common.h" +#include "../renderercommon/iqm.h" +#include "../renderercommon/qgl.h" #define GL_INDEX_TYPE GL_UNSIGNED_INT typedef unsigned int glIndex_t; -// everything that is needed by the backend needs -// to be double buffered to allow it to run in -// parallel on a dual cpu machine -#define SMP_FRAMES 2 - // 14 bits // can't be increased without changing bit packing for drawsurfs // see QSORT_SHADERNUM_SHIFT @@ -84,24 +80,6 @@ typedef struct { float modelMatrix[16]; } orientationr_t; -typedef struct image_s { - char imgName[MAX_QPATH]; // game path, including extension - int width, height; // source image - int uploadWidth, uploadHeight; // after power of two and picmip but not including clamp to MAX_TEXTURE_SIZE - GLuint texnum; // gl texture binding - - int frameUsed; // for texture usage in frame statistics - - int internalFormat; - int TMU; // only needed for voodoo2 - - qboolean mipmap; - qboolean allowPicmip; - int wrapClampMode; // GL_CLAMP_TO_EDGE or GL_REPEAT - - struct image_s* next; -} image_t; - //=============================================================================== typedef enum { @@ -316,13 +294,6 @@ typedef struct { struct shaderCommands_s; -// any change in the LIGHTMAP_* defines here MUST be reflected in -// R_FindShader() in tr_bsp.c -#define LIGHTMAP_2D -4 // shader is for 2D rendering -#define LIGHTMAP_BY_VERTEX -3 // pre-lit triangle models -#define LIGHTMAP_WHITEIMAGE -2 -#define LIGHTMAP_NONE -1 - typedef enum { CT_FRONT_SIDED, CT_BACK_SIDED, @@ -524,9 +495,7 @@ typedef enum { SF_POLY, SF_MD3, SF_MD4, -#ifdef RAVENMD4 SF_MDR, -#endif SF_IQM, SF_FLARE, SF_ENTITY, // beams, rails, lightning, etc that can be determined by entity @@ -573,7 +542,7 @@ typedef struct srfGridMesh_s { surfaceType_t surfaceType; // dynamic lighting information - int dlightBits[SMP_FRAMES]; + int dlightBits; // culling information vec3_t meshBounds[2]; @@ -603,7 +572,7 @@ typedef struct { cplane_t plane; // dynamic lighting information - int dlightBits[SMP_FRAMES]; + int dlightBits; // triangle definitions (no normals at points) int numPoints; @@ -619,7 +588,7 @@ typedef struct { surfaceType_t surfaceType; // dynamic lighting information - int dlightBits[SMP_FRAMES]; + int dlightBits; // culling information (FIXME: use this!) vec3_t bounds[2]; @@ -653,6 +622,7 @@ typedef struct { int *triangles; int *jointParents; + float *jointMats; float *poseMats; float *bounds; char *names; @@ -775,9 +745,7 @@ typedef enum { MOD_BRUSH, MOD_MESH, MOD_MD4, -#ifdef RAVENMD4 MOD_MDR, -#endif MOD_IQM } modtype_t; @@ -806,7 +774,6 @@ void R_ModelBounds( qhandle_t handle, vec3_t mins, vec3_t maxs ); void R_Modellist_f (void); //==================================================== -extern refimport_t ri; #define MAX_DRAWIMAGES 2048 #define MAX_SKINS 1024 @@ -873,7 +840,6 @@ typedef struct { unsigned long glStateBits; } glstate_t; - typedef struct { int c_surfaces, c_shaders, c_vertexes, c_indexes, c_totalIndexes; float c_overDraw; @@ -891,7 +857,6 @@ typedef struct { // all state modified by the back end is seperated // from the front end state typedef struct { - int smpFrame; trRefdef_t refdef; viewParms_t viewParms; orientationr_t or; @@ -923,8 +888,6 @@ typedef struct { int viewCount; // incremented every view (twice a scene if portaled) // and every R_MarkFragments call - int smpFrame; // toggles from 0 to 1 every endFrame - int frameSceneNum; // zeroed at RE_BeginFrame qboolean worldMapLoaded; @@ -1004,17 +967,8 @@ typedef struct { extern backEndState_t backEnd; extern trGlobals_t tr; -extern glconfig_t glConfig; // outside of TR since it shouldn't be cleared during ref re-init extern glstate_t glState; // outside of TR since it shouldn't be cleared during ref re-init -// These two variables should live inside glConfig but can't because of compatibility issues to the original ID vms. -// If you release a stand-alone game and your mod uses tr_types.h from this build you can safely move them to -// the glconfig_t struct. -extern qboolean textureFilterAnisotropic; -extern int maxAnisotropy; -extern float displayAspect; - - // // cvars // @@ -1036,16 +990,6 @@ extern cvar_t *r_znear; // near Z clip plane extern cvar_t *r_zproj; // z distance of projection plane extern cvar_t *r_stereoSeparation; // separation of cameras for stereo rendering -extern cvar_t *r_stencilbits; // number of desired stencil bits -extern cvar_t *r_depthbits; // number of desired depth bits -extern cvar_t *r_colorbits; // number of desired color bits, only relevant for fullscreen -extern cvar_t *r_texturebits; // number of desired texture bits -extern cvar_t *r_ext_multisample; - // 0 = use framebuffer depth - // 16 = use 16-bit textures - // 32 = use 32-bit textures - // all else = error - extern cvar_t *r_measureOverdraw; // enables stencil buffer overdraw measurement extern cvar_t *r_lodbias; // push/pull LOD transitions @@ -1073,20 +1017,7 @@ extern cvar_t *r_facePlaneCull; // enables culling of planar surfaces with back extern cvar_t *r_nocurves; extern cvar_t *r_showcluster; -extern cvar_t *r_mode; // video mode -extern cvar_t *r_fullscreen; -extern cvar_t *r_noborder; extern cvar_t *r_gamma; -extern cvar_t *r_ignorehwgamma; // overrides hardware gamma capabilities - -extern cvar_t *r_allowExtensions; // global enable/disable of OpenGL extensions -extern cvar_t *r_ext_compressed_textures; // these control use of specific extensions -extern cvar_t *r_ext_multitexture; -extern cvar_t *r_ext_compiled_vertex_array; -extern cvar_t *r_ext_texture_env_add; - -extern cvar_t *r_ext_texture_filter_anisotropic; -extern cvar_t *r_ext_max_anisotropy; extern cvar_t *r_nobind; // turns off binding to appropriate textures extern cvar_t *r_singleShader; // make most world faces use default shader @@ -1094,8 +1025,6 @@ extern cvar_t *r_roundImagesDown; extern cvar_t *r_colorMipLevels; // development aid to see texture mip usage extern cvar_t *r_picmip; // controls picmip values extern cvar_t *r_finish; -extern cvar_t *r_drawBuffer; -extern cvar_t *r_swapInterval; extern cvar_t *r_textureMode; extern cvar_t *r_offsetFactor; extern cvar_t *r_offsetUnits; @@ -1122,11 +1051,8 @@ extern cvar_t *r_portalOnly; extern cvar_t *r_subdivisions; extern cvar_t *r_lodCurveError; -extern cvar_t *r_smp; -extern cvar_t *r_showSmp; extern cvar_t *r_skipBackEnd; -extern cvar_t *r_stereoEnabled; extern cvar_t *r_anaglyphMode; extern cvar_t *r_greyscale; @@ -1143,15 +1069,11 @@ extern cvar_t *r_showImages; extern cvar_t *r_debugSort; extern cvar_t *r_printShaders; -extern cvar_t *r_saveFontData; extern cvar_t *r_marksOnTriangleMeshes; //==================================================================== -float R_NoiseGet4f( float x, float y, float z, float t ); -void R_NoiseInit( void ); - void R_SwapBuffers( int ); void R_RenderView( viewParms_t *parms ); @@ -1245,11 +1167,6 @@ qboolean R_GetEntityToken( char *buffer, int size ); model_t *R_AllocModel( void ); void R_Init( void ); -image_t *R_FindImageFile( const char *name, qboolean mipmap, qboolean allowPicmip, int glWrapClampMode ); - -image_t *R_CreateImage( const char *name, const byte *pic, int width, int height, qboolean mipmap - , qboolean allowPicmip, int wrapClampMode ); -qboolean R_GetModeInfo( int *width, int *height, float *windowAspect, int mode ); void R_SetColorMappings( void ); void R_GammaCorrect( byte *buffer, int bufSize ); @@ -1275,11 +1192,6 @@ const void *RB_TakeVideoFrameCmd( const void *data ); // // tr_shader.c // -qhandle_t RE_RegisterShaderLightMap( const char *name, int lightmapIndex ); -qhandle_t RE_RegisterShader( const char *name ); -qhandle_t RE_RegisterShaderNoMip( const char *name ); -qhandle_t RE_RegisterShaderFromImage(const char *name, int lightmapIndex, image_t *image, qboolean mipRawImage); - shader_t *R_FindShader( const char *name, int lightmapIndex, qboolean mipRawImage ); shader_t *R_GetShaderByHandle( qhandle_t hShader ); shader_t *R_GetShaderByState( int index, long *cycleTime ); @@ -1288,33 +1200,6 @@ void R_InitShaders( void ); void R_ShaderList_f( void ); void R_RemapShader(const char *oldShader, const char *newShader, const char *timeOffset); -/* -==================================================================== - -IMPLEMENTATION SPECIFIC FUNCTIONS - -==================================================================== -*/ - -void GLimp_Init( void ); -void GLimp_Shutdown( void ); -void GLimp_EndFrame( void ); - -qboolean GLimp_SpawnRenderThread( void (*function)( void ) ); -void *GLimp_RendererSleep( void ); -void GLimp_FrontEndSleep( void ); -void GLimp_WakeRenderer( void *data ); - -void GLimp_LogComment( char *comment ); -void GLimp_Minimize(void); - -// NOTE TTimo linux works with float gamma value, not the gamma table -// the params won't be used, getting the r_gamma cvar directly -void GLimp_SetGamma( unsigned char red[256], - unsigned char green[256], - unsigned char blue[256] ); - - /* ==================================================================== @@ -1441,7 +1326,7 @@ SKIES void R_BuildCloudData( shaderCommands_t *shader ); void R_InitSkyTexCoords( float cloudLayerHeight ); void R_DrawSkyBox( shaderCommands_t *shader ); -void RB_DrawSun( void ); +void RB_DrawSun( float scale, shader_t *shader ); void RB_ClipSkyPolygons( shaderCommands_t *shader ); /* @@ -1480,7 +1365,7 @@ SCENE GENERATION ============================================================ */ -void R_ToggleSmpFrame( void ); +void R_InitNextFrame( void ); void RE_ClearScene( void ); void RE_AddRefEntityToScene( const refEntity_t *ent ); @@ -1489,7 +1374,6 @@ void RE_AddLightToScene( const vec3_t org, float intensity, float r, float g, fl void RE_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b ); void RE_RenderScene( const refdef_t *fd ); -#ifdef RAVENMD4 /* ============================================================= @@ -1508,7 +1392,6 @@ UNCOMPRESSING BONES #define MC_SCALE_Z (1.0f/64) void MC_UnCompress(float mat[3][4],const unsigned char * comp); -#endif /* ============================================================= @@ -1521,10 +1404,8 @@ ANIMATED MODELS // void R_MakeAnimModel( model_t *model ); haven't seen this one really, so not needed I guess. void R_AddAnimSurfaces( trRefEntity_t *ent ); void RB_SurfaceAnim( md4Surface_t *surfType ); -#ifdef RAVENMD4 void R_MDRAddAnimSurfaces( trRefEntity_t *ent ); void RB_MDRSurfaceAnim( md4Surface_t *surface ); -#endif qboolean R_LoadIQM (model_t *mod, void *buffer, int filesize, const char *name ); void R_AddIQMSurfaces( trRefEntity_t *ent ); void RB_IQMSurfaceAnim( surfaceType_t *surface ); @@ -1584,7 +1465,6 @@ RENDERER BACK END FUNCTIONS ============================================================= */ -void RB_RenderThread( void ); void RB_ExecuteRenderCommands( const void *data ); /* @@ -1698,9 +1578,7 @@ typedef enum { #define MAX_POLYVERTS 3000 // all of the information needed by the back end must be -// contained in a backEndData_t. This entire structure is -// duplicated so the front and back end can run in parallel -// on an SMP machine +// contained in a backEndData_t typedef struct { drawSurf_t drawSurfs[MAX_DRAWSURFS]; dlight_t dlights[MAX_DLIGHTS]; @@ -1713,20 +1591,13 @@ typedef struct { extern int max_polys; extern int max_polyverts; -extern backEndData_t *backEndData[SMP_FRAMES]; // the second one may not be allocated - -extern volatile renderCommandList_t *renderCommandList; - -extern volatile qboolean renderThreadActive; +extern backEndData_t *backEndData; // the second one may not be allocated void *R_GetCommandBuffer( int bytes ); void RB_ExecuteRenderCommands( const void *data ); -void R_InitCommandBuffers( void ); -void R_ShutdownCommandBuffers( void ); - -void R_SyncRenderThread( void ); +void R_IssuePendingRenderCommands( void ); void R_AddDrawSurfCmd( drawSurf_t *drawSurfs, int numDrawSurfs ); @@ -1742,10 +1613,5 @@ size_t RE_SaveJPGToBuffer(byte *buffer, size_t bufSize, int quality, void RE_TakeVideoFrame( int width, int height, byte *captureBuffer, byte *encodeBuffer, qboolean motionJpeg ); -// font stuff -void R_InitFreeType( void ); -void R_DoneFreeType( void ); -void RE_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font); - #endif //TR_LOCAL_H diff --git a/code/renderer/tr_main.c b/code/renderergl1/tr_main.c similarity index 99% rename from code/renderer/tr_main.c rename to code/renderergl1/tr_main.c index 3cf8727e..79d825f6 100644 --- a/code/renderer/tr_main.c +++ b/code/renderergl1/tr_main.c @@ -812,10 +812,6 @@ static qboolean IsMirror( const drawSurf_t *drawSurf, int entityNum ) // translate the original plane originalPlane.dist = originalPlane.dist + DotProduct( originalPlane.normal, tr.or.origin ); } - else - { - plane = originalPlane; - } // locate the portal entity closest to this plane. // origin will be the origin of the portal, origin2 will be @@ -862,10 +858,6 @@ static qboolean SurfIsOffscreen( const drawSurf_t *drawSurf, vec4_t clipDest[128 unsigned int pointOr = 0; unsigned int pointAnd = (unsigned int)~0; - if ( glConfig.smpActive ) { // FIXME! we can't do RB_BeginSurface/RB_EndSurface stuff with smp! - return qfalse; - } - R_RotateForViewer(); R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted ); @@ -1253,11 +1245,9 @@ void R_AddEntitySurfaces (void) { case MOD_MD4: R_AddAnimSurfaces( ent ); break; -#ifdef RAVENMD4 case MOD_MDR: R_MDRAddAnimSurfaces( ent ); break; -#endif case MOD_IQM: R_AddIQMSurfaces( ent ); break; @@ -1352,8 +1342,7 @@ void R_DebugGraphics( void ) { return; } - // the render thread can't make callbacks to the main thread - R_SyncRenderThread(); + R_IssuePendingRenderCommands(); GL_Bind( tr.whiteImage); GL_Cull( CT_FRONT_SIDED ); diff --git a/code/renderer/tr_marks.c b/code/renderergl1/tr_marks.c similarity index 99% rename from code/renderer/tr_marks.c rename to code/renderergl1/tr_marks.c index 0ff3e303..e2c92b6c 100644 --- a/code/renderer/tr_marks.c +++ b/code/renderergl1/tr_marks.c @@ -41,8 +41,8 @@ Out must have space for two more vertexes than in static void R_ChopPolyBehindPlane( int numInPoints, vec3_t inPoints[MAX_VERTS_ON_POLY], int *numOutPoints, vec3_t outPoints[MAX_VERTS_ON_POLY], vec3_t normal, vec_t dist, vec_t epsilon) { - float dists[MAX_VERTS_ON_POLY+4]; - int sides[MAX_VERTS_ON_POLY+4]; + float dists[MAX_VERTS_ON_POLY+4] = { 0 }; + int sides[MAX_VERTS_ON_POLY+4] = { 0 }; int counts[3]; float dot; int i, j; diff --git a/code/renderer/tr_mesh.c b/code/renderergl1/tr_mesh.c similarity index 99% rename from code/renderer/tr_mesh.c rename to code/renderergl1/tr_mesh.c index 0883088f..d0be29bc 100644 --- a/code/renderer/tr_mesh.c +++ b/code/renderergl1/tr_mesh.c @@ -168,10 +168,8 @@ int R_ComputeLOD( trRefEntity_t *ent ) { float flod, lodscale; float projectedRadius; md3Frame_t *frame; -#ifdef RAVENMD4 mdrHeader_t *mdr; mdrFrame_t *mdrframe; -#endif int lod; if ( tr.currentModel->numLods < 2 ) @@ -184,7 +182,6 @@ int R_ComputeLOD( trRefEntity_t *ent ) { // multiple LODs exist, so compute projected bounding sphere // and use that as a criteria for selecting LOD -#ifdef RAVENMD4 if(tr.currentModel->type == MOD_MDR) { int frameSize; @@ -196,7 +193,6 @@ int R_ComputeLOD( trRefEntity_t *ent ) { radius = RadiusFromBounds(mdrframe->bounds[0], mdrframe->bounds[1]); } else -#endif { frame = ( md3Frame_t * ) ( ( ( unsigned char * ) tr.currentModel->md3[0] ) + tr.currentModel->md3[0]->ofsFrames ); diff --git a/code/renderer/tr_model.c b/code/renderergl1/tr_model.c similarity index 96% rename from code/renderer/tr_model.c rename to code/renderergl1/tr_model.c index 51e0427f..f9e2c3af 100644 --- a/code/renderer/tr_model.c +++ b/code/renderergl1/tr_model.c @@ -27,9 +27,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA static qboolean R_LoadMD3(model_t *mod, int lod, void *buffer, const char *name ); static qboolean R_LoadMD4(model_t *mod, void *buffer, const char *name ); -#ifdef RAVENMD4 static qboolean R_LoadMDR(model_t *mod, void *buffer, int filesize, const char *name ); -#endif /* ==================== @@ -116,7 +114,6 @@ qhandle_t R_RegisterMD3(const char *name, model_t *mod) return 0; } -#ifdef RAVENMD4 /* ==================== R_RegisterMDR @@ -154,7 +151,6 @@ qhandle_t R_RegisterMDR(const char *name, model_t *mod) return mod->index; } -#endif /* ==================== @@ -203,9 +199,7 @@ typedef struct static modelExtToLoaderMap_t modelLoaders[ ] = { { "iqm", R_RegisterIQM }, -#ifdef RAVENMD4 { "mdr", R_RegisterMDR }, -#endif { "md4", R_RegisterMD3 }, { "md3", R_RegisterMD3 } }; @@ -306,8 +300,7 @@ qhandle_t RE_RegisterModel( const char *name ) { Q_strncpyz( mod->name, name, sizeof( mod->name ) ); - // make sure the render thread is stopped - R_SyncRenderThread(); + R_IssuePendingRenderCommands(); mod->type = MOD_BAD; mod->numLods = 0; @@ -465,14 +458,16 @@ static qboolean R_LoadMD3 (model_t *mod, int lod, void *buffer, const char *mod_ LL(surf->ofsXyzNormals); LL(surf->ofsEnd); - if ( surf->numVerts > SHADER_MAX_VERTEXES ) { - ri.Printf(PRINT_WARNING, "R_LoadMD3: %s has more than %i verts on a surface (%i).\n", - mod_name, SHADER_MAX_VERTEXES, surf->numVerts ); + if ( surf->numVerts >= SHADER_MAX_VERTEXES ) { + ri.Printf(PRINT_WARNING, "R_LoadMD3: %s has more than %i verts on %s (%i).\n", + mod_name, SHADER_MAX_VERTEXES - 1, surf->name[0] ? surf->name : "a surface", + surf->numVerts ); return qfalse; } - if ( surf->numTriangles*3 > SHADER_MAX_INDEXES ) { - ri.Printf(PRINT_WARNING, "R_LoadMD3: %s has more than %i triangles on a surface (%i).\n", - mod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles ); + if ( surf->numTriangles*3 >= SHADER_MAX_INDEXES ) { + ri.Printf(PRINT_WARNING, "R_LoadMD3: %s has more than %i triangles on %s (%i).\n", + mod_name, ( SHADER_MAX_INDEXES / 3 ) - 1, surf->name[0] ? surf->name : "a surface", + surf->numTriangles ); return qfalse; } @@ -537,7 +532,6 @@ static qboolean R_LoadMD3 (model_t *mod, int lod, void *buffer, const char *mod_ } -#ifdef RAVENMD4 /* ================= @@ -742,16 +736,18 @@ static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char // numBoneReferences and BoneReferences generally seem to be unused // now do the checks that may fail. - if ( surf->numVerts > SHADER_MAX_VERTEXES ) + if ( surf->numVerts >= SHADER_MAX_VERTEXES ) { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has more than %i verts on a surface (%i).\n", - mod_name, SHADER_MAX_VERTEXES, surf->numVerts ); + ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has more than %i verts on %s (%i).\n", + mod_name, SHADER_MAX_VERTEXES - 1, surf->name[0] ? surf->name : "a surface", + surf->numVerts ); return qfalse; } - if ( surf->numTriangles*3 > SHADER_MAX_INDEXES ) + if ( surf->numTriangles*3 >= SHADER_MAX_INDEXES ) { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has more than %i triangles on a surface (%i).\n", - mod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles ); + ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has more than %i triangles on %s (%i).\n", + mod_name, ( SHADER_MAX_INDEXES / 3 ) - 1, surf->name[0] ? surf->name : "a surface", + surf->numTriangles ); return qfalse; } // lowercase the surface name so skin compares are faster @@ -876,7 +872,6 @@ static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char return qtrue; } -#endif /* ================= @@ -958,14 +953,16 @@ static qboolean R_LoadMD4( model_t *mod, void *buffer, const char *mod_name ) { LL(surf->ofsVerts); LL(surf->ofsEnd); - if ( surf->numVerts > SHADER_MAX_VERTEXES ) { - ri.Printf(PRINT_WARNING, "R_LoadMD4: %s has more than %i verts on a surface (%i).\n", - mod_name, SHADER_MAX_VERTEXES, surf->numVerts ); + if ( surf->numVerts >= SHADER_MAX_VERTEXES ) { + ri.Printf(PRINT_WARNING, "R_LoadMD4: %s has more than %i verts on %s (%i).\n", + mod_name, SHADER_MAX_VERTEXES - 1, surf->name[0] ? surf->name : "a surface", + surf->numVerts ); return qfalse; } - if ( surf->numTriangles*3 > SHADER_MAX_INDEXES ) { - ri.Printf(PRINT_WARNING, "R_LoadMD4: %s has more than %i triangles on a surface (%i).\n", - mod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles ); + if ( surf->numTriangles*3 >= SHADER_MAX_INDEXES ) { + ri.Printf(PRINT_WARNING, "R_LoadMD4: %s has more than %i triangles on %s (%i).\n", + mod_name, ( SHADER_MAX_INDEXES / 3 ) - 1, surf->name[0] ? surf->name : "a surface", + surf->numTriangles ); return qfalse; } @@ -1045,7 +1042,7 @@ void RE_BeginRegistration( glconfig_t *glconfigOut ) { *glconfigOut = glConfig; - R_SyncRenderThread(); + R_IssuePendingRenderCommands(); tr.viewCluster = -1; // force markleafs to regenerate R_ClearFlares(); @@ -1137,7 +1134,6 @@ static md3Tag_t *R_GetTag( md3Header_t *mod, int frame, const char *tagName ) { return NULL; } -#ifdef RAVENMD4 void R_GetAnimTag( mdrHeader_t *mod, int framenum, const char *tagName, md3Tag_t * dest) { int i, j, k; @@ -1181,7 +1177,6 @@ void R_GetAnimTag( mdrHeader_t *mod, int framenum, const char *tagName, md3Tag_t VectorClear( dest->origin ); strcpy(dest->name,""); } -#endif /* ================ @@ -1191,9 +1186,7 @@ R_LerpTag int R_LerpTag( orientation_t *tag, qhandle_t handle, int startFrame, int endFrame, float frac, const char *tagName ) { md3Tag_t *start, *end; -#ifdef RAVENMD4 md3Tag_t start_space, end_space; -#endif int i; float frontLerp, backLerp; model_t *model; @@ -1201,7 +1194,6 @@ int R_LerpTag( orientation_t *tag, qhandle_t handle, int startFrame, int endFram model = R_GetModelByHandle( handle ); if ( !model->md3[0] ) { -#ifdef RAVENMD4 if(model->type == MOD_MDR) { start = &start_space; @@ -1209,9 +1201,7 @@ int R_LerpTag( orientation_t *tag, qhandle_t handle, int startFrame, int endFram R_GetAnimTag((mdrHeader_t *) model->modelData, startFrame, tagName, start); R_GetAnimTag((mdrHeader_t *) model->modelData, endFrame, tagName, end); } - else -#endif - if( model->type == MOD_IQM ) { + else if( model->type == MOD_IQM ) { return R_IQMLerpTag( tag, model->modelData, startFrame, endFrame, frac, tagName ); @@ -1287,7 +1277,6 @@ void R_ModelBounds( qhandle_t handle, vec3_t mins, vec3_t maxs ) { VectorCopy( frame->bounds[1], maxs ); return; -#ifdef RAVENMD4 } else if (model->type == MOD_MDR) { mdrHeader_t *header; mdrFrame_t *frame; @@ -1299,7 +1288,6 @@ void R_ModelBounds( qhandle_t handle, vec3_t mins, vec3_t maxs ) { VectorCopy( frame->bounds[1], maxs ); return; -#endif } else if(model->type == MOD_IQM) { iqmData_t *iqmData; diff --git a/code/renderer/tr_model_iqm.c b/code/renderergl1/tr_model_iqm.c similarity index 84% rename from code/renderer/tr_model_iqm.c rename to code/renderergl1/tr_model_iqm.c index 98517d55..a0cdbe75 100644 --- a/code/renderer/tr_model_iqm.c +++ b/code/renderergl1/tr_model_iqm.c @@ -51,6 +51,11 @@ static void Matrix34Multiply( float *a, float *b, float *out ) { out[10] = a[8] * b[2] + a[9] * b[6] + a[10] * b[10]; out[11] = a[8] * b[3] + a[9] * b[7] + a[10] * b[11] + a[11]; } +static void Matrix34Multiply_OnlySetOrigin( float *a, float *b, float *out ) { + out[ 3] = a[0] * b[3] + a[1] * b[7] + a[ 2] * b[11] + a[ 3]; + out[ 7] = a[4] * b[3] + a[5] * b[7] + a[ 6] * b[11] + a[ 7]; + out[11] = a[8] * b[3] + a[9] * b[7] + a[10] * b[11] + a[11]; +} static void InterpolateMatrix( float *a, float *b, float lerp, float *mat ) { float unLerp = 1.0f - lerp; @@ -132,11 +137,12 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na unsigned short *framedata; char *str; int i, j; - float jointMats[IQM_MAX_JOINTS * 2 * 12]; - float *mat; + float jointInvMats[IQM_MAX_JOINTS * 12]; + float *mat, *matInv; size_t size, joint_names; iqmData_t *iqmData; srfIQModel_t *surface; + char meshName[MAX_QPATH]; if( filesize < sizeof(iqmHeader_t) ) { return qfalse; @@ -200,7 +206,7 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na } vertexarray = (iqmVertexArray_t *)((byte *)header + header->ofs_vertexarrays); for( i = 0; i < header->num_vertexarrays; i++, vertexarray++ ) { - int j, n, *intPtr; + int n, *intPtr; if( vertexarray->size <= 0 || vertexarray->size > 4 ) { return qfalse; @@ -305,17 +311,25 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na LL( mesh->first_triangle ); LL( mesh->num_triangles ); + if ( mesh->name < header->num_text ) { + Q_strncpyz( meshName, (char*)header + header->ofs_text + mesh->name, sizeof (meshName) ); + } else { + meshName[0] = '\0'; + } + // check ioq3 limits - if ( mesh->num_vertexes > SHADER_MAX_VERTEXES ) + if ( mesh->num_vertexes >= SHADER_MAX_VERTEXES ) { - ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has more than %i verts on a surface (%i).\n", - mod_name, SHADER_MAX_VERTEXES, mesh->num_vertexes ); + ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has more than %i verts on %s (%i).\n", + mod_name, SHADER_MAX_VERTEXES - 1, meshName[0] ? meshName : "a surface", + mesh->num_vertexes ); return qfalse; } - if ( mesh->num_triangles*3 > SHADER_MAX_INDEXES ) + if ( mesh->num_triangles*3 >= SHADER_MAX_INDEXES ) { - ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has more than %i triangles on a surface (%i).\n", - mod_name, SHADER_MAX_INDEXES / 3, mesh->num_triangles ); + ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has more than %i triangles on %s (%i).\n", + mod_name, ( SHADER_MAX_INDEXES / 3 ) - 1, meshName[0] ? meshName : "a surface", + mesh->num_triangles ); return qfalse; } @@ -329,68 +343,73 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na } } - // check and swap joints - if( IQM_CheckRange( header, header->ofs_joints, - header->num_joints, sizeof(iqmJoint_t) ) ) { - return qfalse; - } - joint = (iqmJoint_t *)((byte *)header + header->ofs_joints); - joint_names = 0; - for( i = 0; i < header->num_joints; i++, joint++ ) { - LL( joint->name ); - LL( joint->parent ); - LL( joint->translate[0] ); - LL( joint->translate[1] ); - LL( joint->translate[2] ); - LL( joint->rotate[0] ); - LL( joint->rotate[1] ); - LL( joint->rotate[2] ); - LL( joint->rotate[3] ); - LL( joint->scale[0] ); - LL( joint->scale[1] ); - LL( joint->scale[2] ); - - if( joint->parent < -1 || - joint->parent >= (int)header->num_joints || - joint->name >= (int)header->num_text ) { - return qfalse; - } - joint_names += strlen( (char *)header + header->ofs_text + - joint->name ) + 1; - } - - // check and swap poses if( header->num_poses != header->num_joints ) { return qfalse; } - if( IQM_CheckRange( header, header->ofs_poses, - header->num_poses, sizeof(iqmPose_t) ) ) { - return qfalse; - } - pose = (iqmPose_t *)((byte *)header + header->ofs_poses); - for( i = 0; i < header->num_poses; i++, pose++ ) { - LL( pose->parent ); - LL( pose->mask ); - LL( pose->channeloffset[0] ); - LL( pose->channeloffset[1] ); - LL( pose->channeloffset[2] ); - LL( pose->channeloffset[3] ); - LL( pose->channeloffset[4] ); - LL( pose->channeloffset[5] ); - LL( pose->channeloffset[6] ); - LL( pose->channeloffset[7] ); - LL( pose->channeloffset[8] ); - LL( pose->channeloffset[9] ); - LL( pose->channelscale[0] ); - LL( pose->channelscale[1] ); - LL( pose->channelscale[2] ); - LL( pose->channelscale[3] ); - LL( pose->channelscale[4] ); - LL( pose->channelscale[5] ); - LL( pose->channelscale[6] ); - LL( pose->channelscale[7] ); - LL( pose->channelscale[8] ); - LL( pose->channelscale[9] ); + + joint_names = 0; + + if ( header->num_joints ) + { + // check and swap joints + if( IQM_CheckRange( header, header->ofs_joints, + header->num_joints, sizeof(iqmJoint_t) ) ) { + return qfalse; + } + joint = (iqmJoint_t *)((byte *)header + header->ofs_joints); + for( i = 0; i < header->num_joints; i++, joint++ ) { + LL( joint->name ); + LL( joint->parent ); + LL( joint->translate[0] ); + LL( joint->translate[1] ); + LL( joint->translate[2] ); + LL( joint->rotate[0] ); + LL( joint->rotate[1] ); + LL( joint->rotate[2] ); + LL( joint->rotate[3] ); + LL( joint->scale[0] ); + LL( joint->scale[1] ); + LL( joint->scale[2] ); + + if( joint->parent < -1 || + joint->parent >= (int)header->num_joints || + joint->name >= (int)header->num_text ) { + return qfalse; + } + joint_names += strlen( (char *)header + header->ofs_text + + joint->name ) + 1; + } + + // check and swap poses + if( IQM_CheckRange( header, header->ofs_poses, + header->num_poses, sizeof(iqmPose_t) ) ) { + return qfalse; + } + pose = (iqmPose_t *)((byte *)header + header->ofs_poses); + for( i = 0; i < header->num_poses; i++, pose++ ) { + LL( pose->parent ); + LL( pose->mask ); + LL( pose->channeloffset[0] ); + LL( pose->channeloffset[1] ); + LL( pose->channeloffset[2] ); + LL( pose->channeloffset[3] ); + LL( pose->channeloffset[4] ); + LL( pose->channeloffset[5] ); + LL( pose->channeloffset[6] ); + LL( pose->channeloffset[7] ); + LL( pose->channeloffset[8] ); + LL( pose->channeloffset[9] ); + LL( pose->channelscale[0] ); + LL( pose->channelscale[1] ); + LL( pose->channelscale[2] ); + LL( pose->channelscale[3] ); + LL( pose->channelscale[4] ); + LL( pose->channelscale[5] ); + LL( pose->channelscale[6] ); + LL( pose->channelscale[7] ); + LL( pose->channelscale[8] ); + LL( pose->channelscale[9] ); + } } if (header->ofs_bounds) @@ -418,7 +437,8 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na // allocate the model and copy the data size = sizeof(iqmData_t); size += header->num_meshes * sizeof( srfIQModel_t ); - size += header->num_joints * header->num_frames * 12 * sizeof( float ); + size += header->num_joints * 12 * sizeof( float ); // joint mats + size += header->num_joints * header->num_frames * 12 * sizeof( float ); // pose mats if(header->ofs_bounds) size += header->num_frames * 6 * sizeof(float); // model bounds size += header->num_vertexes * 3 * sizeof(float); // positions @@ -443,7 +463,8 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na iqmData->num_surfaces = header->num_meshes; iqmData->num_joints = header->num_joints; iqmData->surfaces = (srfIQModel_t *)(iqmData + 1); - iqmData->poseMats = (float *) (iqmData->surfaces + iqmData->num_surfaces); + iqmData->jointMats = (float *) (iqmData->surfaces + iqmData->num_surfaces); + iqmData->poseMats = iqmData->jointMats + 12 * header->num_joints; if(header->ofs_bounds) { iqmData->bounds = iqmData->poseMats + 12 * header->num_joints * header->num_frames; @@ -461,9 +482,13 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na iqmData->triangles = iqmData->jointParents + header->num_joints; iqmData->names = (char *)(iqmData->triangles + 3 * header->num_triangles); + if ( header->num_joints == 0 ) + iqmData->jointMats = iqmData->poseMats = NULL; + // calculate joint matrices and their inverses - // they are needed only until the pose matrices are calculated - mat = jointMats; + // joint inverses are needed only until the pose matrices are calculated + mat = iqmData->jointMats; + matInv = jointInvMats; joint = (iqmJoint_t *)((byte *)header + header->ofs_joints); for( i = 0; i < header->num_joints; i++, joint++ ) { float baseFrame[12], invBaseFrame[12]; @@ -473,17 +498,17 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na if ( joint->parent >= 0 ) { - Matrix34Multiply( jointMats + 2 * 12 * joint->parent, baseFrame, mat ); - mat += 12; - Matrix34Multiply( invBaseFrame, jointMats + 2 * 12 * joint->parent + 12, mat ); + Matrix34Multiply( iqmData->jointMats + 12 * joint->parent, baseFrame, mat ); mat += 12; + Matrix34Multiply( invBaseFrame, jointInvMats + 12 * joint->parent, matInv ); + matInv += 12; } else { Com_Memcpy( mat, baseFrame, sizeof(baseFrame) ); mat += 12; - Com_Memcpy( mat, invBaseFrame, sizeof(invBaseFrame) ); - mat += 12; + Com_Memcpy( matInv, invBaseFrame, sizeof(invBaseFrame) ); + matInv += 12; } } @@ -535,13 +560,13 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na JointToMatrix( rotate, scale, translate, mat1 ); if( pose->parent >= 0 ) { - Matrix34Multiply( jointMats + 12 * 2 * pose->parent, + Matrix34Multiply( iqmData->jointMats + 12 * pose->parent, mat1, mat2 ); } else { Com_Memcpy( mat2, mat1, sizeof(mat1) ); } - Matrix34Multiply( mat2, jointMats + 12 * (2 * j + 1), mat ); + Matrix34Multiply( mat2, jointInvMats + 12 * j, mat ); mat += 12; } } @@ -861,7 +886,7 @@ void R_AddIQMSurfaces( trRefEntity_t *ent ) { } -static void ComputeJointMats( iqmData_t *data, int frame, int oldframe, +static void ComputePoseMats( iqmData_t *data, int frame, int oldframe, float backlerp, float *mat ) { float *mat1, *mat2; int *joint = data->jointParents; @@ -897,6 +922,23 @@ static void ComputeJointMats( iqmData_t *data, int frame, int oldframe, } } +static void ComputeJointMats( iqmData_t *data, int frame, int oldframe, + float backlerp, float *mat ) { + float *mat1; + int i; + + ComputePoseMats( data, frame, oldframe, backlerp, mat ); + + for( i = 0; i < data->num_joints; i++ ) { + float outmat[12]; + mat1 = mat + 12 * i; + + Com_Memcpy(outmat, mat1, sizeof(outmat)); + + Matrix34Multiply_OnlySetOrigin( outmat, data->jointMats + 12 * i, mat1 ); + } +} + /* ================= @@ -911,13 +953,13 @@ void RB_IQMSurfaceAnim( surfaceType_t *surface ) { float jointMats[IQM_MAX_JOINTS * 12]; int i; - vec4_t *outXYZ = &tess.xyz[tess.numVertexes]; - vec4_t *outNormal = &tess.normal[tess.numVertexes]; - vec2_t (*outTexCoord)[2] = &tess.texCoords[tess.numVertexes]; - color4ub_t *outColor = &tess.vertexColors[tess.numVertexes]; + vec4_t *outXYZ; + vec4_t *outNormal; + vec2_t (*outTexCoord)[2]; + color4ub_t *outColor; - int frame = backEnd.currentEntity->e.frame % data->num_frames; - int oldframe = backEnd.currentEntity->e.oldframe % data->num_frames; + int frame = data->num_frames ? backEnd.currentEntity->e.frame % data->num_frames : 0; + int oldframe = data->num_frames ? backEnd.currentEntity->e.oldframe % data->num_frames : 0; float backlerp = backEnd.currentEntity->e.backlerp; int *tri; @@ -926,8 +968,15 @@ void RB_IQMSurfaceAnim( surfaceType_t *surface ) { RB_CHECKOVERFLOW( surf->num_vertexes, surf->num_triangles * 3 ); + outXYZ = &tess.xyz[tess.numVertexes]; + outNormal = &tess.normal[tess.numVertexes]; + outTexCoord = &tess.texCoords[tess.numVertexes]; + outColor = &tess.vertexColors[tess.numVertexes]; + // compute interpolated joint matrices - ComputeJointMats( data, frame, oldframe, backlerp, jointMats ); + if ( data->num_joints > 0 ) { + ComputePoseMats( data, frame, oldframe, backlerp, jointMats ); + } // transform vertexes and fill other data for( i = 0; i < surf->num_vertexes; @@ -937,20 +986,28 @@ void RB_IQMSurfaceAnim( surfaceType_t *surface ) { float nrmMat[9]; int vtx = i + surf->first_vertex; - // compute the vertex matrix by blending the up to - // four blend weights - for( k = 0; k < 12; k++ ) - vtxMat[k] = data->blendWeights[4*vtx] - * jointMats[12*data->blendIndexes[4*vtx] + k]; - for( j = 1; j < 4; j++ ) { - if( data->blendWeights[4*vtx + j] <= 0 ) - break; + if ( data->num_joints == 0 || data->blendWeights[4*vtx] <= 0 ) { + // no blend joint, use identity matrix. + for( j = 0; j < 3; j++ ) { + for( k = 0; k < 4; k++ ) + vtxMat[4*j+k] = ( k == j ) ? 1 : 0; + } + } else { + // compute the vertex matrix by blending the up to + // four blend weights for( k = 0; k < 12; k++ ) - vtxMat[k] += data->blendWeights[4*vtx + j] - * jointMats[12*data->blendIndexes[4*vtx + j] + k]; + vtxMat[k] = data->blendWeights[4*vtx] + * jointMats[12*data->blendIndexes[4*vtx] + k]; + for( j = 1; j < 4; j++ ) { + if( data->blendWeights[4*vtx + j] <= 0 ) + break; + for( k = 0; k < 12; k++ ) + vtxMat[k] += data->blendWeights[4*vtx + j] + * jointMats[12*data->blendIndexes[4*vtx + j] + k]; + } + for( k = 0; k < 12; k++ ) + vtxMat[k] *= 1.0f / 255.0f; } - for( k = 0; k < 12; k++ ) - vtxMat[k] *= 1.0f / 255.0f; // compute the normal matrix as transpose of the adjoint // of the vertex matrix diff --git a/code/renderer/tr_scene.c b/code/renderergl1/tr_scene.c similarity index 91% rename from code/renderer/tr_scene.c rename to code/renderergl1/tr_scene.c index 807cc48d..5d7a3dd1 100644 --- a/code/renderer/tr_scene.c +++ b/code/renderergl1/tr_scene.c @@ -38,20 +38,12 @@ int r_numpolyverts; /* ==================== -R_ToggleSmpFrame +R_InitNextFrame ==================== */ -void R_ToggleSmpFrame( void ) { - if ( r_smp->integer ) { - // use the other buffers next frame, because another CPU - // may still be rendering into the current ones - tr.smpFrame ^= 1; - } else { - tr.smpFrame = 0; - } - - backEndData[tr.smpFrame]->commands.used = 0; +void R_InitNextFrame( void ) { + backEndData->commands.used = 0; r_firstSceneDrawSurf = 0; @@ -143,11 +135,11 @@ void RE_AddPolyToScene( qhandle_t hShader, int numVerts, const polyVert_t *verts return; } - poly = &backEndData[tr.smpFrame]->polys[r_numpolys]; + poly = &backEndData->polys[r_numpolys]; poly->surfaceType = SF_POLY; poly->hShader = hShader; poly->numVerts = numVerts; - poly->verts = &backEndData[tr.smpFrame]->polyVerts[r_numpolyverts]; + poly->verts = &backEndData->polyVerts[r_numpolyverts]; Com_Memcpy( poly->verts, &verts[numVerts*j], numVerts * sizeof( *verts ) ); @@ -224,8 +216,8 @@ void RE_AddRefEntityToScene( const refEntity_t *ent ) { ri.Error( ERR_DROP, "RE_AddRefEntityToScene: bad reType %i", ent->reType ); } - backEndData[tr.smpFrame]->entities[r_numentities].e = *ent; - backEndData[tr.smpFrame]->entities[r_numentities].lightingCalculated = qfalse; + backEndData->entities[r_numentities].e = *ent; + backEndData->entities[r_numentities].lightingCalculated = qfalse; r_numentities++; } @@ -253,7 +245,7 @@ void RE_AddDynamicLightToScene( const vec3_t org, float intensity, float r, floa if ( glConfig.hardwareType == GLHW_RIVA128 || glConfig.hardwareType == GLHW_PERMEDIA2 ) { return; } - dl = &backEndData[tr.smpFrame]->dlights[r_numdlights++]; + dl = &backEndData->dlights[r_numdlights++]; VectorCopy (org, dl->origin); dl->radius = intensity; dl->color[0] = r; @@ -355,16 +347,16 @@ void RE_RenderScene( const refdef_t *fd ) { tr.refdef.floatTime = tr.refdef.time * 0.001f; tr.refdef.numDrawSurfs = r_firstSceneDrawSurf; - tr.refdef.drawSurfs = backEndData[tr.smpFrame]->drawSurfs; + tr.refdef.drawSurfs = backEndData->drawSurfs; tr.refdef.num_entities = r_numentities - r_firstSceneEntity; - tr.refdef.entities = &backEndData[tr.smpFrame]->entities[r_firstSceneEntity]; + tr.refdef.entities = &backEndData->entities[r_firstSceneEntity]; tr.refdef.num_dlights = r_numdlights - r_firstSceneDlight; - tr.refdef.dlights = &backEndData[tr.smpFrame]->dlights[r_firstSceneDlight]; + tr.refdef.dlights = &backEndData->dlights[r_firstSceneDlight]; tr.refdef.numPolys = r_numpolys - r_firstScenePoly; - tr.refdef.polys = &backEndData[tr.smpFrame]->polys[r_firstScenePoly]; + tr.refdef.polys = &backEndData->polys[r_firstScenePoly]; // turn off dynamic lighting globally by clearing all the // dlights if it needs to be disabled or if vertex lighting is enabled diff --git a/code/renderer/tr_shade.c b/code/renderergl1/tr_shade.c similarity index 100% rename from code/renderer/tr_shade.c rename to code/renderergl1/tr_shade.c diff --git a/code/renderer/tr_shade_calc.c b/code/renderergl1/tr_shade_calc.c similarity index 100% rename from code/renderer/tr_shade_calc.c rename to code/renderergl1/tr_shade_calc.c diff --git a/code/renderer/tr_shader.c b/code/renderergl1/tr_shader.c similarity index 97% rename from code/renderer/tr_shader.c rename to code/renderergl1/tr_shader.c index 72fb5487..877c6191 100644 --- a/code/renderer/tr_shader.c +++ b/code/renderergl1/tr_shader.c @@ -636,7 +636,17 @@ static qboolean ParseStage( shaderStage_t *stage, char **text ) } else { - stage->bundle[0].image[0] = R_FindImageFile( token, !shader.noMipMaps, !shader.noPicMip, GL_REPEAT ); + imgType_t type = IMGTYPE_COLORALPHA; + imgFlags_t flags = IMGFLAG_NONE; + + if (!shader.noMipMaps) + flags |= IMGFLAG_MIPMAP; + + if (!shader.noPicMip) + flags |= IMGFLAG_PICMIP; + + stage->bundle[0].image[0] = R_FindImageFile( token, type, flags ); + if ( !stage->bundle[0].image[0] ) { ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name ); @@ -649,6 +659,9 @@ static qboolean ParseStage( shaderStage_t *stage, char **text ) // else if ( !Q_stricmp( token, "clampmap" ) ) { + imgType_t type = IMGTYPE_COLORALPHA; + imgFlags_t flags = IMGFLAG_CLAMPTOEDGE; + token = COM_ParseExt( text, qfalse ); if ( !token[0] ) { @@ -656,7 +669,13 @@ static qboolean ParseStage( shaderStage_t *stage, char **text ) return qfalse; } - stage->bundle[0].image[0] = R_FindImageFile( token, !shader.noMipMaps, !shader.noPicMip, GL_CLAMP_TO_EDGE ); + if (!shader.noMipMaps) + flags |= IMGFLAG_MIPMAP; + + if (!shader.noPicMip) + flags |= IMGFLAG_PICMIP; + + stage->bundle[0].image[0] = R_FindImageFile( token, type, flags ); if ( !stage->bundle[0].image[0] ) { ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name ); @@ -686,7 +705,15 @@ static qboolean ParseStage( shaderStage_t *stage, char **text ) } num = stage->bundle[0].numImageAnimations; if ( num < MAX_IMAGE_ANIMATIONS ) { - stage->bundle[0].image[num] = R_FindImageFile( token, !shader.noMipMaps, !shader.noPicMip, GL_REPEAT ); + imgFlags_t flags = IMGFLAG_NONE; + + if (!shader.noMipMaps) + flags |= IMGFLAG_MIPMAP; + + if (!shader.noPicMip) + flags |= IMGFLAG_PICMIP; + + stage->bundle[0].image[num] = R_FindImageFile( token, IMGTYPE_COLORALPHA, flags ); if ( !stage->bundle[0].image[num] ) { ri.Printf( PRINT_WARNING, "WARNING: R_FindImageFile could not find '%s' in shader '%s'\n", token, shader.name ); @@ -1218,6 +1245,7 @@ static void ParseSkyParms( char **text ) { static char *suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"}; char pathname[MAX_QPATH]; int i; + imgFlags_t imgFlags = IMGFLAG_MIPMAP | IMGFLAG_PICMIP; // outerbox token = COM_ParseExt( text, qfalse ); @@ -1229,7 +1257,7 @@ static void ParseSkyParms( char **text ) { for (i=0 ; i<6 ; i++) { Com_sprintf( pathname, sizeof(pathname), "%s_%s.tga" , token, suf[i] ); - shader.sky.outerbox[i] = R_FindImageFile( ( char * ) pathname, qtrue, qtrue, GL_CLAMP_TO_EDGE ); + shader.sky.outerbox[i] = R_FindImageFile( ( char * ) pathname, IMGTYPE_COLORALPHA, imgFlags | IMGFLAG_CLAMPTOEDGE ); if ( !shader.sky.outerbox[i] ) { shader.sky.outerbox[i] = tr.defaultImage; @@ -1260,7 +1288,7 @@ static void ParseSkyParms( char **text ) { for (i=0 ; i<6 ; i++) { Com_sprintf( pathname, sizeof(pathname), "%s_%s.tga" , token, suf[i] ); - shader.sky.innerbox[i] = R_FindImageFile( ( char * ) pathname, qtrue, qtrue, GL_REPEAT ); + shader.sky.innerbox[i] = R_FindImageFile( ( char * ) pathname, IMGTYPE_COLORALPHA, imgFlags ); if ( !shader.sky.innerbox[i] ) { shader.sky.innerbox[i] = tr.defaultImage; } @@ -1562,7 +1590,7 @@ static qboolean ParseShader( char **text ) // light determines flaring in q3map, not needed here else if ( !Q_stricmp(token, "light") ) { - token = COM_ParseExt( text, qfalse ); + (void)COM_ParseExt( text, qfalse ); continue; } // cull @@ -1640,7 +1668,7 @@ static void ComputeStageIteratorFunc( void ) if ( shader.isSky ) { shader.optimalStageIteratorFunc = RB_StageIteratorSky; - goto done; + return; } if ( r_ignoreFastPath->integer ) @@ -1666,7 +1694,7 @@ static void ComputeStageIteratorFunc( void ) if ( !shader.numDeforms ) { shader.optimalStageIteratorFunc = RB_StageIteratorVertexLitTexture; - goto done; + return; } } } @@ -1692,16 +1720,12 @@ static void ComputeStageIteratorFunc( void ) if ( shader.multitextureEnv ) { shader.optimalStageIteratorFunc = RB_StageIteratorLightmappedMultitexture; - goto done; } } } } } } - -done: - return; } typedef struct { @@ -1872,7 +1896,7 @@ sortedIndex. ============== */ static void FixRenderCommandList( int newShader ) { - renderCommandList_t *cmdList = &backEndData[tr.smpFrame]->commands; + renderCommandList_t *cmdList = &backEndData->commands; if( cmdList ) { const void *curCmd = cmdList->cmds; @@ -2358,7 +2382,7 @@ static char *FindShaderInShaderText( const char *shadername ) { } else { // skip the definition - SkipBracedSection( &p ); + SkipBracedSection( &p, 0 ); } } @@ -2473,12 +2497,6 @@ shader_t *R_FindShader( const char *name, int lightmapIndex, qboolean mipRawImag } } - // make sure the render thread is stopped, because we are probably - // going to have to upload an image - if (r_smp->integer) { - R_SyncRenderThread(); - } - // clear the global shader Com_Memset( &shader, 0, sizeof( shader ) ); Com_Memset( &stages, 0, sizeof( stages ) ); @@ -2518,11 +2536,26 @@ shader_t *R_FindShader( const char *name, int lightmapIndex, qboolean mipRawImag // if not defined in the in-memory shader descriptions, // look for a single supported image file // - image = R_FindImageFile( name, mipRawImage, mipRawImage, mipRawImage ? GL_REPEAT : GL_CLAMP_TO_EDGE ); - if ( !image ) { - ri.Printf( PRINT_DEVELOPER, "Couldn't find image file for shader %s\n", name ); - shader.defaultShader = qtrue; - return FinishShader(); + { + imgFlags_t flags; + + flags = IMGFLAG_NONE; + + if (mipRawImage) + { + flags |= IMGFLAG_MIPMAP | IMGFLAG_PICMIP; + } + else + { + flags |= IMGFLAG_CLAMPTOEDGE; + } + + image = R_FindImageFile( name, IMGTYPE_COLORALPHA, flags ); + if ( !image ) { + ri.Printf( PRINT_DEVELOPER, "Couldn't find image file for shader %s\n", name ); + shader.defaultShader = qtrue; + return FinishShader(); + } } // @@ -2609,12 +2642,6 @@ qhandle_t RE_RegisterShaderFromImage(const char *name, int lightmapIndex, image_ } } - // make sure the render thread is stopped, because we are probably - // going to have to upload an image - if (r_smp->integer) { - R_SyncRenderThread(); - } - // clear the global shader Com_Memset( &shader, 0, sizeof( shader ) ); Com_Memset( &stages, 0, sizeof( stages ) ); @@ -2889,6 +2916,8 @@ static void ScanAndLoadShaderFiles( void ) int i; char *oldp, *token, *hashMem, *textEnd; int shaderTextHashTableSizes[MAX_SHADERTEXT_HASH], hash, size; + char shaderName[MAX_QPATH]; + int shaderLine; long sum = 0, summand; // scan for shader files @@ -2918,26 +2947,40 @@ static void ScanAndLoadShaderFiles( void ) // Do a simple check on the shader structure in that file to make sure one bad shader file cannot fuck up all other shaders. p = buffers[i]; + COM_BeginParseSession(filename); while(1) { token = COM_ParseExt(&p, qtrue); if(!*token) break; - - oldp = p; - + + Q_strncpyz(shaderName, token, sizeof(shaderName)); + shaderLine = COM_GetCurrentParseLine(); + token = COM_ParseExt(&p, qtrue); - if(token[0] != '{' && token[1] != '\0') + if(token[0] != '{' || token[1] != '\0') { - ri.Printf(PRINT_WARNING, "WARNING: Bad shader file %s has incorrect syntax.\n", filename); + ri.Printf(PRINT_WARNING, "WARNING: Ignoring shader file %s. Shader \"%s\" on line %d missing opening brace", + filename, shaderName, shaderLine); + if (token[0]) + { + ri.Printf(PRINT_WARNING, " (found \"%s\" on line %d)", token, COM_GetCurrentParseLine()); + } + ri.Printf(PRINT_WARNING, ".\n"); ri.FS_FreeFile(buffers[i]); buffers[i] = NULL; break; } - SkipBracedSection(&oldp); - p = oldp; + if(!SkipBracedSection(&p, 1)) + { + ri.Printf(PRINT_WARNING, "WARNING: Ignoring shader file %s. Shader \"%s\" on line %d missing closing brace.\n", + filename, shaderName, shaderLine); + ri.FS_FreeFile(buffers[i]); + buffers[i] = NULL; + break; + } } @@ -2981,7 +3024,7 @@ static void ScanAndLoadShaderFiles( void ) hash = generateHashValue(token, MAX_SHADERTEXT_HASH); shaderTextHashTableSizes[hash]++; size++; - SkipBracedSection(&p); + SkipBracedSection(&p, 0); } size += MAX_SHADERTEXT_HASH; @@ -3007,7 +3050,7 @@ static void ScanAndLoadShaderFiles( void ) hash = generateHashValue(token, MAX_SHADERTEXT_HASH); shaderTextHashTable[hash][shaderTextHashTableSizes[hash]++] = oldp; - SkipBracedSection(&p); + SkipBracedSection(&p, 0); } return; diff --git a/code/rend2/tr_shadows.c b/code/renderergl1/tr_shadows.c similarity index 100% rename from code/rend2/tr_shadows.c rename to code/renderergl1/tr_shadows.c diff --git a/code/renderer/tr_sky.c b/code/renderergl1/tr_sky.c similarity index 90% rename from code/renderer/tr_sky.c rename to code/renderergl1/tr_sky.c index 3e774a31..daa5ff12 100644 --- a/code/renderer/tr_sky.c +++ b/code/renderergl1/tr_sky.c @@ -696,23 +696,21 @@ void R_InitSkyTexCoords( float heightCloud ) /* ** RB_DrawSun */ -void RB_DrawSun( void ) { +void RB_DrawSun( float scale, shader_t *shader ) { float size; float dist; vec3_t origin, vec1, vec2; - vec3_t temp; + byte sunColor[4] = { 255, 255, 255, 255 }; if ( !backEnd.skyRenderedThisView ) { return; } - if ( !r_drawSun->integer ) { - return; - } + qglLoadMatrixf( backEnd.viewParms.world.modelMatrix ); qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]); dist = backEnd.viewParms.zFar / 1.75; // div sqrt(3) - size = dist * 0.4; + size = dist * scale; VectorScale( tr.sunDirection, dist, origin ); PerpendicularVector( vec1, tr.sunDirection ); @@ -724,58 +722,9 @@ void RB_DrawSun( void ) { // farthest depth range qglDepthRange( 1.0, 1.0 ); - // FIXME: use quad stamp - RB_BeginSurface( tr.sunShader, tess.fogNum ); - VectorCopy( origin, temp ); - VectorSubtract( temp, vec1, temp ); - VectorSubtract( temp, vec2, temp ); - VectorCopy( temp, tess.xyz[tess.numVertexes] ); - tess.texCoords[tess.numVertexes][0][0] = 0; - tess.texCoords[tess.numVertexes][0][1] = 0; - tess.vertexColors[tess.numVertexes][0] = 255; - tess.vertexColors[tess.numVertexes][1] = 255; - tess.vertexColors[tess.numVertexes][2] = 255; - tess.numVertexes++; + RB_BeginSurface( shader, 0 ); - VectorCopy( origin, temp ); - VectorAdd( temp, vec1, temp ); - VectorSubtract( temp, vec2, temp ); - VectorCopy( temp, tess.xyz[tess.numVertexes] ); - tess.texCoords[tess.numVertexes][0][0] = 0; - tess.texCoords[tess.numVertexes][0][1] = 1; - tess.vertexColors[tess.numVertexes][0] = 255; - tess.vertexColors[tess.numVertexes][1] = 255; - tess.vertexColors[tess.numVertexes][2] = 255; - tess.numVertexes++; - - VectorCopy( origin, temp ); - VectorAdd( temp, vec1, temp ); - VectorAdd( temp, vec2, temp ); - VectorCopy( temp, tess.xyz[tess.numVertexes] ); - tess.texCoords[tess.numVertexes][0][0] = 1; - tess.texCoords[tess.numVertexes][0][1] = 1; - tess.vertexColors[tess.numVertexes][0] = 255; - tess.vertexColors[tess.numVertexes][1] = 255; - tess.vertexColors[tess.numVertexes][2] = 255; - tess.numVertexes++; - - VectorCopy( origin, temp ); - VectorSubtract( temp, vec1, temp ); - VectorAdd( temp, vec2, temp ); - VectorCopy( temp, tess.xyz[tess.numVertexes] ); - tess.texCoords[tess.numVertexes][0][0] = 1; - tess.texCoords[tess.numVertexes][0][1] = 0; - tess.vertexColors[tess.numVertexes][0] = 255; - tess.vertexColors[tess.numVertexes][1] = 255; - tess.vertexColors[tess.numVertexes][2] = 255; - tess.numVertexes++; - - tess.indexes[tess.numIndexes++] = 0; - tess.indexes[tess.numIndexes++] = 1; - tess.indexes[tess.numIndexes++] = 2; - tess.indexes[tess.numIndexes++] = 0; - tess.indexes[tess.numIndexes++] = 2; - tess.indexes[tess.numIndexes++] = 3; + RB_AddQuadStamp(origin, vec1, vec2, sunColor); RB_EndSurface(); diff --git a/code/rend2/tr_subs.c b/code/renderergl1/tr_subs.c similarity index 100% rename from code/rend2/tr_subs.c rename to code/renderergl1/tr_subs.c diff --git a/code/renderer/tr_surface.c b/code/renderergl1/tr_surface.c similarity index 99% rename from code/renderer/tr_surface.c rename to code/renderergl1/tr_surface.c index 75592150..3b4a943b 100644 --- a/code/renderer/tr_surface.c +++ b/code/renderergl1/tr_surface.c @@ -231,7 +231,7 @@ static void RB_SurfaceTriangles( srfTriangles_t *srf ) { int dlightBits; qboolean needsNormal; - dlightBits = srf->dlightBits[backEnd.smpFrame]; + dlightBits = srf->dlightBits; tess.dlightBits |= dlightBits; RB_CHECKOVERFLOW( srf->numVerts, srf->numIndexes ); @@ -915,7 +915,7 @@ static void RB_SurfaceFace( srfSurfaceFace_t *surf ) { RB_CHECKOVERFLOW( surf->numPoints, surf->numIndices ); - dlightBits = surf->dlightBits[backEnd.smpFrame]; + dlightBits = surf->dlightBits; tess.dlightBits |= dlightBits; indices = ( unsigned * ) ( ( ( char * ) surf ) + surf->ofsIndices ); @@ -1007,7 +1007,7 @@ static void RB_SurfaceGrid( srfGridMesh_t *cv ) { int *vDlightBits; qboolean needsNormal; - dlightBits = cv->dlightBits[backEnd.smpFrame]; + dlightBits = cv->dlightBits; tess.dlightBits |= dlightBits; // determine the allowable discrepance @@ -1157,6 +1157,7 @@ Draws x/y/z lines from the origin for orientation debugging */ static void RB_SurfaceAxis( void ) { GL_Bind( tr.whiteImage ); + GL_State( GLS_DEFAULT ); qglLineWidth( 3 ); qglBegin( GL_LINES ); qglColor3f( 1,0,0 ); @@ -1202,7 +1203,6 @@ static void RB_SurfaceEntity( surfaceType_t *surfType ) { RB_SurfaceAxis(); break; } - return; } static void RB_SurfaceBad( surfaceType_t *surfType ) { @@ -1234,9 +1234,7 @@ void (*rb_surfaceTable[SF_NUM_SURFACE_TYPES])( void *) = { (void(*)(void*))RB_SurfacePolychain, // SF_POLY, (void(*)(void*))RB_SurfaceMesh, // SF_MD3, (void(*)(void*))RB_SurfaceAnim, // SF_MD4, -#ifdef RAVENMD4 (void(*)(void*))RB_MDRSurfaceAnim, // SF_MDR, -#endif (void(*)(void*))RB_IQMSurfaceAnim, // SF_IQM, (void(*)(void*))RB_SurfaceFlare, // SF_FLARE, (void(*)(void*))RB_SurfaceEntity, // SF_ENTITY diff --git a/code/renderer/tr_world.c b/code/renderergl1/tr_world.c similarity index 98% rename from code/renderer/tr_world.c rename to code/renderergl1/tr_world.c index 376bf122..0a2743f9 100644 --- a/code/renderer/tr_world.c +++ b/code/renderergl1/tr_world.c @@ -180,7 +180,7 @@ static int R_DlightFace( srfSurfaceFace_t *face, int dlightBits ) { tr.pc.c_dlightSurfacesCulled++; } - face->dlightBits[ tr.smpFrame ] = dlightBits; + face->dlightBits = dlightBits; return dlightBits; } @@ -208,14 +208,14 @@ static int R_DlightGrid( srfGridMesh_t *grid, int dlightBits ) { tr.pc.c_dlightSurfacesCulled++; } - grid->dlightBits[ tr.smpFrame ] = dlightBits; + grid->dlightBits = dlightBits; return dlightBits; } static int R_DlightTrisurf( srfTriangles_t *surf, int dlightBits ) { // FIXME: more dlight culling to trisurfs... - surf->dlightBits[ tr.smpFrame ] = dlightBits; + surf->dlightBits = dlightBits; return dlightBits; #if 0 int i; @@ -241,7 +241,7 @@ static int R_DlightTrisurf( srfTriangles_t *surf, int dlightBits ) { tr.pc.c_dlightSurfacesCulled++; } - grid->dlightBits[ tr.smpFrame ] = dlightBits; + grid->dlightBits = dlightBits; return dlightBits; #endif } @@ -530,7 +530,7 @@ R_ClusterPVS ============== */ static const byte *R_ClusterPVS (int cluster) { - if (!tr.world || !tr.world->vis || cluster < 0 || cluster >= tr.world->numClusters ) { + if (!tr.world->vis || cluster < 0 || cluster >= tr.world->numClusters ) { return tr.world->novis; } diff --git a/code/rend2/glsl/bokeh_fp.glsl b/code/renderergl2/glsl/bokeh_fp.glsl similarity index 100% rename from code/rend2/glsl/bokeh_fp.glsl rename to code/renderergl2/glsl/bokeh_fp.glsl diff --git a/code/rend2/glsl/bokeh_vp.glsl b/code/renderergl2/glsl/bokeh_vp.glsl similarity index 100% rename from code/rend2/glsl/bokeh_vp.glsl rename to code/renderergl2/glsl/bokeh_vp.glsl diff --git a/code/rend2/glsl/calclevels4x_fp.glsl b/code/renderergl2/glsl/calclevels4x_fp.glsl similarity index 100% rename from code/rend2/glsl/calclevels4x_fp.glsl rename to code/renderergl2/glsl/calclevels4x_fp.glsl diff --git a/code/rend2/glsl/calclevels4x_vp.glsl b/code/renderergl2/glsl/calclevels4x_vp.glsl similarity index 100% rename from code/rend2/glsl/calclevels4x_vp.glsl rename to code/renderergl2/glsl/calclevels4x_vp.glsl diff --git a/code/rend2/glsl/depthblur_fp.glsl b/code/renderergl2/glsl/depthblur_fp.glsl similarity index 100% rename from code/rend2/glsl/depthblur_fp.glsl rename to code/renderergl2/glsl/depthblur_fp.glsl diff --git a/code/rend2/glsl/depthblur_vp.glsl b/code/renderergl2/glsl/depthblur_vp.glsl similarity index 100% rename from code/rend2/glsl/depthblur_vp.glsl rename to code/renderergl2/glsl/depthblur_vp.glsl diff --git a/code/rend2/glsl/dlight_fp.glsl b/code/renderergl2/glsl/dlight_fp.glsl similarity index 100% rename from code/rend2/glsl/dlight_fp.glsl rename to code/renderergl2/glsl/dlight_fp.glsl diff --git a/code/rend2/glsl/dlight_vp.glsl b/code/renderergl2/glsl/dlight_vp.glsl similarity index 100% rename from code/rend2/glsl/dlight_vp.glsl rename to code/renderergl2/glsl/dlight_vp.glsl diff --git a/code/rend2/glsl/down4x_fp.glsl b/code/renderergl2/glsl/down4x_fp.glsl similarity index 100% rename from code/rend2/glsl/down4x_fp.glsl rename to code/renderergl2/glsl/down4x_fp.glsl diff --git a/code/rend2/glsl/down4x_vp.glsl b/code/renderergl2/glsl/down4x_vp.glsl similarity index 100% rename from code/rend2/glsl/down4x_vp.glsl rename to code/renderergl2/glsl/down4x_vp.glsl diff --git a/code/rend2/glsl/fogpass_fp.glsl b/code/renderergl2/glsl/fogpass_fp.glsl similarity index 100% rename from code/rend2/glsl/fogpass_fp.glsl rename to code/renderergl2/glsl/fogpass_fp.glsl diff --git a/code/rend2/glsl/fogpass_vp.glsl b/code/renderergl2/glsl/fogpass_vp.glsl similarity index 100% rename from code/rend2/glsl/fogpass_vp.glsl rename to code/renderergl2/glsl/fogpass_vp.glsl diff --git a/code/rend2/glsl/generic_fp.glsl b/code/renderergl2/glsl/generic_fp.glsl similarity index 100% rename from code/rend2/glsl/generic_fp.glsl rename to code/renderergl2/glsl/generic_fp.glsl diff --git a/code/rend2/glsl/generic_vp.glsl b/code/renderergl2/glsl/generic_vp.glsl similarity index 100% rename from code/rend2/glsl/generic_vp.glsl rename to code/renderergl2/glsl/generic_vp.glsl diff --git a/code/rend2/glsl/lightall_fp.glsl b/code/renderergl2/glsl/lightall_fp.glsl similarity index 54% rename from code/rend2/glsl/lightall_fp.glsl rename to code/renderergl2/glsl/lightall_fp.glsl index ff6eb865..0b455dd6 100644 --- a/code/rend2/glsl/lightall_fp.glsl +++ b/code/renderergl2/glsl/lightall_fp.glsl @@ -27,11 +27,19 @@ uniform int u_TCGen0; #endif #if defined(USE_LIGHT_VECTOR) +uniform vec4 u_LightOrigin; uniform vec3 u_DirectedLight; uniform vec3 u_AmbientLight; uniform float u_LightRadius; #endif +#if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP) +uniform vec3 u_PrimaryLightColor; +uniform vec3 u_PrimaryLightAmbient; +uniform float u_PrimaryLightRadius; +#endif + + #if defined(USE_LIGHT) uniform vec2 u_MaterialInfo; #endif @@ -46,24 +54,30 @@ varying vec4 var_Color; varying vec3 var_Position; #endif -#if defined(USE_TCGEN) || defined(USE_NORMALMAP) || defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) +#if defined(USE_TCGEN) || defined(USE_NORMALMAP) || (defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)) varying vec3 var_SampleToView; #endif #if !defined(USE_FAST_LIGHT) varying vec3 var_Normal; - #if defined(USE_VERT_TANGENT_SPACE) +#endif + +#if defined(USE_VERT_TANGENT_SPACE) varying vec3 var_Tangent; varying vec3 var_Bitangent; - #endif #endif varying vec3 var_VertLight; #if defined(USE_LIGHT) && !defined(USE_DELUXEMAP) -varying vec3 var_WorldLight; +varying vec3 var_LightDirection; #endif +#if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP) +varying vec3 var_PrimaryLightDirection; +#endif + + #define EPSILON 0.00000001 #if defined(USE_PARALLAXMAP) @@ -126,45 +140,45 @@ float RayIntersectDisplaceMap(vec2 dp, vec2 ds, sampler2D normalMap) } #endif -float CalcDiffuse(vec3 N, vec3 L, vec3 E, float NE, float NL, float fzero, float shininess) +vec3 CalcDiffuse(vec3 diffuseAlbedo, vec3 N, vec3 L, vec3 E, float NE, float NL, float shininess) { #if defined(USE_OREN_NAYAR) || defined(USE_TRIACE_OREN_NAYAR) float gamma = dot(E, L) - NE * NL; float B = 2.22222 + 0.1 * shininess; - #if defined(USE_OREN_NAYAR) + #if defined(USE_OREN_NAYAR) float A = 1.0 - 1.0 / (2.0 + 0.33 * shininess); gamma = clamp(gamma, 0.0, 1.0); - #endif + #endif - #if defined(USE_TRIACE_OREN_NAYAR) + #if defined(USE_TRIACE_OREN_NAYAR) float A = 1.0 - 1.0 / (2.0 + 0.65 * shininess); if (gamma >= 0.0) - #endif + #endif { B *= max(max(NL, NE), EPSILON); } - return (A + gamma / B) * (1.0 - fzero); + return diffuseAlbedo * (A + gamma / B); #else - return 1.0 - fzero; + return diffuseAlbedo; #endif } #if defined(USE_SPECULARMAP) -float CalcSpecular(float NH, float NL, float NE, float EH, float fzero, float shininess) +vec3 CalcSpecular(vec3 specularReflectance, float NH, float NL, float NE, float EH, float shininess) { #if defined(USE_BLINN) || defined(USE_TRIACE) || defined(USE_TORRANCE_SPARROW) float blinn = pow(NH, shininess); #endif #if defined(USE_BLINN) - return blinn; + return specularReflectance * blinn; #endif #if defined(USE_COOK_TORRANCE) || defined (USE_TRIACE) || defined (USE_TORRANCE_SPARROW) - float fresnel = fzero + (1.0 - fzero) * pow(1.0 - EH, 5); + vec3 fresnel = specularReflectance + (vec3(1.0) - specularReflectance) * pow(1.0 - EH, 5); #endif #if defined(USE_COOK_TORRANCE) || defined(USE_TORRANCE_SPARROW) @@ -198,14 +212,14 @@ float CalcSpecular(float NH, float NL, float NE, float EH, float fzero, float sh void main() { #if !defined(USE_FAST_LIGHT) && (defined(USE_LIGHT) || defined(USE_NORMALMAP)) - vec3 surfNormal = normalize(var_Normal); + vec3 surfN = normalize(var_Normal); #endif #if defined(USE_DELUXEMAP) - vec3 worldLight = 2.0 * texture2D(u_DeluxeMap, var_LightTex).xyz - vec3(1.0); - //worldLight += var_WorldLight * 0.0001; + vec3 L = 2.0 * texture2D(u_DeluxeMap, var_LightTex).xyz - vec3(1.0); + //L += var_LightDirection * 0.0001; #elif defined(USE_LIGHT) - vec3 worldLight = var_WorldLight; + vec3 L = var_LightDirection; #endif #if defined(USE_LIGHTMAP) @@ -213,101 +227,114 @@ void main() #if defined(RGBE_LIGHTMAP) lightSample.rgb *= exp2(lightSample.a * 255.0 - 128.0); #endif - vec3 directedLight = lightSample.rgb; + vec3 lightColor = lightSample.rgb; #elif defined(USE_LIGHT_VECTOR) && !defined(USE_FAST_LIGHT) #if defined(USE_INVSQRLIGHT) - float intensity = 1.0 / dot(worldLight, worldLight); + float intensity = 1.0 / dot(L, L); #else - float intensity = clamp((1.0 - dot(worldLight, worldLight) / (u_LightRadius * u_LightRadius)) * 1.07, 0.0, 1.0); + float intensity = clamp((1.0 - dot(L, L) / (u_LightRadius * u_LightRadius)) * 1.07, 0.0, 1.0); #endif - vec3 directedLight = u_DirectedLight * intensity; - vec3 ambientLight = u_AmbientLight; - - #if defined(USE_SHADOWMAP) - vec2 shadowTex = gl_FragCoord.xy * r_FBufScale; - directedLight *= texture2D(u_ShadowMap, shadowTex).r; - #endif + vec3 lightColor = u_DirectedLight * intensity; + vec3 ambientColor = u_AmbientLight; #elif defined(USE_LIGHT_VERTEX) && !defined(USE_FAST_LIGHT) - vec3 directedLight = var_VertLight; + vec3 lightColor = var_VertLight; #endif -#if defined(USE_TCGEN) || defined(USE_NORMALMAP) || defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) - vec3 SampleToView = normalize(var_SampleToView); +#if defined(USE_TCGEN) || defined(USE_NORMALMAP) || (defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)) + vec3 E = normalize(var_SampleToView); #endif - vec2 tex = var_DiffuseTex; + vec2 texCoords = var_DiffuseTex; float ambientDiff = 1.0; #if defined(USE_NORMALMAP) #if defined(USE_VERT_TANGENT_SPACE) - vec3 tangent = var_Tangent; - vec3 bitangent = var_Bitangent; + mat3 tangentToWorld = mat3(var_Tangent, var_Bitangent, var_Normal); #else vec3 q0 = dFdx(var_Position); vec3 q1 = dFdy(var_Position); - vec2 st0 = dFdx(tex); - vec2 st1 = dFdy(tex); + vec2 st0 = dFdx(texCoords); + vec2 st1 = dFdy(texCoords); float dir = sign(st1.t * st0.s - st0.t * st1.s); - vec3 tangent = normalize( q0 * st1.t - q1 * st0.t) * dir; - vec3 bitangent = -normalize( q0 * st1.s - q1 * st0.s) * dir; - #endif + vec3 tangent = normalize(q0 * st1.t - q1 * st0.t) * dir; + vec3 bitangent = -normalize(q0 * st1.s - q1 * st0.s) * dir; mat3 tangentToWorld = mat3(tangent, bitangent, var_Normal); + #endif #if defined(USE_PARALLAXMAP) - vec3 offsetDir = normalize(SampleToView * tangentToWorld); - #if 0 - float height = SampleHeight(u_NormalMap, tex); - float pdist = 0.05 * height - (0.05 / 2.0); - #else + vec3 offsetDir = normalize(E * tangentToWorld); offsetDir.xy *= -0.05 / offsetDir.z; - float pdist = RayIntersectDisplaceMap(tex, offsetDir.xy, u_NormalMap); - #endif - tex += offsetDir.xy * pdist; + + texCoords += offsetDir.xy * RayIntersectDisplaceMap(texCoords, offsetDir.xy, u_NormalMap); #endif + vec3 texN; #if defined(SWIZZLE_NORMALMAP) - vec3 normal = 2.0 * texture2D(u_NormalMap, tex).agb - 1.0; + texN.xy = 2.0 * texture2D(u_NormalMap, texCoords).ag - 1.0; #else - vec3 normal = 2.0 * texture2D(u_NormalMap, tex).rgb - 1.0; + texN.xy = 2.0 * texture2D(u_NormalMap, texCoords).rg - 1.0; #endif - normal.z = sqrt(clamp(1.0 - dot(normal.xy, normal.xy), 0.0, 1.0)); - vec3 worldNormal = tangentToWorld * normal; + texN.z = sqrt(clamp(1.0 - dot(texN.xy, texN.xy), 0.0, 1.0)); + vec3 N = tangentToWorld * texN; #if defined(r_normalAmbient) - ambientDiff = 0.781341 * normal.z + 0.218659; + ambientDiff = 0.781341 * texN.z + 0.218659; #endif -#elif defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) - vec3 worldNormal = surfNormal; +#elif defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) + vec3 N = surfN; #endif #if (defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)) || (defined(USE_TCGEN) && defined(USE_NORMALMAP)) - worldNormal = normalize(worldNormal); + N = normalize(N); #endif #if defined(USE_TCGEN) && defined(USE_NORMALMAP) if (u_TCGen0 == TCGEN_ENVIRONMENT_MAPPED) { - tex = -reflect(normalize(SampleToView), worldNormal).yz * vec2(0.5, -0.5) + 0.5; + texCoords = -reflect(E, N).yz * vec2(0.5, -0.5) + 0.5; } #endif - vec4 diffuse = texture2D(u_DiffuseMap, tex); + vec4 diffuseAlbedo = texture2D(u_DiffuseMap, texCoords); +#if defined(USE_LIGHT) && defined(USE_GAMMA2_TEXTURES) + diffuseAlbedo.rgb *= diffuseAlbedo.rgb; +#endif #if defined(USE_LIGHT) && defined(USE_FAST_LIGHT) - #if defined(USE_LIGHTMAP) - diffuse.rgb *= directedLight; + gl_FragColor = diffuse.rgb; + #if defined(USE_LIGHTMAP) + gl_FragColor *= lightColor; #endif #elif defined(USE_LIGHT) - worldLight = normalize(worldLight); + L = normalize(L); - float surfNL = clamp(dot(surfNormal, worldLight), 0.0, 1.0); + float surfNL = clamp(dot(surfN, L), 0.0, 1.0); + + #if defined(USE_SHADOWMAP) + vec2 shadowTex = gl_FragCoord.xy * r_FBufScale; + float shadowValue = texture2D(u_ShadowMap, shadowTex).r; + + // surfaces not facing the light are always shadowed + shadowValue *= step(0.0, dot(surfN, var_PrimaryLightDirection)); + + #if defined(SHADOWMAP_MODULATE) + //vec3 shadowColor = min(u_PrimaryLightAmbient, lightColor); + vec3 shadowColor = u_PrimaryLightAmbient * lightColor; + + #if 0 + // Only shadow when the world light is parallel to the primary light + shadowValue = 1.0 + (shadowValue - 1.0) * clamp(dot(L, var_PrimaryLightDirection), 0.0, 1.0); + #endif + lightColor = mix(shadowColor, lightColor, shadowValue); + #endif + #endif #if defined(USE_LIGHTMAP) || defined(USE_LIGHT_VERTEX) #if defined(USE_STANDARD_DELUXEMAP) // Standard deluxe mapping treats the light sample as fully directed // and doesn't compensate for light angle attenuation. - vec3 ambientLight = vec3(0.0); + vec3 ambientColor = vec3(0.0); #else // Separate the light sample into directed and ambient parts. // @@ -331,52 +358,72 @@ void main() #endif // Recover any unused light as ambient - vec3 ambientLight = directedLight; - directedLight *= directedScale; - ambientLight -= directedLight * surfNL; + vec3 ambientColor = lightColor; + lightColor *= directedScale; + ambientColor -= lightColor * surfNL; #endif #endif - - float NL = clamp(dot(worldNormal, worldLight), 0.0, 1.0); - float NE = clamp(dot(worldNormal, SampleToView), 0.0, 1.0); - float fzero = u_MaterialInfo.x; + float NL = clamp(dot(N, L), 0.0, 1.0); + float NE = clamp(dot(N, E), 0.0, 1.0); + + float maxReflectance = u_MaterialInfo.x; float shininess = u_MaterialInfo.y; #if defined(USE_SPECULARMAP) - vec4 specular = texture2D(u_SpecularMap, tex); - //specular.rgb = clamp(specular.rgb - diffuse.rgb, 0.0, 1.0); - shininess *= specular.a; + vec4 specularReflectance = texture2D(u_SpecularMap, texCoords); + specularReflectance.rgb *= maxReflectance; + shininess *= specularReflectance.a; + // adjust diffuse by specular reflectance, to maintain energy conservation + diffuseAlbedo.rgb *= vec3(1.0) - specularReflectance.rgb; #endif - float directedDiff = NL * CalcDiffuse(worldNormal, worldLight, SampleToView, NE, NL, fzero, shininess); - diffuse.rgb *= directedLight * directedDiff + ambientDiff * ambientLight; - - #if defined(USE_SPECULARMAP) - vec3 halfAngle = normalize(worldLight + SampleToView); + gl_FragColor.rgb = lightColor * NL * CalcDiffuse(diffuseAlbedo.rgb, N, L, E, NE, NL, shininess); + gl_FragColor.rgb += ambientDiff * ambientColor * diffuseAlbedo.rgb; + #if defined(USE_PRIMARY_LIGHT) + vec3 L2 = var_PrimaryLightDirection; + float NL2 = clamp(dot(N, L2), 0.0, 1.0); - float EH = clamp(dot(SampleToView, halfAngle), 0.0, 1.0); - float NH = clamp(dot(worldNormal, halfAngle), 0.0, 1.0); - - float directedSpec = NL * CalcSpecular(NH, NL, NE, EH, fzero, shininess); - - #if defined(r_normalAmbient) - vec3 ambientHalf = normalize(surfNormal + SampleToView); - float ambientSpec = max(dot(ambientHalf, worldNormal) + 0.5, 0.0); - ambientSpec *= ambientSpec * 0.44; - ambientSpec = pow(ambientSpec, shininess) * fzero; - specular.rgb *= directedSpec * directedLight + ambientSpec * ambientLight; + #if defined(USE_SHADOWMAP) + gl_FragColor.rgb += u_PrimaryLightColor * shadowValue * NL2 * CalcDiffuse(diffuseAlbedo.rgb, N, L2, E, NE, NL2, shininess); #else - specular.rgb *= directedSpec * directedLight; + gl_FragColor.rgb += u_PrimaryLightColor * NL2 * CalcDiffuse(diffuseAlbedo.rgb, N, L2, E, NE, NL2, shininess); #endif #endif + + #if defined(USE_SPECULARMAP) + vec3 H = normalize(L + E); + + float EH = clamp(dot(E, H), 0.0, 1.0); + float NH = clamp(dot(N, H), 0.0, 1.0); + + gl_FragColor.rgb += lightColor * NL * CalcSpecular(specularReflectance.rgb, NH, NL, NE, EH, shininess); + + #if defined(r_normalAmbient) + vec3 ambientHalf = normalize(surfN + E); + float ambientSpec = max(dot(ambientHalf, N) + 0.5, 0.0); + ambientSpec *= ambientSpec * 0.44; + gl_FragColor.rgb += specularReflectance.rgb * ambientSpec * ambientColor; + #endif + + #if defined(USE_PRIMARY_LIGHT) + vec3 H2 = normalize(L2 + E); + float EH2 = clamp(dot(E, H2), 0.0, 1.0); + float NH2 = clamp(dot(N, H2), 0.0, 1.0); + + + #if defined(USE_SHADOWMAP) + gl_FragColor.rgb += u_PrimaryLightColor * shadowValue * NL2 * CalcSpecular(specularReflectance.rgb, NH2, NL2, NE, EH2, shininess); + #else + gl_FragColor.rgb += u_PrimaryLightColor * NL2 * CalcSpecular(specularReflectance.rgb, NH2, NL2, NE, EH2, shininess); + #endif + #endif + #endif +#else + gl_FragColor.rgb = diffuseAlbedo.rgb; #endif - gl_FragColor = diffuse; - -#if defined(USE_SPECULARMAP) && defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) - gl_FragColor.rgb += specular.rgb; -#endif + gl_FragColor.a = diffuseAlbedo.a; gl_FragColor *= var_Color; } diff --git a/code/rend2/glsl/lightall_vp.glsl b/code/renderergl2/glsl/lightall_vp.glsl similarity index 71% rename from code/rend2/glsl/lightall_vp.glsl rename to code/renderergl2/glsl/lightall_vp.glsl index 027f2741..03775caf 100644 --- a/code/rend2/glsl/lightall_vp.glsl +++ b/code/renderergl2/glsl/lightall_vp.glsl @@ -1,5 +1,5 @@ attribute vec4 attr_TexCoord0; -#if defined(USE_LIGHTMAP) +#if defined(USE_LIGHTMAP) || defined(USE_TCGEN) attribute vec4 attr_TexCoord1; #endif attribute vec4 attr_Color; @@ -31,6 +31,8 @@ uniform vec3 u_ViewOrigin; #if defined(USE_TCGEN) uniform int u_TCGen0; +uniform vec3 u_TCGen0Vector0; +uniform vec3 u_TCGen0Vector1; #endif #if defined(USE_TCMOD) @@ -59,6 +61,10 @@ uniform float u_LightRadius; #endif #endif +#if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP) +uniform vec4 u_PrimaryLightOrigin; +#endif + varying vec2 var_DiffuseTex; #if defined(USE_LIGHTMAP) @@ -89,7 +95,34 @@ varying vec3 var_VertLight; #endif #if defined(USE_LIGHT) && !defined(USE_DELUXEMAP) && !defined(USE_FAST_LIGHT) -varying vec3 var_WorldLight; +varying vec3 var_LightDirection; +#endif + +#if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP) +varying vec3 var_PrimaryLightDirection; +#endif + +#if defined(USE_TCGEN) +vec2 GenTexCoords(int TCGen, vec3 position, vec3 normal, vec3 TCGenVector0, vec3 TCGenVector1) +{ + vec2 tex = attr_TexCoord0.st; + + if (TCGen == TCGEN_LIGHTMAP) + { + tex = attr_TexCoord1.st; + } + else if (TCGen == TCGEN_ENVIRONMENT_MAPPED) + { + vec3 viewer = normalize(u_ViewOrigin - position); + tex = -reflect(viewer, normal).yz * vec2(0.5, -0.5) + 0.5; + } + else if (TCGen == TCGEN_VECTOR) + { + tex = vec2(dot(position, TCGenVector0), dot(position, TCGenVector1)); + } + + return tex; +} #endif #if defined(USE_TCMOD) @@ -99,7 +132,7 @@ vec2 ModTexCoords(vec2 st, vec3 position, vec4 texMatrix, vec4 offTurb) float phase = offTurb.w; vec2 st2 = vec2(dot(st, texMatrix.xz), dot(st, texMatrix.yw)) + offTurb.xy; - vec3 offsetPos = position / 1024.0; + vec3 offsetPos = vec3(0); //position / 1024.0; offsetPos.x += offsetPos.z; vec2 texOffset = sin((offsetPos.xy + vec2(phase)) * 2.0 * M_PI); @@ -130,7 +163,7 @@ void main() gl_Position = u_ModelViewProjectionMatrix * position; #if (defined(USE_LIGHTMAP) || defined(USE_LIGHT_VERTEX)) && !defined(USE_DELUXEMAP) && !defined(USE_FAST_LIGHT) - vec3 worldLight = attr_LightDirection; + vec3 L = attr_LightDirection; #endif #if defined(USE_MODELMATRIX) @@ -142,7 +175,7 @@ void main() #endif #if defined(USE_LIGHTMAP) && !defined(USE_DELUXEMAP) && !defined(USE_FAST_LIGHT) - worldLight = (u_ModelMatrix * vec4(worldLight, 0.0)).xyz; + L = (u_ModelMatrix * vec4(L, 0.0)).xyz; #endif #endif @@ -150,28 +183,20 @@ void main() var_Position = position.xyz; #endif -#if defined(USE_TCGEN) || defined(USE_NORMALMAP) || defined(USE_LIGHT) && !defined(USE_FAST_LIGHT) - vec3 SampleToView = u_ViewOrigin - position.xyz; - var_SampleToView = SampleToView; +#if defined(USE_TCGEN) || defined(USE_NORMALMAP) || (defined(USE_LIGHT) && !defined(USE_FAST_LIGHT)) + var_SampleToView = u_ViewOrigin - position.xyz; #endif - vec2 tex; - #if defined(USE_TCGEN) - if (u_TCGen0 == TCGEN_ENVIRONMENT_MAPPED) - { - tex = -reflect(normalize(SampleToView), normal).yz * vec2(0.5, -0.5) + 0.5; - } - else + vec2 texCoords = GenTexCoords(u_TCGen0, position.xyz, normal, u_TCGen0Vector0, u_TCGen0Vector1); +#else + vec2 texCoords = attr_TexCoord0.st; #endif - { - tex = attr_TexCoord0.st; - } #if defined(USE_TCMOD) - var_DiffuseTex = ModTexCoords(tex, position.xyz, u_DiffuseTexMatrix, u_DiffuseTexOffTurb); + var_DiffuseTex = ModTexCoords(texCoords, position.xyz, u_DiffuseTexMatrix, u_DiffuseTexOffTurb); #else - var_DiffuseTex = tex; + var_DiffuseTex = texCoords; #endif #if defined(USE_LIGHTMAP) @@ -188,10 +213,10 @@ void main() #if defined(USE_LIGHT) && !defined(USE_DELUXEMAP) #if defined(USE_LIGHT_VECTOR) - vec3 worldLight = u_LightOrigin.xyz - (position.xyz * u_LightOrigin.w); + vec3 L = u_LightOrigin.xyz - (position.xyz * u_LightOrigin.w); #endif #if !defined(USE_FAST_LIGHT) - var_WorldLight = worldLight; + var_LightDirection = L; #endif #endif @@ -205,12 +230,16 @@ void main() #if defined(USE_LIGHT_VECTOR) && defined(USE_FAST_LIGHT) #if defined(USE_INVSQRLIGHT) - float intensity = 1.0 / dot(worldLight, worldLight); + float intensity = 1.0 / dot(L, L); #else - float intensity = clamp((1.0 - dot(worldLight, worldLight) / (u_LightRadius * u_LightRadius)) * 1.07, 0.0, 1.0); + float intensity = clamp((1.0 - dot(L, L) / (u_LightRadius * u_LightRadius)) * 1.07, 0.0, 1.0); #endif - float NL = clamp(dot(normal, normalize(worldLight)), 0.0, 1.0); + float NL = clamp(dot(normal, normalize(L)), 0.0, 1.0); var_Color.rgb *= u_DirectedLight * intensity * NL + u_AmbientLight; #endif + +#if defined(USE_PRIMARY_LIGHT) || defined(USE_SHADOWMAP) + var_PrimaryLightDirection = u_PrimaryLightOrigin.xyz - (position.xyz * u_PrimaryLightOrigin.w); +#endif } diff --git a/code/rend2/glsl/pshadow_fp.glsl b/code/renderergl2/glsl/pshadow_fp.glsl similarity index 100% rename from code/rend2/glsl/pshadow_fp.glsl rename to code/renderergl2/glsl/pshadow_fp.glsl diff --git a/code/rend2/glsl/pshadow_vp.glsl b/code/renderergl2/glsl/pshadow_vp.glsl similarity index 100% rename from code/rend2/glsl/pshadow_vp.glsl rename to code/renderergl2/glsl/pshadow_vp.glsl diff --git a/code/rend2/glsl/shadowfill_fp.glsl b/code/renderergl2/glsl/shadowfill_fp.glsl similarity index 100% rename from code/rend2/glsl/shadowfill_fp.glsl rename to code/renderergl2/glsl/shadowfill_fp.glsl diff --git a/code/rend2/glsl/shadowfill_vp.glsl b/code/renderergl2/glsl/shadowfill_vp.glsl similarity index 100% rename from code/rend2/glsl/shadowfill_vp.glsl rename to code/renderergl2/glsl/shadowfill_vp.glsl diff --git a/code/rend2/glsl/shadowmask_fp.glsl b/code/renderergl2/glsl/shadowmask_fp.glsl similarity index 99% rename from code/rend2/glsl/shadowmask_fp.glsl rename to code/renderergl2/glsl/shadowmask_fp.glsl index b3a698c8..4bac5ccd 100644 --- a/code/rend2/glsl/shadowmask_fp.glsl +++ b/code/renderergl2/glsl/shadowmask_fp.glsl @@ -86,7 +86,7 @@ void main() vec4 shadowpos = u_ShadowMvp * biasPos; #if defined(USE_SHADOW_CASCADE) - const float fadeTo = 0.5; + const float fadeTo = 1.0; result = fadeTo; #else result = 0.0; diff --git a/code/rend2/glsl/shadowmask_vp.glsl b/code/renderergl2/glsl/shadowmask_vp.glsl similarity index 100% rename from code/rend2/glsl/shadowmask_vp.glsl rename to code/renderergl2/glsl/shadowmask_vp.glsl diff --git a/code/rend2/glsl/ssao_fp.glsl b/code/renderergl2/glsl/ssao_fp.glsl similarity index 100% rename from code/rend2/glsl/ssao_fp.glsl rename to code/renderergl2/glsl/ssao_fp.glsl diff --git a/code/rend2/glsl/ssao_vp.glsl b/code/renderergl2/glsl/ssao_vp.glsl similarity index 100% rename from code/rend2/glsl/ssao_vp.glsl rename to code/renderergl2/glsl/ssao_vp.glsl diff --git a/code/rend2/glsl/texturecolor_fp.glsl b/code/renderergl2/glsl/texturecolor_fp.glsl similarity index 100% rename from code/rend2/glsl/texturecolor_fp.glsl rename to code/renderergl2/glsl/texturecolor_fp.glsl diff --git a/code/rend2/glsl/texturecolor_vp.glsl b/code/renderergl2/glsl/texturecolor_vp.glsl similarity index 100% rename from code/rend2/glsl/texturecolor_vp.glsl rename to code/renderergl2/glsl/texturecolor_vp.glsl diff --git a/code/rend2/glsl/tonemap_fp.glsl b/code/renderergl2/glsl/tonemap_fp.glsl similarity index 100% rename from code/rend2/glsl/tonemap_fp.glsl rename to code/renderergl2/glsl/tonemap_fp.glsl diff --git a/code/rend2/glsl/tonemap_vp.glsl b/code/renderergl2/glsl/tonemap_vp.glsl similarity index 100% rename from code/rend2/glsl/tonemap_vp.glsl rename to code/renderergl2/glsl/tonemap_vp.glsl diff --git a/code/rend2/tr_animation.c b/code/renderergl2/tr_animation.c similarity index 99% rename from code/rend2/tr_animation.c rename to code/renderergl2/tr_animation.c index 794111c6..c4c9debb 100644 --- a/code/rend2/tr_animation.c +++ b/code/renderergl2/tr_animation.c @@ -168,7 +168,6 @@ void RB_SurfaceAnim( md4Surface_t *surface ) { } -#ifdef RAVENMD4 // copied and adapted from tr_mesh.c @@ -655,4 +654,3 @@ void MC_UnCompress(float mat[3][4],const unsigned char * comp) val-=1<<(MC_BITS_VECT-1); mat[2][2]=((float)(val))*MC_SCALE_VECT; } -#endif diff --git a/code/rend2/tr_backend.c b/code/renderergl2/tr_backend.c similarity index 80% rename from code/rend2/tr_backend.c rename to code/renderergl2/tr_backend.c index c3d39433..de05f53b 100644 --- a/code/rend2/tr_backend.c +++ b/code/renderergl2/tr_backend.c @@ -21,7 +21,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "tr_local.h" -backEndData_t *backEndData[SMP_FRAMES]; +backEndData_t *backEndData; backEndState_t backEnd; @@ -53,7 +53,9 @@ void GL_Bind2( image_t *image, GLenum type ) { } if ( glState.currenttextures[glState.currenttmu] != texnum ) { - image->frameUsed = tr.frameCount; + if ( image ) { + image->frameUsed = tr.frameCount; + } glState.currenttextures[glState.currenttmu] = texnum; qglBindTexture (type, texnum); } @@ -149,12 +151,6 @@ void GL_BindToTMU( image_t *image, int tmu ) ** GL_Cull */ void GL_Cull( int cullType ) { -#ifdef REACTION - // Makro - flip culling if needed - qboolean flip = (backEnd.currentEntity != NULL && backEnd.currentEntity->mirrored != qfalse && cullType != CT_TWO_SIDED); - cullType ^= flip; // this assumes CT_BACK_SIDED and CT_FRONT_SIDED are 0 or 1 -#endif - if ( glState.faceCulling == cullType ) { return; } @@ -176,6 +172,11 @@ void GL_Cull( int cullType ) { cullFront = !cullFront; } + if ( backEnd.currentEntity && backEnd.currentEntity->mirrored ) + { + cullFront = !cullFront; + } + qglCullFace( cullFront ? GL_FRONT : GL_BACK ); } } @@ -252,7 +253,7 @@ void GL_State( unsigned long stateBits ) // if ( diff & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) { - GLenum srcFactor, dstFactor; + GLenum srcFactor = GL_ONE, dstFactor = GL_ONE; if ( stateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) { @@ -286,7 +287,6 @@ void GL_State( unsigned long stateBits ) srcFactor = GL_SRC_ALPHA_SATURATE; break; default: - srcFactor = GL_ONE; // to get warning to shut up ri.Error( ERR_DROP, "GL_State: invalid src blend state bits" ); break; } @@ -318,7 +318,6 @@ void GL_State( unsigned long stateBits ) dstFactor = GL_ONE_MINUS_DST_ALPHA; break; default: - dstFactor = GL_ONE; // to get warning to shut up ri.Error( ERR_DROP, "GL_State: invalid dst blend state bits" ); break; } @@ -548,10 +547,6 @@ void RB_BeginDrawingView (void) { // we will only draw a sun if there was sky rendered in this view backEnd.skyRenderedThisView = qfalse; -#ifdef REACTION - backEnd.viewHasSunFlare = qfalse; -#endif - // clip to the plane of the portal if ( backEnd.viewParms.isPortal ) { #if 0 @@ -594,9 +589,7 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { FBO_t* fbo = NULL; qboolean inQuery = qfalse; -#if 1 //def REACTION float depth[2]; -#endif // save original time for entity shader offsets @@ -614,12 +607,9 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { oldDlighted = qfalse; oldPshadowed = qfalse; oldSort = -1; - depthRange = qfalse; -#if 1 //def REACTION depth[0] = 0.f; depth[1] = 1.f; -#endif backEnd.pc.c_surfaces += numDrawSurfs; @@ -639,8 +629,8 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { // change the tess parameters if needed // a "entityMergable" shader is a shader that can have surfaces from seperate // entities merged into a single batch, like smoke and blood puff sprites - if (shader != oldShader || fogNum != oldFogNum || dlighted != oldDlighted || pshadowed != oldPshadowed - || ( entityNum != oldEntityNum && !shader->entityMergable ) ) { + if ( shader != NULL && ( shader != oldShader || fogNum != oldFogNum || dlighted != oldDlighted || pshadowed != oldPshadowed + || ( entityNum != oldEntityNum && !shader->entityMergable ) ) ) { if (oldShader != NULL) { RB_EndSurface(); } @@ -662,22 +652,6 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { qboolean sunflare = qfalse; depthRange = isCrosshair = qfalse; -#ifdef REACTION - // if we were rendering to a FBO and the previous entity was a sunflare - // and the current one isn't, switch back to the main fbo - if (oldEntityNum != -1 && fbo && !backEnd.depthFill && - RF_SUNFLARE == (backEnd.refdef.entities[oldEntityNum].e.renderfx & RF_SUNFLARE) && - 0 == (backEnd.refdef.entities[entityNum].e.renderfx & RF_SUNFLARE)) - { - if (inQuery) { - inQuery = qfalse; - qglEndQueryARB(GL_SAMPLES_PASSED_ARB); - } - FBO_Bind(fbo); - qglDepthRange(depth[0], depth[1]); - } -#endif - if ( entityNum != REFENTITYNUM_WORLD ) { backEnd.currentEntity = &backEnd.refdef.entities[entityNum]; backEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime; @@ -693,31 +667,6 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or ); } -#ifdef REACTION - // if the current entity is a sunflare - if(backEnd.currentEntity->e.renderfx & RF_SUNFLARE && !backEnd.depthFill) { - // if we're rendering to a fbo - if (fbo) { - VectorCopy(backEnd.currentEntity->e.origin, backEnd.sunFlarePos); - // switch FBO - FBO_Bind(tr.godRaysFbo); - - qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); - qglClear( GL_COLOR_BUFFER_BIT ); - - qglDepthRange(1.f, 1.f); - if (glRefConfig.occlusionQuery && !inQuery && !backEnd.viewHasSunFlare) { - inQuery = qtrue; - tr.sunFlareQueryActive[tr.sunFlareQueryIndex] = qtrue; - qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, tr.sunFlareQuery[tr.sunFlareQueryIndex]); - } - sunflare = qtrue; - } else { - depthRange = qtrue; - } - } -#endif - if(backEnd.currentEntity->e.renderfx & RF_DEPTHHACK) { // hack the depth range to prevent view model from poking into walls @@ -766,14 +715,12 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { } } -#if 1 //def REACTION if(!oldDepthRange) { depth[0] = 0; depth[1] = 0.3f; qglDepthRange (depth[0], depth[1]); } -#endif } else { @@ -784,10 +731,9 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { if (!sunflare) qglDepthRange (0, 1); -#if 1 //def REACTION + depth[0] = 0; depth[1] = 1; -#endif } oldDepthRange = depthRange; @@ -809,19 +755,8 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { } if (inQuery) { - inQuery = qfalse; qglEndQueryARB(GL_SAMPLES_PASSED_ARB); } -#ifdef REACTION - // HACK: flip Z and render black to god rays buffer - if (backEnd.frameHasSunFlare && !backEnd.depthFill) - { - vec4_t black; - VectorSet4(black, 0, 0, 0, 1); - qglDepthRange (1, 1); - FBO_BlitFromTexture(tr.whiteImage, NULL, NULL, tr.godRaysFbo, NULL, NULL, black, GLS_DEPTHFUNC_GREATER); - } -#endif if (glRefConfig.framebufferObject) FBO_Bind(fbo); @@ -829,16 +764,15 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) { // go back to the world modelview matrix GL_SetModelviewMatrix( backEnd.viewParms.world.modelMatrix ); - //if ( depthRange ) { - qglDepthRange (0, 1); - //} + + qglDepthRange (0, 1); } /* ============================================================================ -RENDER BACK END THREAD FUNCTIONS +RENDER BACK END FUNCTIONS ============================================================================ */ @@ -907,13 +841,13 @@ Used for cinematics. void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty) { int i, j; int start, end; - shaderProgram_t *sp = &tr.textureColorShader; - vec4_t color; + vec4_t quadVerts[4]; + vec2_t texCoords[4]; if ( !tr.registered ) { return; } - R_SyncRenderThread(); + R_IssuePendingRenderCommands(); // we definately want to sync every frame for the cinematics qglFinish(); @@ -932,24 +866,7 @@ void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte * ri.Error (ERR_DROP, "Draw_StretchRaw: size not a power of 2: %i by %i", cols, rows); } - GL_Bind( tr.scratchImage[client] ); - - // if the scratchImage isn't in the format we want, specify it as a new texture - if ( cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height ) { - tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols; - tr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = rows; - qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); - qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); - } else { - if (dirty) { - // otherwise, just subimage upload it so that drivers can tell we are going to be changing - // it and don't try and do a texture compression - qglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data ); - } - } + RE_UploadCinematic (w, h, cols, rows, data, client, dirty); if ( r_speeds->integer ) { end = ri.Milliseconds(); @@ -971,84 +888,22 @@ void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte * RB_SetGL2D(); - tess.numIndexes = 0; - tess.numVertexes = 0; - tess.firstIndex = 0; - tess.minIndex = 0; - tess.maxIndex = 0; + VectorSet4(quadVerts[0], x, y, 0.0f, 1.0f); + VectorSet4(quadVerts[1], x + w, y, 0.0f, 1.0f); + VectorSet4(quadVerts[2], x + w, y + h, 0.0f, 1.0f); + VectorSet4(quadVerts[3], x, y + h, 0.0f, 1.0f); - tess.xyz[tess.numVertexes][0] = x; - tess.xyz[tess.numVertexes][1] = y; - tess.xyz[tess.numVertexes][2] = 0; - tess.xyz[tess.numVertexes][3] = 1; - tess.texCoords[tess.numVertexes][0][0] = 0.5f / cols; - tess.texCoords[tess.numVertexes][0][1] = 0.5f / rows; - tess.texCoords[tess.numVertexes][1][0] = 0; - tess.texCoords[tess.numVertexes][1][1] = 1; - tess.numVertexes++; + VectorSet2(texCoords[0], 0.5f / cols, 0.5f / rows); + VectorSet2(texCoords[1], (cols - 0.5f) / cols, 0.5f / rows); + VectorSet2(texCoords[2], (cols - 0.5f) / cols, (rows - 0.5f) / rows); + VectorSet2(texCoords[3], 0.5f / cols, (rows - 0.5f) / rows); - tess.xyz[tess.numVertexes][0] = x + w; - tess.xyz[tess.numVertexes][1] = y; - tess.xyz[tess.numVertexes][2] = 0; - tess.xyz[tess.numVertexes][3] = 1; - tess.texCoords[tess.numVertexes][0][0] = (cols - 0.5f) / cols; - tess.texCoords[tess.numVertexes][0][1] = 0.5f / rows; - tess.texCoords[tess.numVertexes][1][0] = 0; - tess.texCoords[tess.numVertexes][1][1] = 1; - tess.numVertexes++; - - tess.xyz[tess.numVertexes][0] = x + w; - tess.xyz[tess.numVertexes][1] = y + h; - tess.xyz[tess.numVertexes][2] = 0; - tess.xyz[tess.numVertexes][3] = 1; - tess.texCoords[tess.numVertexes][0][0] = (cols - 0.5f) / cols; - tess.texCoords[tess.numVertexes][0][1] = (rows - 0.5f) / rows; - tess.texCoords[tess.numVertexes][1][0] = 0; - tess.texCoords[tess.numVertexes][1][1] = 1; - tess.numVertexes++; - - tess.xyz[tess.numVertexes][0] = x; - tess.xyz[tess.numVertexes][1] = y + h; - tess.xyz[tess.numVertexes][2] = 0; - tess.xyz[tess.numVertexes][3] = 1; - tess.texCoords[tess.numVertexes][0][0] = 0.5f / cols; - tess.texCoords[tess.numVertexes][0][1] = (rows - 0.5f) / rows; - tess.texCoords[tess.numVertexes][1][0] = 0; - tess.texCoords[tess.numVertexes][1][1] = 1; - tess.numVertexes++; - - tess.indexes[tess.numIndexes++] = 0; - tess.indexes[tess.numIndexes++] = 1; - tess.indexes[tess.numIndexes++] = 2; - tess.indexes[tess.numIndexes++] = 0; - tess.indexes[tess.numIndexes++] = 2; - tess.indexes[tess.numIndexes++] = 3; - tess.minIndex = 0; - tess.maxIndex = 3; - - // FIXME: A lot of this can probably be removed for speed, and refactored into a more convenient function - RB_UpdateVBOs(ATTR_POSITION | ATTR_TEXCOORD); + GLSL_BindProgram(&tr.textureColorShader); - sp = &tr.textureColorShader; + GLSL_SetUniformMatrix16(&tr.textureColorShader, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); + GLSL_SetUniformVec4(&tr.textureColorShader, UNIFORM_COLOR, colorWhite); - GLSL_VertexAttribsState(ATTR_POSITION | ATTR_TEXCOORD); - - GLSL_BindProgram(sp); - - GLSL_SetUniformMatrix16(sp, TEXTURECOLOR_UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); - VectorSet4(color, 1, 1, 1, 1); - GLSL_SetUniformVec4(sp, TEXTURECOLOR_UNIFORM_COLOR, color); - - R_DrawElementsVBO(tess.numIndexes, tess.firstIndex, tess.minIndex, tess.maxIndex); - - //R_BindNullVBO(); - //R_BindNullIBO(); - - tess.numIndexes = 0; - tess.numVertexes = 0; - tess.firstIndex = 0; - tess.minIndex = 0; - tess.maxIndex = 0; + RB_InstantQuad2(quadVerts, texCoords); } void RE_UploadCinematic (int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty) { @@ -1249,18 +1104,18 @@ const void *RB_DrawSurfs( const void *data ) { FBO_Bind(tr.screenShadowFbo); - box[0] = (backEnd.refdef.x ) * tr.screenShadowFbo->width / (float)glConfig.vidWidth; - box[1] = (backEnd.refdef.y ) * tr.screenShadowFbo->height / (float)glConfig.vidHeight; - box[2] = (backEnd.refdef.width ) * tr.screenShadowFbo->width / (float)glConfig.vidWidth; - box[3] = (backEnd.refdef.height) * tr.screenShadowFbo->height / (float)glConfig.vidHeight; + box[0] = backEnd.viewParms.viewportX * tr.screenShadowFbo->width / (float)glConfig.vidWidth; + box[1] = backEnd.viewParms.viewportY * tr.screenShadowFbo->height / (float)glConfig.vidHeight; + box[2] = backEnd.viewParms.viewportWidth * tr.screenShadowFbo->width / (float)glConfig.vidWidth; + box[3] = backEnd.viewParms.viewportHeight * tr.screenShadowFbo->height / (float)glConfig.vidHeight; qglViewport(box[0], box[1], box[2], box[3]); qglScissor(box[0], box[1], box[2], box[3]); - box[0] = (backEnd.refdef.x ) / (float)glConfig.vidWidth; - box[1] = (backEnd.refdef.y ) / (float)glConfig.vidHeight; - box[2] = (backEnd.refdef.x + backEnd.refdef.width ) / (float)glConfig.vidWidth; - box[3] = (backEnd.refdef.y + backEnd.refdef.height) / (float)glConfig.vidHeight; + box[0] = backEnd.viewParms.viewportX / (float)glConfig.vidWidth; + box[1] = backEnd.viewParms.viewportY / (float)glConfig.vidHeight; + box[2] = box[0] + backEnd.viewParms.viewportWidth / (float)glConfig.vidWidth; + box[3] = box[1] + backEnd.viewParms.viewportHeight / (float)glConfig.vidHeight; texCoords[0][0] = box[0]; texCoords[0][1] = box[3]; texCoords[1][0] = box[2]; texCoords[1][1] = box[3]; @@ -1286,11 +1141,11 @@ const void *RB_DrawSurfs( const void *data ) { GL_BindToTMU(tr.sunShadowDepthImage[1], TB_SHADOWMAP2); GL_BindToTMU(tr.sunShadowDepthImage[2], TB_SHADOWMAP3); - GLSL_SetUniformMatrix16(&tr.shadowmaskShader, SHADOWMASK_UNIFORM_SHADOWMVP, backEnd.refdef.sunShadowMvp[0]); - GLSL_SetUniformMatrix16(&tr.shadowmaskShader, SHADOWMASK_UNIFORM_SHADOWMVP2, backEnd.refdef.sunShadowMvp[1]); - GLSL_SetUniformMatrix16(&tr.shadowmaskShader, SHADOWMASK_UNIFORM_SHADOWMVP3, backEnd.refdef.sunShadowMvp[2]); + GLSL_SetUniformMatrix16(&tr.shadowmaskShader, UNIFORM_SHADOWMVP, backEnd.refdef.sunShadowMvp[0]); + GLSL_SetUniformMatrix16(&tr.shadowmaskShader, UNIFORM_SHADOWMVP2, backEnd.refdef.sunShadowMvp[1]); + GLSL_SetUniformMatrix16(&tr.shadowmaskShader, UNIFORM_SHADOWMVP3, backEnd.refdef.sunShadowMvp[2]); - GLSL_SetUniformVec3(&tr.shadowmaskShader, SHADOWMASK_UNIFORM_VIEWORIGIN, backEnd.refdef.vieworg); + GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWORIGIN, backEnd.refdef.vieworg); { vec4_t viewInfo; vec3_t viewVector; @@ -1302,15 +1157,15 @@ const void *RB_DrawSurfs( const void *data ) { float zmin = r_znear->value; VectorScale(backEnd.refdef.viewaxis[0], zmax, viewVector); - GLSL_SetUniformVec3(&tr.shadowmaskShader, SHADOWMASK_UNIFORM_VIEWFORWARD, viewVector); + GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWFORWARD, viewVector); VectorScale(backEnd.refdef.viewaxis[1], xmax, viewVector); - GLSL_SetUniformVec3(&tr.shadowmaskShader, SHADOWMASK_UNIFORM_VIEWLEFT, viewVector); + GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWLEFT, viewVector); VectorScale(backEnd.refdef.viewaxis[2], ymax, viewVector); - GLSL_SetUniformVec3(&tr.shadowmaskShader, SHADOWMASK_UNIFORM_VIEWUP, viewVector); + GLSL_SetUniformVec3(&tr.shadowmaskShader, UNIFORM_VIEWUP, viewVector); VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0); - GLSL_SetUniformVec4(&tr.shadowmaskShader, SHADOWMASK_UNIFORM_VIEWINFO, viewInfo); + GLSL_SetUniformVec4(&tr.shadowmaskShader, UNIFORM_VIEWINFO, viewInfo); } @@ -1351,7 +1206,7 @@ const void *RB_DrawSurfs( const void *data ) { VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0); - GLSL_SetUniformVec4(&tr.ssaoShader, SSAO_UNIFORM_VIEWINFO, viewInfo); + GLSL_SetUniformVec4(&tr.ssaoShader, UNIFORM_VIEWINFO, viewInfo); } RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes); @@ -1375,7 +1230,7 @@ const void *RB_DrawSurfs( const void *data ) { VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0); - GLSL_SetUniformVec4(&tr.depthBlurShader[0], DEPTHBLUR_UNIFORM_VIEWINFO, viewInfo); + GLSL_SetUniformVec4(&tr.depthBlurShader[0], UNIFORM_VIEWINFO, viewInfo); } RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes); @@ -1399,7 +1254,7 @@ const void *RB_DrawSurfs( const void *data ) { VectorSet4(viewInfo, zmax / zmin, zmax, 0.0, 0.0); - GLSL_SetUniformVec4(&tr.depthBlurShader[1], DEPTHBLUR_UNIFORM_VIEWINFO, viewInfo); + GLSL_SetUniformVec4(&tr.depthBlurShader[1], UNIFORM_VIEWINFO, viewInfo); } @@ -1420,9 +1275,35 @@ const void *RB_DrawSurfs( const void *data ) { { RB_RenderDrawSurfList( cmd->drawSurfs, cmd->numDrawSurfs ); -#if 0 - RB_DrawSun(); -#endif + if (r_drawSun->integer) + { + RB_DrawSun(0.1, tr.sunShader); + } + + if (r_drawSunRays->integer) + { + FBO_t *oldFbo = glState.currentFBO; + FBO_Bind(tr.sunRaysFbo); + + qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); + qglClear( GL_COLOR_BUFFER_BIT ); + + if (glRefConfig.occlusionQuery) + { + tr.sunFlareQueryActive[tr.sunFlareQueryIndex] = qtrue; + qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, tr.sunFlareQuery[tr.sunFlareQueryIndex]); + } + + RB_DrawSun(0.3, tr.sunFlareShader); + + if (glRefConfig.occlusionQuery) + { + qglEndQueryARB(GL_SAMPLES_PASSED_ARB); + } + + FBO_Bind(oldFbo); + } + // darken down any stencil shadows RB_ShadowFinish(); @@ -1448,6 +1329,10 @@ const void *RB_DrawBuffer( const void *data ) { cmd = (const drawBufferCommand_t *)data; + // finish any 2D drawing if needed + if(tess.numIndexes) + RB_EndSurface(); + if (glRefConfig.framebufferObject) FBO_Bind(NULL); @@ -1531,6 +1416,10 @@ const void *RB_ColorMask(const void *data) { const colorMaskCommand_t *cmd = data; + // finish any 2D drawing if needed + if(tess.numIndexes) + RB_EndSurface(); + if (glRefConfig.framebufferObject) { // reverse color mask, so 0 0 0 0 is the default @@ -1555,6 +1444,7 @@ const void *RB_ClearDepth(const void *data) { const clearDepthCommand_t *cmd = data; + // finish any 2D drawing if needed if(tess.numIndexes) RB_EndSurface(); @@ -1587,6 +1477,7 @@ const void *RB_ClearDepth(const void *data) return (const void *)(cmd + 1); } + /* ============= RB_SwapBuffers @@ -1672,9 +1563,6 @@ const void *RB_SwapBuffers( const void *data ) { backEnd.framePostProcessed = qfalse; backEnd.projection2D = qfalse; -#ifdef REACTION - backEnd.frameHasSunFlare = qfalse; -#endif return (const void *)(cmd + 1); } @@ -1689,6 +1577,10 @@ const void *RB_CapShadowMap(const void *data) { const capShadowmapCommand_t *cmd = data; + // finish any 2D drawing if needed + if(tess.numIndexes) + RB_EndSurface(); + if (cmd->map != -1) { GL_SelectTexture(0); @@ -1708,7 +1600,6 @@ const void *RB_CapShadowMap(const void *data) } - /* ============= RB_PostProcess @@ -1719,37 +1610,64 @@ const void *RB_PostProcess(const void *data) { const postProcessCommand_t *cmd = data; FBO_t *srcFbo; + vec4i_t srcBox, dstBox; qboolean autoExposure; + // finish any 2D drawing if needed + if(tess.numIndexes) + RB_EndSurface(); + if (!glRefConfig.framebufferObject || !r_postProcess->integer) { // do nothing return (const void *)(cmd + 1); } + if (cmd) + { + backEnd.refdef = cmd->refdef; + backEnd.viewParms = cmd->viewParms; + } + srcFbo = tr.renderFbo; if (tr.msaaResolveFbo) { // Resolve the MSAA before anything else + // Can't resolve just part of the MSAA FBO, so multiple views will suffer a performance hit here FBO_FastBlit(tr.renderFbo, NULL, tr.msaaResolveFbo, NULL, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST); srcFbo = tr.msaaResolveFbo; } + dstBox[0] = backEnd.viewParms.viewportX; + dstBox[1] = backEnd.viewParms.viewportY; + dstBox[2] = backEnd.viewParms.viewportWidth; + dstBox[3] = backEnd.viewParms.viewportHeight; + if (r_ssao->integer) { - FBO_BlitFromTexture(tr.screenSsaoImage, NULL, NULL, srcFbo, NULL, NULL, NULL, GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO); + srcBox[0] = backEnd.viewParms.viewportX * tr.screenSsaoImage->width / (float)glConfig.vidWidth; + srcBox[1] = backEnd.viewParms.viewportY * tr.screenSsaoImage->height / (float)glConfig.vidHeight; + srcBox[2] = backEnd.viewParms.viewportWidth * tr.screenSsaoImage->width / (float)glConfig.vidWidth; + srcBox[3] = backEnd.viewParms.viewportHeight * tr.screenSsaoImage->height / (float)glConfig.vidHeight; + + FBO_BlitFromTexture(tr.screenSsaoImage, srcBox, NULL, srcFbo, dstBox, NULL, NULL, GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO); } + srcBox[0] = backEnd.viewParms.viewportX; + srcBox[1] = backEnd.viewParms.viewportY; + srcBox[2] = backEnd.viewParms.viewportWidth; + srcBox[3] = backEnd.viewParms.viewportHeight; + if (srcFbo) { if (r_hdr->integer && (r_toneMap->integer || r_forceToneMap->integer)) { autoExposure = r_autoExposure->integer || r_forceAutoExposure->integer; - RB_ToneMap(srcFbo, autoExposure); + RB_ToneMap(srcFbo, srcBox, tr.screenScratchFbo, dstBox, autoExposure); } else if (r_cameraExposure->value == 0.0f) { - FBO_FastBlit(srcFbo, NULL, tr.screenScratchFbo, NULL, GL_COLOR_BUFFER_BIT, GL_NEAREST); + FBO_FastBlit(srcFbo, srcBox, tr.screenScratchFbo, dstBox, GL_COLOR_BUFFER_BIT, GL_NEAREST); } else { @@ -1760,21 +1678,17 @@ const void *RB_PostProcess(const void *data) color[2] = pow(2, r_cameraExposure->value); //exp2(r_cameraExposure->value); color[3] = 1.0f; - FBO_Blit(srcFbo, NULL, NULL, tr.screenScratchFbo, NULL, NULL, color, 0); + FBO_Blit(srcFbo, NULL, NULL, tr.screenScratchFbo, dstBox, NULL, color, 0); } } -#ifdef REACTION - if (1) - { - RB_GodRays(); + if (r_drawSunRays->integer) + RB_SunRays(tr.screenScratchFbo, srcBox, tr.screenScratchFbo, dstBox); - if (1) - RB_BokehBlur(backEnd.refdef.blurFactor); - else - RB_GaussianBlur(backEnd.refdef.blurFactor); - } -#endif + if (1) + RB_BokehBlur(tr.screenScratchFbo, srcBox, tr.screenScratchFbo, dstBox, backEnd.refdef.blurFactor); + else + RB_GaussianBlur(backEnd.refdef.blurFactor); if (0) { @@ -1800,7 +1714,7 @@ const void *RB_PostProcess(const void *data) { vec4i_t dstBox; VectorSet4(dstBox, 256, glConfig.vidHeight - 256, 256, 256); - FBO_BlitFromTexture(tr.renderImage, NULL, NULL, tr.screenScratchFbo, dstBox, NULL, NULL, 0); + FBO_BlitFromTexture(tr.sunRaysImage, NULL, NULL, tr.screenScratchFbo, dstBox, NULL, NULL, 0); } backEnd.framePostProcessed = qtrue; @@ -1808,12 +1722,10 @@ const void *RB_PostProcess(const void *data) return (const void *)(cmd + 1); } + /* ==================== RB_ExecuteRenderCommands - -This function will be called synchronously if running without -smp extensions, or asynchronously by another thread. ==================== */ void RB_ExecuteRenderCommands( const void *data ) { @@ -1821,12 +1733,6 @@ void RB_ExecuteRenderCommands( const void *data ) { t1 = ri.Milliseconds (); - if ( !r_smp->integer || data == backEndData[0]->commands.cmds ) { - backEnd.smpFrame = 0; - } else { - backEnd.smpFrame = 1; - } - while ( 1 ) { data = PADP(data, sizeof(void *)); @@ -1866,7 +1772,11 @@ void RB_ExecuteRenderCommands( const void *data ) { break; case RC_END_OF_LIST: default: - // stop rendering on this thread + // finish any 2D drawing if needed + if(tess.numIndexes) + RB_EndSurface(); + + // stop rendering t2 = ri.Milliseconds (); backEnd.pc.msec = t2 - t1; return; @@ -1874,31 +1784,3 @@ void RB_ExecuteRenderCommands( const void *data ) { } } - - -/* -================ -RB_RenderThread -================ -*/ -void RB_RenderThread( void ) { - const void *data; - - // wait for either a rendering command or a quit command - while ( 1 ) { - // sleep until we have work to do - data = GLimp_RendererSleep(); - - if ( !data ) { - return; // all done, renderer is shutting down - } - - renderThreadActive = qtrue; - - RB_ExecuteRenderCommands( data ); - - renderThreadActive = qfalse; - } -} - - diff --git a/code/rend2/tr_bsp.c b/code/renderergl2/tr_bsp.c similarity index 93% rename from code/rend2/tr_bsp.c rename to code/renderergl2/tr_bsp.c index 08e66c85..05b933e8 100644 --- a/code/rend2/tr_bsp.c +++ b/code/renderergl2/tr_bsp.c @@ -218,7 +218,7 @@ static void R_LoadLightmaps( lump_t *l, lump_t *surfs ) { buf = fileBase + l->fileofs; // we are about to upload textures - R_SyncRenderThread(); + R_IssuePendingRenderCommands(); tr.lightmapSize = DEFAULT_LIGHTMAP_SIZE; numLightmaps = len / (tr.lightmapSize * tr.lightmapSize * 3); @@ -350,7 +350,7 @@ static void R_LoadLightmaps( lump_t *l, lump_t *surfs ) { } if (!size) - ri.Error(ERR_DROP, "Bad header for %s!\n", filename); + ri.Error(ERR_DROP, "Bad header for %s!", filename); size -= 2; p += 2; @@ -368,10 +368,10 @@ static void R_LoadLightmaps( lump_t *l, lump_t *surfs ) { #if 0 // HDRFILE_RGBE if (size != tr.lightmapSize * tr.lightmapSize * 4) - ri.Error(ERR_DROP, "Bad size for %s (%i)!\n", filename, size); + ri.Error(ERR_DROP, "Bad size for %s (%i)!", filename, size); #else // HDRFILE_FLOAT if (size != tr.lightmapSize * tr.lightmapSize * 12) - ri.Error(ERR_DROP, "Bad size for %s (%i)!\n", filename, size); + ri.Error(ERR_DROP, "Bad size for %s (%i)!", filename, size); #endif } else @@ -524,11 +524,13 @@ static float FatPackU(float input, int lightmapnum) if (tr.worldDeluxeMapping) lightmapnum >>= 1; - lightmapnum %= (tr.fatLightmapStep * tr.fatLightmapStep); - if(tr.fatLightmapSize > 0) { - int x = lightmapnum % tr.fatLightmapStep; + int x; + + lightmapnum %= (tr.fatLightmapStep * tr.fatLightmapStep); + + x = lightmapnum % tr.fatLightmapStep; return (input / ((float)tr.fatLightmapStep)) + ((1.0 / ((float)tr.fatLightmapStep)) * (float)x); } @@ -544,11 +546,13 @@ static float FatPackV(float input, int lightmapnum) if (tr.worldDeluxeMapping) lightmapnum >>= 1; - lightmapnum %= (tr.fatLightmapStep * tr.fatLightmapStep); - if(tr.fatLightmapSize > 0) { - int y = lightmapnum / tr.fatLightmapStep; + int y; + + lightmapnum %= (tr.fatLightmapStep * tr.fatLightmapStep); + + y = lightmapnum / tr.fatLightmapStep; return (input / ((float)tr.fatLightmapStep)) + ((1.0 / ((float)tr.fatLightmapStep)) * (float)y); } @@ -789,7 +793,7 @@ static void ParseFace( dsurface_t *ds, drawVert_t *verts, float *hdrVertColors, surf->data = (surfaceType_t *)cv; #ifdef USE_VERT_TANGENT_SPACE - // Tr3B - calc tangent spaces + // Calculate tangent spaces { srfVert_t *dv[3]; @@ -1022,7 +1026,7 @@ static void ParseTriSurf( dsurface_t *ds, drawVert_t *verts, float *hdrVertColor } #ifdef USE_VERT_TANGENT_SPACE - // Tr3B - calc tangent spaces + // Calculate tangent spaces { srfVert_t *dv[3]; @@ -2123,8 +2127,6 @@ static void R_CreateWorldVBO(void) } - startTime = ri.Milliseconds(); - ri.Free(surfacesSorted); ri.Hunk_FreeTempMemory(triangles); @@ -2151,7 +2153,6 @@ static void R_LoadSurfaces( lump_t *surfs, lump_t *verts, lump_t *indexLump ) { numTriSurfs = 0; numFlares = 0; - in = (void *)(fileBase + surfs->fileofs); if (surfs->filelen % sizeof(*in)) ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name); count = surfs->filelen / sizeof(*in); @@ -2187,7 +2188,7 @@ static void R_LoadSurfaces( lump_t *surfs, lump_t *verts, lump_t *indexLump ) { { //ri.Printf(PRINT_ALL, "Found!\n"); if (size != sizeof(float) * 3 * (verts->filelen / sizeof(*dv))) - ri.Error(ERR_DROP, "Bad size for %s (%i, expected %i)!\n", filename, size, (int)((sizeof(float)) * 3 * (verts->filelen / sizeof(*dv)))); + ri.Error(ERR_DROP, "Bad size for %s (%i, expected %i)!", filename, size, (int)((sizeof(float)) * 3 * (verts->filelen / sizeof(*dv)))); } } @@ -2316,7 +2317,7 @@ static void R_LoadSubmodels( lump_t *l ) { if(i == 0) { - // Tr3B: add this for limiting VBO surface creation + // Add this for limiting VBO surface creation s_worldData.numWorldSurfaces = out->numSurfaces; } } @@ -2688,7 +2689,7 @@ void R_LoadLightGrid( lump_t *l ) { if (size != sizeof(float) * 6 * numGridPoints) { - ri.Error(ERR_DROP, "Bad size for %s (%i, expected %i)!\n", filename, size, (int)(sizeof(float)) * 6 * numGridPoints); + ri.Error(ERR_DROP, "Bad size for %s (%i, expected %i)!", filename, size, (int)(sizeof(float)) * 6 * numGridPoints); } w->hdrLightGrid = ri.Hunk_Alloc(size, h_low); @@ -3185,7 +3186,7 @@ void R_MergeLeafSurfaces(void) } // finish up the ibo - R_SyncRenderThread(); + R_IssuePendingRenderCommands(); qglGenBuffersARB(1, &ibo->indexesVBO); @@ -3276,11 +3277,12 @@ void RE_LoadWorldMap( const char *name ) { byte *startMarker; if ( tr.worldMapLoaded ) { - ri.Error( ERR_DROP, "ERROR: attempted to redundantly load world map\n" ); + ri.Error( ERR_DROP, "ERROR: attempted to redundantly load world map" ); } // set default map light scale - tr.mapLightScale = 1.0f; + tr.mapLightScale = 1.0f; + tr.sunShadowScale = 0.5f; // set default sun direction to be used if it isn't // overridden by a shader @@ -3350,6 +3352,193 @@ void RE_LoadWorldMap( const char *name ) { // determine vertex light directions R_CalcVertexLightDirs(); + // determine which parts of the map are in sunlight + if (0) + { + world_t *w; + + w = &s_worldData; + uint8_t *primaryLightGrid, *data; + int lightGridSize; + int i; + + lightGridSize = w->lightGridBounds[0] * w->lightGridBounds[1] * w->lightGridBounds[2]; + primaryLightGrid = ri.Malloc(lightGridSize * sizeof(*primaryLightGrid)); + + memset(primaryLightGrid, 0, lightGridSize * sizeof(*primaryLightGrid)); + + data = w->lightGridData; + for (i = 0; i < lightGridSize; i++, data += 8) + { + int lat, lng; + vec3_t gridLightDir, gridLightCol; + + // skip samples in wall + if (!(data[0]+data[1]+data[2]+data[3]+data[4]+data[5]) ) + continue; + + gridLightCol[0] = ByteToFloat(data[3]); + gridLightCol[1] = ByteToFloat(data[4]); + gridLightCol[2] = ByteToFloat(data[5]); + (void)gridLightCol; // Suppress unused-but-set-variable warning + + lat = data[7]; + lng = data[6]; + lat *= (FUNCTABLE_SIZE/256); + lng *= (FUNCTABLE_SIZE/256); + + // decode X as cos( lat ) * sin( long ) + // decode Y as sin( lat ) * sin( long ) + // decode Z as cos( long ) + + gridLightDir[0] = tr.sinTable[(lat+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK] * tr.sinTable[lng]; + gridLightDir[1] = tr.sinTable[lat] * tr.sinTable[lng]; + gridLightDir[2] = tr.sinTable[(lng+(FUNCTABLE_SIZE/4))&FUNCTABLE_MASK]; + + // FIXME: magic number for determining if light direction is close enough to sunlight + if (DotProduct(gridLightDir, tr.sunDirection) > 0.75f) + { + primaryLightGrid[i] = 1; + } + else + { + primaryLightGrid[i] = 255; + } + } + + if (0) + { + int i; + byte *buffer = ri.Malloc(w->lightGridBounds[0] * w->lightGridBounds[1] * 3 + 18); + byte *out; + uint8_t *in; + char fileName[MAX_QPATH]; + + Com_Memset (buffer, 0, 18); + buffer[2] = 2; // uncompressed type + buffer[12] = w->lightGridBounds[0] & 255; + buffer[13] = w->lightGridBounds[0] >> 8; + buffer[14] = w->lightGridBounds[1] & 255; + buffer[15] = w->lightGridBounds[1] >> 8; + buffer[16] = 24; // pixel size + + in = primaryLightGrid; + for (i = 0; i < w->lightGridBounds[2]; i++) + { + int j; + + sprintf(fileName, "primarylg%d.tga", i); + + out = buffer + 18; + for (j = 0; j < w->lightGridBounds[0] * w->lightGridBounds[1]; j++) + { + if (*in == 1) + { + *out++ = 255; + *out++ = 255; + *out++ = 255; + } + else if (*in == 255) + { + *out++ = 64; + *out++ = 64; + *out++ = 64; + } + else + { + *out++ = 0; + *out++ = 0; + *out++ = 0; + } + in++; + } + + ri.FS_WriteFile(fileName, buffer, w->lightGridBounds[0] * w->lightGridBounds[1] * 3 + 18); + } + + ri.Free(buffer); + } + + for (i = 0; i < w->numWorldSurfaces; i++) + { + msurface_t *surf = w->surfaces + i; + cullinfo_t *ci = &surf->cullinfo; + + if(ci->type & CULLINFO_PLANE) + { + if (DotProduct(ci->plane.normal, tr.sunDirection) <= 0.0f) + { + //ri.Printf(PRINT_ALL, "surface %d is not oriented towards sunlight\n", i); + continue; + } + } + + if(ci->type & CULLINFO_BOX) + { + int ibounds[2][3], x, y, z, goodSamples, numSamples; + vec3_t lightOrigin; + + VectorSubtract( ci->bounds[0], w->lightGridOrigin, lightOrigin ); + + ibounds[0][0] = floor(lightOrigin[0] * w->lightGridInverseSize[0]); + ibounds[0][1] = floor(lightOrigin[1] * w->lightGridInverseSize[1]); + ibounds[0][2] = floor(lightOrigin[2] * w->lightGridInverseSize[2]); + + VectorSubtract( ci->bounds[1], w->lightGridOrigin, lightOrigin ); + + ibounds[1][0] = ceil(lightOrigin[0] * w->lightGridInverseSize[0]); + ibounds[1][1] = ceil(lightOrigin[1] * w->lightGridInverseSize[1]); + ibounds[1][2] = ceil(lightOrigin[2] * w->lightGridInverseSize[2]); + + ibounds[0][0] = CLAMP(ibounds[0][0], 0, w->lightGridSize[0]); + ibounds[0][1] = CLAMP(ibounds[0][1], 0, w->lightGridSize[1]); + ibounds[0][2] = CLAMP(ibounds[0][2], 0, w->lightGridSize[2]); + + ibounds[1][0] = CLAMP(ibounds[1][0], 0, w->lightGridSize[0]); + ibounds[1][1] = CLAMP(ibounds[1][1], 0, w->lightGridSize[1]); + ibounds[1][2] = CLAMP(ibounds[1][2], 0, w->lightGridSize[2]); + + /* + ri.Printf(PRINT_ALL, "surf %d bounds (%f %f %f)-(%f %f %f) ibounds (%d %d %d)-(%d %d %d)\n", i, + ci->bounds[0][0], ci->bounds[0][1], ci->bounds[0][2], + ci->bounds[1][0], ci->bounds[1][1], ci->bounds[1][2], + ibounds[0][0], ibounds[0][1], ibounds[0][2], + ibounds[1][0], ibounds[1][1], ibounds[1][2]); + */ + + goodSamples = 0; + numSamples = 0; + for (x = ibounds[0][0]; x <= ibounds[1][0]; x++) + { + for (y = ibounds[0][1]; y <= ibounds[1][1]; y++) + { + for (z = ibounds[0][2]; z <= ibounds[1][2]; z++) + { + uint8_t primaryLight = primaryLightGrid[x * 8 + y * 8 * w->lightGridBounds[0] + z * 8 * w->lightGridBounds[0] * w->lightGridBounds[2]]; + + if (primaryLight == 0) + continue; + + numSamples++; + + if (primaryLight == 1) + goodSamples++; + } + } + } + + // FIXME: magic number for determining whether object is mostly in sunlight + if (goodSamples > numSamples * 0.75f) + { + //ri.Printf(PRINT_ALL, "surface %d is in sunlight\n", i); + //surf->primaryLight = 1; + } + } + } + + ri.Free(primaryLightGrid); + } + // create static VBOS from the world R_CreateWorldVBO(); if (r_mergeLeafSurfaces->integer) diff --git a/code/rend2/tr_cmds.c b/code/renderergl2/tr_cmds.c similarity index 86% rename from code/rend2/tr_cmds.c rename to code/renderergl2/tr_cmds.c index 2f67d221..1426b581 100644 --- a/code/rend2/tr_cmds.c +++ b/code/renderergl2/tr_cmds.c @@ -21,11 +21,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "tr_local.h" -volatile renderCommandList_t *renderCommandList; - -volatile qboolean renderThreadActive; - - /* ===================== R_PerformanceCounters @@ -82,49 +77,15 @@ void R_PerformanceCounters( void ) { } -/* -==================== -R_InitCommandBuffers -==================== -*/ -void R_InitCommandBuffers( void ) { - glConfig.smpActive = qfalse; - if ( r_smp->integer ) { - ri.Printf( PRINT_ALL, "Trying SMP acceleration...\n" ); - if ( GLimp_SpawnRenderThread( RB_RenderThread ) ) { - ri.Printf( PRINT_ALL, "...succeeded.\n" ); - glConfig.smpActive = qtrue; - } else { - ri.Printf( PRINT_ALL, "...failed.\n" ); - } - } -} - -/* -==================== -R_ShutdownCommandBuffers -==================== -*/ -void R_ShutdownCommandBuffers( void ) { - // kill the rendering thread - if ( glConfig.smpActive ) { - GLimp_WakeRenderer( NULL ); - glConfig.smpActive = qfalse; - } -} - /* ==================== R_IssueRenderCommands ==================== */ -int c_blockedOnRender; -int c_blockedOnMain; - void R_IssueRenderCommands( qboolean runPerformanceCounters ) { renderCommandList_t *cmdList; - cmdList = &backEndData[tr.smpFrame]->commands; + cmdList = &backEndData->commands; assert(cmdList); // add an end-of-list command *(int *)(cmdList->cmds + cmdList->used) = RC_END_OF_LIST; @@ -132,26 +93,6 @@ void R_IssueRenderCommands( qboolean runPerformanceCounters ) { // clear it out, in case this is a sync and not a buffer flip cmdList->used = 0; - if ( glConfig.smpActive ) { - // if the render thread is not idle, wait for it - if ( renderThreadActive ) { - c_blockedOnRender++; - if ( r_showSmp->integer ) { - ri.Printf( PRINT_ALL, "R" ); - } - } else { - c_blockedOnMain++; - if ( r_showSmp->integer ) { - ri.Printf( PRINT_ALL, "." ); - } - } - - // sleep until the renderer has completed - GLimp_FrontEndSleep(); - } - - // at this point, the back end thread is idle, so it is ok - // to look at its performance counters if ( runPerformanceCounters ) { R_PerformanceCounters(); } @@ -159,49 +100,36 @@ void R_IssueRenderCommands( qboolean runPerformanceCounters ) { // actually start the commands going if ( !r_skipBackEnd->integer ) { // let it start on the new batch - if ( !glConfig.smpActive ) { - RB_ExecuteRenderCommands( cmdList->cmds ); - } else { - GLimp_WakeRenderer( cmdList ); - } + RB_ExecuteRenderCommands( cmdList->cmds ); } } /* ==================== -R_SyncRenderThread +R_IssuePendingRenderCommands Issue any pending commands and wait for them to complete. -After exiting, the render thread will have completed its work -and will remain idle and the main thread is free to issue -OpenGL calls until R_IssueRenderCommands is called. ==================== */ -void R_SyncRenderThread( void ) { +void R_IssuePendingRenderCommands( void ) { if ( !tr.registered ) { return; } R_IssueRenderCommands( qfalse ); - - if ( !glConfig.smpActive ) { - return; - } - GLimp_FrontEndSleep(); } /* ============ R_GetCommandBuffer -make sure there is enough command space, waiting on the -render thread if needed. +make sure there is enough command space ============ */ void *R_GetCommandBuffer( int bytes ) { renderCommandList_t *cmdList; - cmdList = &backEndData[tr.smpFrame]->commands; + cmdList = &backEndData->commands; bytes = PAD(bytes, sizeof(void *)); // always leave room for the end of list command @@ -423,7 +351,7 @@ void RE_BeginFrame( stereoFrame_t stereoFrame ) { } else { - R_SyncRenderThread(); + R_IssuePendingRenderCommands(); qglEnable( GL_STENCIL_TEST ); qglStencilMask( ~0U ); qglClearStencil( 0U ); @@ -436,7 +364,7 @@ void RE_BeginFrame( stereoFrame_t stereoFrame ) { { // this is only reached if it was on and is now off if ( r_measureOverdraw->modified ) { - R_SyncRenderThread(); + R_IssuePendingRenderCommands(); qglDisable( GL_STENCIL_TEST ); } r_measureOverdraw->modified = qfalse; @@ -446,7 +374,7 @@ void RE_BeginFrame( stereoFrame_t stereoFrame ) { // texturemode stuff // if ( r_textureMode->modified ) { - R_SyncRenderThread(); + R_IssuePendingRenderCommands(); GL_TextureMode( r_textureMode->string ); r_textureMode->modified = qfalse; } @@ -457,7 +385,7 @@ void RE_BeginFrame( stereoFrame_t stereoFrame ) { if ( r_gamma->modified ) { r_gamma->modified = qfalse; - R_SyncRenderThread(); + R_IssuePendingRenderCommands(); R_SetColorMappings(); } @@ -466,7 +394,7 @@ void RE_BeginFrame( stereoFrame_t stereoFrame ) { { int err; - R_SyncRenderThread(); + R_IssuePendingRenderCommands(); if ((err = qglGetError()) != GL_NO_ERROR) ri.Error(ERR_FATAL, "RE_BeginFrame() - glGetError() failed (0x%x)!", err); } @@ -612,9 +540,7 @@ void RE_EndFrame( int *frontEndMsec, int *backEndMsec ) { R_IssueRenderCommands( qtrue ); - // use the other buffers next frame, because another CPU - // may still be rendering into the current ones - R_ToggleSmpFrame(); + R_InitNextFrame(); if ( frontEndMsec ) { *frontEndMsec = tr.frontEndMsec; diff --git a/code/rend2/tr_curve.c b/code/renderergl2/tr_curve.c similarity index 100% rename from code/rend2/tr_curve.c rename to code/renderergl2/tr_curve.c diff --git a/code/rend2/tr_extensions.c b/code/renderergl2/tr_extensions.c similarity index 100% rename from code/rend2/tr_extensions.c rename to code/renderergl2/tr_extensions.c diff --git a/code/rend2/tr_extramath.c b/code/renderergl2/tr_extramath.c similarity index 100% rename from code/rend2/tr_extramath.c rename to code/renderergl2/tr_extramath.c diff --git a/code/rend2/tr_extramath.h b/code/renderergl2/tr_extramath.h similarity index 98% rename from code/rend2/tr_extramath.h rename to code/renderergl2/tr_extramath.h index 17d4c7a8..3e11bb48 100644 --- a/code/rend2/tr_extramath.h +++ b/code/renderergl2/tr_extramath.h @@ -42,6 +42,7 @@ void Matrix16View(vec3_t axes[3], vec3_t origin, matrix_t out); void Matrix16SimpleInverse( const matrix_t in, matrix_t out); #define VectorCopy2(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1]) +#define VectorSet2(v,x,y) ((v)[0]=(x),(v)[1]=(y)); #define VectorCopy4(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3]) #define VectorSet4(v,x,y,z,w) ((v)[0]=(x),(v)[1]=(y),(v)[2]=(z),(v)[3]=(w)) diff --git a/code/rend2/tr_extratypes.h b/code/renderergl2/tr_extratypes.h similarity index 92% rename from code/rend2/tr_extratypes.h rename to code/renderergl2/tr_extratypes.h index b84cd5e4..84e39a76 100644 --- a/code/rend2/tr_extratypes.h +++ b/code/renderergl2/tr_extratypes.h @@ -25,11 +25,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // tr_extratypes.h, for mods that want to extend tr_types.h without losing compatibility with original VMs -// extra renderfx flags start at 0x0400 -#define RF_SUNFLARE 0x0400 - // extra refdef flags start at 0x0008 -#define RDF_NOFOG 0x0008 // don't apply fog +#define RDF_NOFOG 0x0008 // don't apply fog to polys added using RE_AddPolyToScene #define RDF_EXTRA 0x0010 // Makro - refdefex_t to follow after refdef_t #define RDF_SUNLIGHT 0x0020 // SmileTheory - render sunlight and shadows diff --git a/code/rend2/tr_fbo.c b/code/renderergl2/tr_fbo.c similarity index 95% rename from code/rend2/tr_fbo.c rename to code/renderergl2/tr_fbo.c index 0e84d944..fee11d5c 100644 --- a/code/rend2/tr_fbo.c +++ b/code/renderergl2/tr_fbo.c @@ -107,7 +107,7 @@ FBO_t *FBO_Create(const char *name, int width, int height) if(strlen(name) >= MAX_QPATH) { - ri.Error(ERR_DROP, "FBO_Create: \"%s\" is too long\n", name); + ri.Error(ERR_DROP, "FBO_Create: \"%s\" is too long", name); } if(width <= 0 || width > glRefConfig.maxRenderbufferSize) @@ -370,8 +370,7 @@ void FBO_Init(void) GL_CheckErrors(); - // make sure the render thread is stopped - R_SyncRenderThread(); + R_IssuePendingRenderCommands(); /* if(glRefConfig.textureNonPowerOfTwo) { @@ -453,20 +452,17 @@ void FBO_Init(void) FBO_Bind(NULL); } -#ifdef REACTION + if (r_drawSunRays->integer) { - tr.godRaysFbo = FBO_Create("_godRays", tr.renderDepthImage->width, tr.renderDepthImage->height); - FBO_Bind(tr.godRaysFbo); + tr.sunRaysFbo = FBO_Create("_sunRays", tr.renderDepthImage->width, tr.renderDepthImage->height); + FBO_Bind(tr.sunRaysFbo); - //FBO_CreateBuffer(tr.godRaysFbo, GL_RGBA8, 0, multisample); - FBO_AttachTextureImage(tr.godRaysImage, 0); + FBO_AttachTextureImage(tr.sunRaysImage, 0); - //FBO_CreateBuffer(tr.godRaysFbo, GL_DEPTH_COMPONENT24_ARB, 0, multisample); R_AttachFBOTextureDepth(tr.renderDepthImage->texnum); - R_CheckFBO(tr.godRaysFbo); + R_CheckFBO(tr.sunRaysFbo); } -#endif // FIXME: Don't use separate color/depth buffers for a shadow buffer for( i = 0; i < MAX_DRAWN_PSHADOWS; i++) @@ -724,7 +720,7 @@ void FBO_BlitFromTexture(struct image_s *src, vec4i_t inSrcBox, vec2_t inSrcTexS } else { - color[0] = color[1] = color[2] = color[3] = 1.0f; + VectorCopy4(colorWhite, color); } if (!shaderProgram) @@ -771,11 +767,11 @@ void FBO_BlitFromTexture(struct image_s *src, vec4i_t inSrcBox, vec2_t inSrcTexS GLSL_BindProgram(shaderProgram); - GLSL_SetUniformMatrix16(shaderProgram, TEXTURECOLOR_UNIFORM_MODELVIEWPROJECTIONMATRIX, projection); - GLSL_SetUniformVec4(shaderProgram, TEXTURECOLOR_UNIFORM_COLOR, color); - GLSL_SetUniformVec2(shaderProgram, TEXTURECOLOR_UNIFORM_INVTEXRES, invTexRes); - GLSL_SetUniformVec2(shaderProgram, TEXTURECOLOR_UNIFORM_AUTOEXPOSUREMINMAX, tr.refdef.autoExposureMinMax); - GLSL_SetUniformVec3(shaderProgram, TEXTURECOLOR_UNIFORM_TONEMINAVGMAXLINEAR, tr.refdef.toneMinAvgMaxLinear); + GLSL_SetUniformMatrix16(shaderProgram, UNIFORM_MODELVIEWPROJECTIONMATRIX, projection); + GLSL_SetUniformVec4(shaderProgram, UNIFORM_COLOR, color); + GLSL_SetUniformVec2(shaderProgram, UNIFORM_INVTEXRES, invTexRes); + GLSL_SetUniformVec2(shaderProgram, UNIFORM_AUTOEXPOSUREMINMAX, tr.refdef.autoExposureMinMax); + GLSL_SetUniformVec3(shaderProgram, UNIFORM_TONEMINAVGMAXLINEAR, tr.refdef.toneMinAvgMaxLinear); RB_InstantQuad2(quadVerts, texCoords); //, color, shaderProgram, invTexRes); @@ -862,4 +858,4 @@ void FBO_FastBlit(FBO_t *src, vec4i_t srcBox, FBO_t *dst, vec4i_t dstBox, int bu qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); glState.currentFBO = NULL; -} \ No newline at end of file +} diff --git a/code/rend2/tr_fbo.h b/code/renderergl2/tr_fbo.h similarity index 100% rename from code/rend2/tr_fbo.h rename to code/renderergl2/tr_fbo.h diff --git a/code/rend2/tr_flares.c b/code/renderergl2/tr_flares.c similarity index 99% rename from code/rend2/tr_flares.c rename to code/renderergl2/tr_flares.c index 8e6c321f..5bcefa2a 100644 --- a/code/rend2/tr_flares.c +++ b/code/renderergl2/tr_flares.c @@ -352,8 +352,8 @@ void RB_RenderFlare( flare_t *f ) { VectorScale(f->color, f->drawIntensity * intensity, color); -// Calculations for fogging - if(tr.world && f->fogNum < tr.world->numfogs) + // Calculations for fogging + if(tr.world && f->fogNum > 0 && f->fogNum < tr.world->numfogs) { tess.numVertexes = 1; VectorCopy(f->origin, tess.xyz[0]); diff --git a/code/rend2/tr_glsl.c b/code/renderergl2/tr_glsl.c similarity index 65% rename from code/rend2/tr_glsl.c rename to code/renderergl2/tr_glsl.c index 7f0b7a4d..d8b07432 100644 --- a/code/rend2/tr_glsl.c +++ b/code/renderergl2/tr_glsl.c @@ -53,6 +53,93 @@ extern const char *fallbackShader_texturecolor_fp; extern const char *fallbackShader_tonemap_vp; extern const char *fallbackShader_tonemap_fp; +typedef struct uniformInfo_s +{ + char *name; + int type; +} +uniformInfo_t; + +// These must be in the same order as in uniform_t in tr_local.h. +static uniformInfo_t uniformsInfo[] = +{ + { "u_DiffuseMap", GLSL_INT }, + { "u_LightMap", GLSL_INT }, + { "u_NormalMap", GLSL_INT }, + { "u_DeluxeMap", GLSL_INT }, + { "u_SpecularMap", GLSL_INT }, + + { "u_TextureMap", GLSL_INT }, + { "u_LevelsMap", GLSL_INT }, + + { "u_ScreenImageMap", GLSL_INT }, + { "u_ScreenDepthMap", GLSL_INT }, + + { "u_ShadowMap", GLSL_INT }, + { "u_ShadowMap2", GLSL_INT }, + { "u_ShadowMap3", GLSL_INT }, + + { "u_ShadowMvp", GLSL_MAT16 }, + { "u_ShadowMvp2", GLSL_MAT16 }, + { "u_ShadowMvp3", GLSL_MAT16 }, + + { "u_DiffuseTexMatrix", GLSL_VEC4 }, + { "u_DiffuseTexOffTurb", GLSL_VEC4 }, + { "u_Texture1Env", GLSL_INT }, + + { "u_TCGen0", GLSL_INT }, + { "u_TCGen0Vector0", GLSL_VEC3 }, + { "u_TCGen0Vector1", GLSL_VEC3 }, + + { "u_DeformGen", GLSL_INT }, + { "u_DeformParams", GLSL_FLOAT5 }, + + { "u_ColorGen", GLSL_INT }, + { "u_AlphaGen", GLSL_INT }, + { "u_Color", GLSL_VEC4 }, + { "u_BaseColor", GLSL_VEC4 }, + { "u_VertColor", GLSL_VEC4 }, + + { "u_DlightInfo", GLSL_VEC4 }, + { "u_LightForward", GLSL_VEC3 }, + { "u_LightUp", GLSL_VEC3 }, + { "u_LightRight", GLSL_VEC3 }, + { "u_LightOrigin", GLSL_VEC4 }, + { "u_LightRadius", GLSL_FLOAT }, + { "u_AmbientLight", GLSL_VEC3 }, + { "u_DirectedLight", GLSL_VEC3 }, + + { "u_PortalRange", GLSL_FLOAT }, + + { "u_FogDistance", GLSL_VEC4 }, + { "u_FogDepth", GLSL_VEC4 }, + { "u_FogEyeT", GLSL_FLOAT }, + { "u_FogColorMask", GLSL_VEC4 }, + + { "u_ModelMatrix", GLSL_MAT16 }, + { "u_ModelViewProjectionMatrix", GLSL_MAT16 }, + + { "u_Time", GLSL_FLOAT }, + { "u_VertexLerp" , GLSL_FLOAT }, + { "u_MaterialInfo", GLSL_VEC2 }, + + { "u_ViewInfo", GLSL_VEC4 }, + { "u_ViewOrigin", GLSL_VEC3 }, + { "u_ViewForward", GLSL_VEC3 }, + { "u_ViewLeft", GLSL_VEC3 }, + { "u_ViewUp", GLSL_VEC3 }, + + { "u_InvTexRes", GLSL_VEC2 }, + { "u_AutoExposureMinMax", GLSL_VEC2 }, + { "u_ToneMinAvgMaxLinear", GLSL_VEC3 }, + + { "u_PrimaryLightOrigin", GLSL_VEC4 }, + { "u_PrimaryLightColor", GLSL_VEC3 }, + { "u_PrimaryLightAmbient", GLSL_VEC3 }, + { "u_PrimaryLightRadius", GLSL_FLOAT } +}; + + static void GLSL_PrintInfoLog(GLhandleARB object, qboolean developerOnly) { char *msg; @@ -334,7 +421,7 @@ static int GLSL_LoadGPUShaderText(const char *name, const char *fallback, return result; } -static void GLSL_LinkProgram(GLhandleARB program, char *vpCode, char *fpCode) +static void GLSL_LinkProgram(GLhandleARB program) { GLint linked; @@ -344,9 +431,8 @@ static void GLSL_LinkProgram(GLhandleARB program, char *vpCode, char *fpCode) if(!linked) { GLSL_PrintInfoLog(program, qfalse); - ri.Printf(PRINT_ALL, "vpCode:\n%s\n", vpCode); - ri.Printf(PRINT_ALL, "fpCode:\n%s\n", fpCode); - ri.Error(ERR_DROP, "\nshaders failed to link"); + ri.Printf(PRINT_ALL, "\n"); + ri.Error(ERR_DROP, "shaders failed to link"); } } @@ -360,7 +446,8 @@ static void GLSL_ValidateProgram(GLhandleARB program) if(!validated) { GLSL_PrintInfoLog(program, qfalse); - ri.Error(ERR_DROP, "\nshaders failed to validate"); + ri.Printf(PRINT_ALL, "\n"); + ri.Error(ERR_DROP, "shaders failed to validate"); } } @@ -389,13 +476,13 @@ static void GLSL_ShowProgramUniforms(GLhandleARB program) qglUseProgramObjectARB(0); } -static int GLSL_InitGPUShader2(shaderProgram_t * program, const char *name, int attribs, const char *vpCode, const char *fpCode, int numUniforms) +static int GLSL_InitGPUShader2(shaderProgram_t * program, const char *name, int attribs, const char *vpCode, const char *fpCode) { ri.Printf(PRINT_DEVELOPER, "------- GPU shader -------\n"); if(strlen(name) >= MAX_QPATH) { - ri.Error(ERR_DROP, "GLSL_InitGPUShader2: \"%s\" is too long\n", name); + ri.Error(ERR_DROP, "GLSL_InitGPUShader2: \"%s\" is too long", name); } Q_strncpyz(program->name, name, sizeof(program->name)); @@ -469,35 +556,14 @@ static int GLSL_InitGPUShader2(shaderProgram_t * program, const char *name, int qglBindAttribLocationARB(program->program, ATTR_INDEX_BITANGENT2, "attr_Bitangent2"); #endif - GLSL_LinkProgram(program->program, vpCode, fpCode); - - program->numUniforms = numUniforms; - - { - int i, size; - - size = sizeof(*program->uniforms) * numUniforms; - program->uniforms = ri.Malloc(size); - for (i = 0; i < numUniforms; i++) - { - program->uniforms[i] = -1; - } - - size = sizeof(*program->uniformTypes) * numUniforms; - program->uniformTypes = ri.Malloc(size); - memset(program->uniformTypes, 0, size); - - size = sizeof(*program->uniformBufferOffsets) * numUniforms; - program->uniformBufferOffsets = ri.Malloc(size); - memset(program->uniformBufferOffsets, 0, size); - } + GLSL_LinkProgram(program->program); return 1; } static int GLSL_InitGPUShader(shaderProgram_t * program, const char *name, int attribs, qboolean fragmentShader, const GLcharARB *extra, qboolean addHeader, - const char *fallback_vp, const char *fallback_fp, int numUniforms) + const char *fallback_vp, const char *fallback_fp) { char vpCode[32000]; char fpCode[32000]; @@ -542,65 +608,56 @@ static int GLSL_InitGPUShader(shaderProgram_t * program, const char *name, } } - result = GLSL_InitGPUShader2(program, name, attribs, vpCode, fragmentShader ? fpCode : NULL, numUniforms); + result = GLSL_InitGPUShader2(program, name, attribs, vpCode, fragmentShader ? fpCode : NULL); return result; } -// intentionally deceiving the user here, not actually setting the names but getting their indexes. -void GLSL_AddUniform(shaderProgram_t *program, int uniformNum, const char *name, int type) +void GLSL_InitUniforms(shaderProgram_t *program) { + int i, size; + GLint *uniforms = program->uniforms; - uniforms[uniformNum] = qglGetUniformLocationARB(program->program, name); - program->uniformTypes[uniformNum] = type; -} - -void GLSL_EndUniforms(shaderProgram_t *program) -{ - if (program->numUniforms) + size = 0; + for (i = 0; i < UNIFORM_COUNT; i++) { - int i, size; + uniforms[i] = qglGetUniformLocationARB(program->program, uniformsInfo[i].name); + + if (uniforms[i] == -1) + continue; - size = 0; - for (i = 0; i < program->numUniforms; i++) + program->uniformBufferOffsets[i] = size; + + switch(uniformsInfo[i].type) { - if (program->uniforms[i] != -1) - { - program->uniformBufferOffsets[i] = size; - - switch(program->uniformTypes[i]) - { - case GLSL_INT: - size += sizeof(GLint); - break; - case GLSL_FLOAT: - size += sizeof(GLfloat); - break; - case GLSL_FLOAT5: - size += sizeof(vec_t) * 5; - break; - case GLSL_VEC2: - size += sizeof(vec_t) * 2; - break; - case GLSL_VEC3: - size += sizeof(vec_t) * 3; - break; - case GLSL_VEC4: - size += sizeof(vec_t) * 4; - break; - case GLSL_MAT16: - size += sizeof(vec_t) * 16; - break; - default: - break; - } - } + case GLSL_INT: + size += sizeof(GLint); + break; + case GLSL_FLOAT: + size += sizeof(GLfloat); + break; + case GLSL_FLOAT5: + size += sizeof(vec_t) * 5; + break; + case GLSL_VEC2: + size += sizeof(vec_t) * 2; + break; + case GLSL_VEC3: + size += sizeof(vec_t) * 3; + break; + case GLSL_VEC4: + size += sizeof(vec_t) * 4; + break; + case GLSL_MAT16: + size += sizeof(vec_t) * 16; + break; + default: + break; } - - program->uniformBuffer = ri.Malloc(size); - } + + program->uniformBuffer = ri.Malloc(size); } void GLSL_FinishGPUShader(shaderProgram_t *program) @@ -618,7 +675,7 @@ void GLSL_SetUniformInt(shaderProgram_t *program, int uniformNum, GLint value) if (uniforms[uniformNum] == -1) return; - if (program->uniformTypes[uniformNum] != GLSL_INT) + if (uniformsInfo[uniformNum].type != GLSL_INT) { ri.Printf( PRINT_WARNING, "GLSL_SetUniformInt: wrong type for uniform %i in program %s\n", uniformNum, program->name); return; @@ -642,7 +699,7 @@ void GLSL_SetUniformFloat(shaderProgram_t *program, int uniformNum, GLfloat valu if (uniforms[uniformNum] == -1) return; - if (program->uniformTypes[uniformNum] != GLSL_FLOAT) + if (uniformsInfo[uniformNum].type != GLSL_FLOAT) { ri.Printf( PRINT_WARNING, "GLSL_SetUniformFloat: wrong type for uniform %i in program %s\n", uniformNum, program->name); return; @@ -666,7 +723,7 @@ void GLSL_SetUniformVec2(shaderProgram_t *program, int uniformNum, const vec2_t if (uniforms[uniformNum] == -1) return; - if (program->uniformTypes[uniformNum] != GLSL_VEC2) + if (uniformsInfo[uniformNum].type != GLSL_VEC2) { ri.Printf( PRINT_WARNING, "GLSL_SetUniformVec2: wrong type for uniform %i in program %s\n", uniformNum, program->name); return; @@ -691,7 +748,7 @@ void GLSL_SetUniformVec3(shaderProgram_t *program, int uniformNum, const vec3_t if (uniforms[uniformNum] == -1) return; - if (program->uniformTypes[uniformNum] != GLSL_VEC3) + if (uniformsInfo[uniformNum].type != GLSL_VEC3) { ri.Printf( PRINT_WARNING, "GLSL_SetUniformVec3: wrong type for uniform %i in program %s\n", uniformNum, program->name); return; @@ -715,7 +772,7 @@ void GLSL_SetUniformVec4(shaderProgram_t *program, int uniformNum, const vec4_t if (uniforms[uniformNum] == -1) return; - if (program->uniformTypes[uniformNum] != GLSL_VEC4) + if (uniformsInfo[uniformNum].type != GLSL_VEC4) { ri.Printf( PRINT_WARNING, "GLSL_SetUniformVec4: wrong type for uniform %i in program %s\n", uniformNum, program->name); return; @@ -739,7 +796,7 @@ void GLSL_SetUniformFloat5(shaderProgram_t *program, int uniformNum, const vec5_ if (uniforms[uniformNum] == -1) return; - if (program->uniformTypes[uniformNum] != GLSL_FLOAT5) + if (uniformsInfo[uniformNum].type != GLSL_FLOAT5) { ri.Printf( PRINT_WARNING, "GLSL_SetUniformFloat5: wrong type for uniform %i in program %s\n", uniformNum, program->name); return; @@ -763,7 +820,7 @@ void GLSL_SetUniformMatrix16(shaderProgram_t *program, int uniformNum, const mat if (uniforms[uniformNum] == -1) return; - if (program->uniformTypes[uniformNum] != GLSL_MAT16) + if (uniformsInfo[uniformNum].type != GLSL_MAT16) { ri.Printf( PRINT_WARNING, "GLSL_SetUniformMatrix16: wrong type for uniform %i in program %s\n", uniformNum, program->name); return; @@ -797,26 +854,11 @@ void GLSL_DeleteGPUShader(shaderProgram_t *program) qglDeleteObjectARB(program->program); - if (program->uniforms) - { - ri.Free(program->uniforms); - } - - if (program->uniformTypes) - { - ri.Free(program->uniformTypes); - } - if (program->uniformBuffer) { ri.Free(program->uniformBuffer); } - if (program->uniformBufferOffsets) - { - ri.Free(program->uniformBufferOffsets); - } - Com_Memset(program, 0, sizeof(*program)); } } @@ -831,8 +873,7 @@ void GLSL_InitGPUShaders(void) ri.Printf(PRINT_ALL, "------- GLSL_InitGPUShaders -------\n"); - // make sure the render thread is stopped - R_SyncRenderThread(); + R_IssuePendingRenderCommands(); startTime = ri.Milliseconds(); @@ -868,70 +909,16 @@ void GLSL_InitGPUShaders(void) if (r_hdr->integer && !(glRefConfig.textureFloat && glRefConfig.halfFloatPixel)) Q_strcat(extradefines, 1024, "#define RGBE_LIGHTMAP\n"); - if (!GLSL_InitGPUShader(&tr.genericShader[i], "generic", attribs, qtrue, extradefines, qtrue, fallbackShader_generic_vp, fallbackShader_generic_fp, GENERIC_UNIFORM_COUNT)) + if (!GLSL_InitGPUShader(&tr.genericShader[i], "generic", attribs, qtrue, extradefines, qtrue, fallbackShader_generic_vp, fallbackShader_generic_fp)) { - ri.Error(ERR_FATAL, "Could not load generic shader!\n"); + ri.Error(ERR_FATAL, "Could not load generic shader!"); } - // There's actually no need to filter these out, since they'll - // redirect to -1 if nonexistent, but it's more understandable this way. - - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_MODELVIEWPROJECTIONMATRIX, "u_ModelViewProjectionMatrix", GLSL_MAT16); - - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_BASECOLOR, "u_BaseColor", GLSL_VEC4); - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_VERTCOLOR, "u_VertColor", GLSL_VEC4); - - if (i & GENERICDEF_USE_RGBAGEN) - { - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_COLORGEN, "u_ColorGen", GLSL_INT); - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_ALPHAGEN, "u_AlphaGen", GLSL_INT); - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_AMBIENTLIGHT, "u_AmbientLight", GLSL_VEC3); - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_DIRECTEDLIGHT, "u_DirectedLight", GLSL_VEC3); - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_LIGHTORIGIN, "u_LightOrigin", GLSL_VEC4); - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_PORTALRANGE, "u_PortalRange", GLSL_FLOAT); - } - - if (i & GENERICDEF_USE_TCGEN_AND_TCMOD) - { - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_TCGEN0, "u_TCGen0", GLSL_INT); - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_TCGEN0VECTOR0, "u_TCGen0Vector0", GLSL_VEC3); - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_TCGEN0VECTOR1, "u_TCGen0Vector1", GLSL_VEC3); - } - - if (i & GENERICDEF_USE_FOG) - { - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_FOGCOLORMASK, "u_FogColorMask", GLSL_VEC4); - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_FOGDISTANCE, "u_FogDistance", GLSL_VEC4); - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_FOGDEPTH, "u_FogDepth", GLSL_VEC4); - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_FOGEYET, "u_FogEyeT", GLSL_FLOAT); - } - - if (i & GENERICDEF_USE_DEFORM_VERTEXES) - { - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_DEFORMGEN, "u_DeformGen", GLSL_INT); - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_DEFORMPARAMS, "u_DeformParams", GLSL_FLOAT5); - } - - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_TIME, "u_Time", GLSL_FLOAT); - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_VIEWORIGIN, "u_ViewOrigin", GLSL_VEC3); - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_DIFFUSETEXMATRIX, "u_DiffuseTexMatrix", GLSL_VEC4); - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_DIFFUSETEXOFFTURB,"u_DiffuseTexOffTurb",GLSL_VEC4); - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_TEXTURE1ENV, "u_Texture1Env", GLSL_INT); - - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_DIFFUSEMAP, "u_DiffuseMap", GLSL_INT); - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_LIGHTMAP, "u_LightMap", GLSL_INT); - - - if (i & GENERICDEF_USE_VERTEX_ANIMATION) - { - GLSL_AddUniform(&tr.genericShader[i], GENERIC_UNIFORM_VERTEXLERP, "u_VertexLerp", GLSL_FLOAT); - } - - GLSL_EndUniforms(&tr.genericShader[i]); + GLSL_InitUniforms(&tr.genericShader[i]); qglUseProgramObjectARB(tr.genericShader[i].program); - GLSL_SetUniformInt(&tr.genericShader[i], GENERIC_UNIFORM_DIFFUSEMAP, TB_DIFFUSEMAP); - GLSL_SetUniformInt(&tr.genericShader[i], GENERIC_UNIFORM_LIGHTMAP, TB_LIGHTMAP); + GLSL_SetUniformInt(&tr.genericShader[i], UNIFORM_DIFFUSEMAP, TB_DIFFUSEMAP); + GLSL_SetUniformInt(&tr.genericShader[i], UNIFORM_LIGHTMAP, TB_LIGHTMAP); qglUseProgramObjectARB(0); GLSL_FinishGPUShader(&tr.genericShader[i]); @@ -942,19 +929,15 @@ void GLSL_InitGPUShaders(void) attribs = ATTR_POSITION | ATTR_TEXCOORD; - if (!GLSL_InitGPUShader(&tr.textureColorShader, "texturecolor", attribs, qtrue, NULL, qfalse, fallbackShader_texturecolor_vp, fallbackShader_texturecolor_fp, TEXTURECOLOR_UNIFORM_COUNT)) + if (!GLSL_InitGPUShader(&tr.textureColorShader, "texturecolor", attribs, qtrue, NULL, qfalse, fallbackShader_texturecolor_vp, fallbackShader_texturecolor_fp)) { - ri.Error(ERR_FATAL, "Could not load texturecolor shader!\n"); + ri.Error(ERR_FATAL, "Could not load texturecolor shader!"); } - GLSL_AddUniform(&tr.textureColorShader, TEXTURECOLOR_UNIFORM_MODELVIEWPROJECTIONMATRIX, "u_ModelViewProjectionMatrix", GLSL_MAT16); - GLSL_AddUniform(&tr.textureColorShader, TEXTURECOLOR_UNIFORM_COLOR, "u_Color", GLSL_VEC4); - GLSL_AddUniform(&tr.textureColorShader, TEXTURECOLOR_UNIFORM_TEXTUREMAP, "u_DiffuseMap", GLSL_INT); - - GLSL_EndUniforms(&tr.textureColorShader); + GLSL_InitUniforms(&tr.textureColorShader); qglUseProgramObjectARB(tr.textureColorShader.program); - GLSL_SetUniformInt(&tr.textureColorShader, TEXTURECOLOR_UNIFORM_TEXTUREMAP, TB_DIFFUSEMAP); + GLSL_SetUniformInt(&tr.textureColorShader, UNIFORM_TEXTUREMAP, TB_DIFFUSEMAP); qglUseProgramObjectARB(0); GLSL_FinishGPUShader(&tr.textureColorShader); @@ -972,22 +955,12 @@ void GLSL_InitGPUShaders(void) if (i & FOGDEF_USE_VERTEX_ANIMATION) Q_strcat(extradefines, 1024, "#define USE_VERTEX_ANIMATION\n"); - if (!GLSL_InitGPUShader(&tr.fogShader[i], "fogpass", attribs, qtrue, extradefines, qtrue, fallbackShader_fogpass_vp, fallbackShader_fogpass_fp, FOGPASS_UNIFORM_COUNT)) + if (!GLSL_InitGPUShader(&tr.fogShader[i], "fogpass", attribs, qtrue, extradefines, qtrue, fallbackShader_fogpass_vp, fallbackShader_fogpass_fp)) { - ri.Error(ERR_FATAL, "Could not load fogpass shader!\n"); + ri.Error(ERR_FATAL, "Could not load fogpass shader!"); } - GLSL_AddUniform(&tr.fogShader[i], FOGPASS_UNIFORM_FOGDISTANCE, "u_FogDistance", GLSL_VEC4); - GLSL_AddUniform(&tr.fogShader[i], FOGPASS_UNIFORM_FOGDEPTH, "u_FogDepth", GLSL_VEC4); - GLSL_AddUniform(&tr.fogShader[i], FOGPASS_UNIFORM_FOGEYET, "u_FogEyeT", GLSL_FLOAT); - GLSL_AddUniform(&tr.fogShader[i], FOGPASS_UNIFORM_DEFORMGEN, "u_DeformGen", GLSL_INT); - GLSL_AddUniform(&tr.fogShader[i], FOGPASS_UNIFORM_DEFORMPARAMS, "u_DeformParams", GLSL_FLOAT5); - GLSL_AddUniform(&tr.fogShader[i], FOGPASS_UNIFORM_TIME, "u_Time", GLSL_FLOAT); - GLSL_AddUniform(&tr.fogShader[i], FOGPASS_UNIFORM_COLOR, "u_Color", GLSL_VEC4); - GLSL_AddUniform(&tr.fogShader[i], FOGPASS_UNIFORM_MODELVIEWPROJECTIONMATRIX, "u_ModelViewProjectionMatrix", GLSL_MAT16); - GLSL_AddUniform(&tr.fogShader[i], FOGPASS_UNIFORM_VERTEXLERP, "u_VertexLerp", GLSL_FLOAT); - - GLSL_EndUniforms(&tr.fogShader[i]); + GLSL_InitUniforms(&tr.fogShader[i]); GLSL_FinishGPUShader(&tr.fogShader[i]); numEtcShaders++; @@ -1004,22 +977,15 @@ void GLSL_InitGPUShaders(void) Q_strcat(extradefines, 1024, "#define USE_DEFORM_VERTEXES\n"); } - if (!GLSL_InitGPUShader(&tr.dlightShader[i], "dlight", attribs, qtrue, extradefines, qtrue, fallbackShader_dlight_vp, fallbackShader_dlight_fp, DLIGHT_UNIFORM_COUNT)) + if (!GLSL_InitGPUShader(&tr.dlightShader[i], "dlight", attribs, qtrue, extradefines, qtrue, fallbackShader_dlight_vp, fallbackShader_dlight_fp)) { - ri.Error(ERR_FATAL, "Could not load dlight shader!\n"); + ri.Error(ERR_FATAL, "Could not load dlight shader!"); } - GLSL_AddUniform(&tr.dlightShader[i], DLIGHT_UNIFORM_DLIGHTINFO, "u_DlightInfo", GLSL_VEC4); - GLSL_AddUniform(&tr.dlightShader[i], DLIGHT_UNIFORM_DEFORMGEN, "u_DeformGen", GLSL_INT); - GLSL_AddUniform(&tr.dlightShader[i], DLIGHT_UNIFORM_DEFORMPARAMS, "u_DeformParams", GLSL_FLOAT5); - GLSL_AddUniform(&tr.dlightShader[i], DLIGHT_UNIFORM_TIME, "u_Time", GLSL_FLOAT); - GLSL_AddUniform(&tr.dlightShader[i], DLIGHT_UNIFORM_COLOR, "u_Color", GLSL_VEC4); - GLSL_AddUniform(&tr.dlightShader[i], DLIGHT_UNIFORM_MODELVIEWPROJECTIONMATRIX, "u_ModelViewProjectionMatrix", GLSL_MAT16); - - GLSL_EndUniforms(&tr.dlightShader[i]); + GLSL_InitUniforms(&tr.dlightShader[i]); qglUseProgramObjectARB(tr.dlightShader[i].program); - GLSL_SetUniformInt(&tr.dlightShader[i], DLIGHT_UNIFORM_DIFFUSEMAP, TB_DIFFUSEMAP); + GLSL_SetUniformInt(&tr.dlightShader[i], UNIFORM_DIFFUSEMAP, TB_DIFFUSEMAP); qglUseProgramObjectARB(0); GLSL_FinishGPUShader(&tr.dlightShader[i]); @@ -1049,7 +1015,8 @@ void GLSL_InitGPUShaders(void) if (!(i & LIGHTDEF_USE_NORMALMAP) && (i & LIGHTDEF_USE_PARALLAXMAP)) continue; - if (!((i & LIGHTDEF_LIGHTTYPE_MASK) == LIGHTDEF_USE_LIGHT_VECTOR)) + //if (!((i & LIGHTDEF_LIGHTTYPE_MASK) == LIGHTDEF_USE_LIGHT_VECTOR)) + if (!(i & LIGHTDEF_LIGHTTYPE_MASK)) { if (i & LIGHTDEF_USE_SHADOWMAP) continue; @@ -1146,8 +1113,15 @@ void GLSL_InitGPUShaders(void) Q_strcat(extradefines, 1024, "#define USE_PARALLAXMAP\n"); if (i & LIGHTDEF_USE_SHADOWMAP) + { Q_strcat(extradefines, 1024, "#define USE_SHADOWMAP\n"); + if (r_sunlightMode->integer == 1) + Q_strcat(extradefines, 1024, "#define SHADOWMAP_MODULATE\n"); + else if (r_sunlightMode->integer == 2) + Q_strcat(extradefines, 1024, "#define USE_PRIMARY_LIGHT\n"); + } + if (i & LIGHTDEF_USE_TCGEN_AND_TCMOD) { Q_strcat(extradefines, 1024, "#define USE_TCGEN\n"); @@ -1167,48 +1141,20 @@ void GLSL_InitGPUShaders(void) #endif } - if (!GLSL_InitGPUShader(&tr.lightallShader[i], "lightall", attribs, qtrue, extradefines, qtrue, fallbackShader_lightall_vp, fallbackShader_lightall_fp, GENERIC_UNIFORM_COUNT)) + if (!GLSL_InitGPUShader(&tr.lightallShader[i], "lightall", attribs, qtrue, extradefines, qtrue, fallbackShader_lightall_vp, fallbackShader_lightall_fp)) { - ri.Error(ERR_FATAL, "Could not load lightall shader!\n"); + ri.Error(ERR_FATAL, "Could not load lightall shader!"); } - GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_MODELVIEWPROJECTIONMATRIX, "u_ModelViewProjectionMatrix", GLSL_MAT16); - GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_MODELMATRIX, "u_ModelMatrix", GLSL_MAT16); - GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_DIFFUSETEXMATRIX, "u_DiffuseTexMatrix", GLSL_VEC4); - GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_DIFFUSETEXOFFTURB, "u_DiffuseTexOffTurb", GLSL_VEC4); - //GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_NORMALTEXMATRIX, "u_NormalTexMatrix", GLSL_MAT16); - //GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_SPECULARTEXMATRIX, "u_SpecularTexMatrix", GLSL_MAT16); - GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_VIEWORIGIN, "u_ViewOrigin", GLSL_VEC3); - - GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_TCGEN0, "u_TCGen0", GLSL_INT); - - GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_DIFFUSEMAP, "u_DiffuseMap", GLSL_INT); - GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_LIGHTMAP, "u_LightMap", GLSL_INT); - GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_NORMALMAP, "u_NormalMap", GLSL_INT); - GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_DELUXEMAP, "u_DeluxeMap", GLSL_INT); - GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_SPECULARMAP, "u_SpecularMap", GLSL_INT); - GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_SHADOWMAP, "u_ShadowMap", GLSL_INT); - - GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_AMBIENTLIGHT, "u_AmbientLight", GLSL_VEC3); - GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_DIRECTEDLIGHT, "u_DirectedLight", GLSL_VEC3); - GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_LIGHTORIGIN, "u_LightOrigin", GLSL_VEC4); - GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_LIGHTRADIUS, "u_LightRadius", GLSL_FLOAT); - - GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_MATERIALINFO, "u_MaterialInfo", GLSL_VEC2); - - GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_BASECOLOR, "u_BaseColor", GLSL_VEC4); - GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_VERTCOLOR, "u_VertColor", GLSL_VEC4); - GLSL_AddUniform(&tr.lightallShader[i], GENERIC_UNIFORM_VERTEXLERP, "u_VertexLerp", GLSL_FLOAT); - - GLSL_EndUniforms(&tr.lightallShader[i]); + GLSL_InitUniforms(&tr.lightallShader[i]); qglUseProgramObjectARB(tr.lightallShader[i].program); - GLSL_SetUniformInt(&tr.lightallShader[i], GENERIC_UNIFORM_DIFFUSEMAP, TB_DIFFUSEMAP); - GLSL_SetUniformInt(&tr.lightallShader[i], GENERIC_UNIFORM_LIGHTMAP, TB_LIGHTMAP); - GLSL_SetUniformInt(&tr.lightallShader[i], GENERIC_UNIFORM_NORMALMAP, TB_NORMALMAP); - GLSL_SetUniformInt(&tr.lightallShader[i], GENERIC_UNIFORM_DELUXEMAP, TB_DELUXEMAP); - GLSL_SetUniformInt(&tr.lightallShader[i], GENERIC_UNIFORM_SPECULARMAP, TB_SPECULARMAP); - GLSL_SetUniformInt(&tr.lightallShader[i], GENERIC_UNIFORM_SHADOWMAP, TB_SHADOWMAP); + GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_DIFFUSEMAP, TB_DIFFUSEMAP); + GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_LIGHTMAP, TB_LIGHTMAP); + GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_NORMALMAP, TB_NORMALMAP); + GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_DELUXEMAP, TB_DELUXEMAP); + GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_SPECULARMAP, TB_SPECULARMAP); + GLSL_SetUniformInt(&tr.lightallShader[i], UNIFORM_SHADOWMAP, TB_SHADOWMAP); qglUseProgramObjectARB(0); GLSL_FinishGPUShader(&tr.lightallShader[i]); @@ -1220,22 +1166,12 @@ void GLSL_InitGPUShaders(void) extradefines[0] = '\0'; - if (!GLSL_InitGPUShader(&tr.shadowmapShader, "shadowfill", attribs, qtrue, extradefines, qtrue, fallbackShader_shadowfill_vp, fallbackShader_shadowfill_fp, GENERIC_UNIFORM_COUNT)) + if (!GLSL_InitGPUShader(&tr.shadowmapShader, "shadowfill", attribs, qtrue, extradefines, qtrue, fallbackShader_shadowfill_vp, fallbackShader_shadowfill_fp)) { - ri.Error(ERR_FATAL, "Could not load shadowfill shader!\n"); + ri.Error(ERR_FATAL, "Could not load shadowfill shader!"); } - GLSL_AddUniform(&tr.shadowmapShader, GENERIC_UNIFORM_DEFORMGEN, "u_DeformGen", GLSL_INT); - GLSL_AddUniform(&tr.shadowmapShader, GENERIC_UNIFORM_DEFORMPARAMS, "u_DeformParams", GLSL_FLOAT5); - GLSL_AddUniform(&tr.shadowmapShader, GENERIC_UNIFORM_TIME, "u_Time", GLSL_FLOAT); - GLSL_AddUniform(&tr.shadowmapShader, GENERIC_UNIFORM_MODELVIEWPROJECTIONMATRIX, "u_ModelViewProjectionMatrix", GLSL_MAT16); - GLSL_AddUniform(&tr.shadowmapShader, GENERIC_UNIFORM_MODELMATRIX, "u_ModelMatrix", GLSL_MAT16); - GLSL_AddUniform(&tr.shadowmapShader, GENERIC_UNIFORM_VERTEXLERP, "u_VertexLerp", GLSL_FLOAT); - - GLSL_AddUniform(&tr.shadowmapShader, GENERIC_UNIFORM_LIGHTORIGIN, "u_LightOrigin", GLSL_VEC4); - GLSL_AddUniform(&tr.shadowmapShader, GENERIC_UNIFORM_LIGHTRADIUS, "u_LightRadius", GLSL_FLOAT); - - GLSL_EndUniforms(&tr.shadowmapShader); + GLSL_InitUniforms(&tr.shadowmapShader); GLSL_FinishGPUShader(&tr.shadowmapShader); numEtcShaders++; @@ -1245,22 +1181,15 @@ void GLSL_InitGPUShaders(void) Q_strcat(extradefines, 1024, "#define USE_PCF\n#define USE_DISCARD\n"); - if (!GLSL_InitGPUShader(&tr.pshadowShader, "pshadow", attribs, qtrue, extradefines, qtrue, fallbackShader_pshadow_vp, fallbackShader_pshadow_fp, PSHADOW_UNIFORM_COUNT)) + if (!GLSL_InitGPUShader(&tr.pshadowShader, "pshadow", attribs, qtrue, extradefines, qtrue, fallbackShader_pshadow_vp, fallbackShader_pshadow_fp)) { - ri.Error(ERR_FATAL, "Could not load pshadow shader!\n"); + ri.Error(ERR_FATAL, "Could not load pshadow shader!"); } - GLSL_AddUniform(&tr.pshadowShader, PSHADOW_UNIFORM_MODELVIEWPROJECTIONMATRIX, "u_ModelViewProjectionMatrix", GLSL_MAT16); - GLSL_AddUniform(&tr.pshadowShader, PSHADOW_UNIFORM_LIGHTFORWARD, "u_LightForward", GLSL_VEC3); - GLSL_AddUniform(&tr.pshadowShader, PSHADOW_UNIFORM_LIGHTUP, "u_LightUp", GLSL_VEC3); - GLSL_AddUniform(&tr.pshadowShader, PSHADOW_UNIFORM_LIGHTRIGHT, "u_LightRight", GLSL_VEC3); - GLSL_AddUniform(&tr.pshadowShader, PSHADOW_UNIFORM_LIGHTORIGIN, "u_LightOrigin", GLSL_VEC4); - GLSL_AddUniform(&tr.pshadowShader, PSHADOW_UNIFORM_LIGHTRADIUS, "u_LightRadius", GLSL_FLOAT); - - GLSL_EndUniforms(&tr.pshadowShader); + GLSL_InitUniforms(&tr.pshadowShader); qglUseProgramObjectARB(tr.pshadowShader.program); - GLSL_SetUniformInt(&tr.pshadowShader, PSHADOW_UNIFORM_SHADOWMAP, TB_DIFFUSEMAP); + GLSL_SetUniformInt(&tr.pshadowShader, UNIFORM_SHADOWMAP, TB_DIFFUSEMAP); qglUseProgramObjectARB(0); GLSL_FinishGPUShader(&tr.pshadowShader); @@ -1271,20 +1200,15 @@ void GLSL_InitGPUShaders(void) attribs = ATTR_POSITION | ATTR_TEXCOORD; extradefines[0] = '\0'; - if (!GLSL_InitGPUShader(&tr.down4xShader, "down4x", attribs, qtrue, extradefines, qtrue, fallbackShader_down4x_vp, fallbackShader_down4x_fp, TEXTURECOLOR_UNIFORM_COUNT)) + if (!GLSL_InitGPUShader(&tr.down4xShader, "down4x", attribs, qtrue, extradefines, qtrue, fallbackShader_down4x_vp, fallbackShader_down4x_fp)) { - ri.Error(ERR_FATAL, "Could not load down4x shader!\n"); + ri.Error(ERR_FATAL, "Could not load down4x shader!"); } - GLSL_AddUniform(&tr.down4xShader, TEXTURECOLOR_UNIFORM_MODELVIEWPROJECTIONMATRIX, "u_ModelViewProjectionMatrix", GLSL_MAT16); - GLSL_AddUniform(&tr.down4xShader, TEXTURECOLOR_UNIFORM_INVTEXRES, "u_InvTexRes", GLSL_VEC2); - - GLSL_AddUniform(&tr.down4xShader, TEXTURECOLOR_UNIFORM_TEXTUREMAP, "u_TextureMap", GLSL_INT); - - GLSL_EndUniforms(&tr.down4xShader); + GLSL_InitUniforms(&tr.down4xShader); qglUseProgramObjectARB(tr.down4xShader.program); - GLSL_SetUniformInt(&tr.down4xShader, TEXTURECOLOR_UNIFORM_TEXTUREMAP, TB_DIFFUSEMAP); + GLSL_SetUniformInt(&tr.down4xShader, UNIFORM_TEXTUREMAP, TB_DIFFUSEMAP); qglUseProgramObjectARB(0); GLSL_FinishGPUShader(&tr.down4xShader); @@ -1295,21 +1219,15 @@ void GLSL_InitGPUShaders(void) attribs = ATTR_POSITION | ATTR_TEXCOORD; extradefines[0] = '\0'; - if (!GLSL_InitGPUShader(&tr.bokehShader, "bokeh", attribs, qtrue, extradefines, qtrue, fallbackShader_bokeh_vp, fallbackShader_bokeh_fp, TEXTURECOLOR_UNIFORM_COUNT)) + if (!GLSL_InitGPUShader(&tr.bokehShader, "bokeh", attribs, qtrue, extradefines, qtrue, fallbackShader_bokeh_vp, fallbackShader_bokeh_fp)) { - ri.Error(ERR_FATAL, "Could not load bokeh shader!\n"); + ri.Error(ERR_FATAL, "Could not load bokeh shader!"); } - - GLSL_AddUniform(&tr.bokehShader, TEXTURECOLOR_UNIFORM_MODELVIEWPROJECTIONMATRIX, "u_ModelViewProjectionMatrix", GLSL_MAT16); - GLSL_AddUniform(&tr.bokehShader, TEXTURECOLOR_UNIFORM_INVTEXRES, "u_InvTexRes", GLSL_VEC2); - GLSL_AddUniform(&tr.bokehShader, TEXTURECOLOR_UNIFORM_COLOR, "u_Color", GLSL_VEC4); - GLSL_AddUniform(&tr.bokehShader, TEXTURECOLOR_UNIFORM_TEXTUREMAP, "u_TextureMap", GLSL_INT); - - GLSL_EndUniforms(&tr.bokehShader); + GLSL_InitUniforms(&tr.bokehShader); qglUseProgramObjectARB(tr.bokehShader.program); - GLSL_SetUniformInt(&tr.bokehShader, TEXTURECOLOR_UNIFORM_TEXTUREMAP, TB_DIFFUSEMAP); + GLSL_SetUniformInt(&tr.bokehShader, UNIFORM_TEXTUREMAP, TB_DIFFUSEMAP); qglUseProgramObjectARB(0); GLSL_FinishGPUShader(&tr.bokehShader); @@ -1320,24 +1238,16 @@ void GLSL_InitGPUShaders(void) attribs = ATTR_POSITION | ATTR_TEXCOORD; extradefines[0] = '\0'; - if (!GLSL_InitGPUShader(&tr.tonemapShader, "tonemap", attribs, qtrue, extradefines, qtrue, fallbackShader_tonemap_vp, fallbackShader_tonemap_fp, TEXTURECOLOR_UNIFORM_COUNT)) + if (!GLSL_InitGPUShader(&tr.tonemapShader, "tonemap", attribs, qtrue, extradefines, qtrue, fallbackShader_tonemap_vp, fallbackShader_tonemap_fp)) { - ri.Error(ERR_FATAL, "Could not load tonemap shader!\n"); + ri.Error(ERR_FATAL, "Could not load tonemap shader!"); } - - GLSL_AddUniform(&tr.tonemapShader, TEXTURECOLOR_UNIFORM_MODELVIEWPROJECTIONMATRIX, "u_ModelViewProjectionMatrix", GLSL_MAT16); - GLSL_AddUniform(&tr.tonemapShader, TEXTURECOLOR_UNIFORM_INVTEXRES, "u_InvTexRes", GLSL_VEC2); - GLSL_AddUniform(&tr.tonemapShader, TEXTURECOLOR_UNIFORM_COLOR, "u_Color", GLSL_VEC4); - GLSL_AddUniform(&tr.tonemapShader, TEXTURECOLOR_UNIFORM_AUTOEXPOSUREMINMAX, "u_AutoExposureMinMax", GLSL_VEC2); - GLSL_AddUniform(&tr.tonemapShader, TEXTURECOLOR_UNIFORM_TONEMINAVGMAXLINEAR, "u_ToneMinAvgMaxLinear", GLSL_VEC3); - GLSL_AddUniform(&tr.tonemapShader, TEXTURECOLOR_UNIFORM_TEXTUREMAP, "u_TextureMap", GLSL_INT); - GLSL_AddUniform(&tr.tonemapShader, TEXTURECOLOR_UNIFORM_LEVELSMAP, "u_LevelsMap", GLSL_INT); - GLSL_EndUniforms(&tr.tonemapShader); + GLSL_InitUniforms(&tr.tonemapShader); qglUseProgramObjectARB(tr.tonemapShader.program); - GLSL_SetUniformInt(&tr.tonemapShader, TEXTURECOLOR_UNIFORM_TEXTUREMAP, TB_COLORMAP); - GLSL_SetUniformInt(&tr.tonemapShader, TEXTURECOLOR_UNIFORM_LEVELSMAP, TB_LEVELSMAP); + GLSL_SetUniformInt(&tr.tonemapShader, UNIFORM_TEXTUREMAP, TB_COLORMAP); + GLSL_SetUniformInt(&tr.tonemapShader, UNIFORM_LEVELSMAP, TB_LEVELSMAP); qglUseProgramObjectARB(0); GLSL_FinishGPUShader(&tr.tonemapShader); @@ -1353,21 +1263,15 @@ void GLSL_InitGPUShaders(void) if (!i) Q_strcat(extradefines, 1024, "#define FIRST_PASS\n"); - if (!GLSL_InitGPUShader(&tr.calclevels4xShader[i], "calclevels4x", attribs, qtrue, extradefines, qtrue, fallbackShader_calclevels4x_vp, fallbackShader_calclevels4x_fp, TEXTURECOLOR_UNIFORM_COUNT)) + if (!GLSL_InitGPUShader(&tr.calclevels4xShader[i], "calclevels4x", attribs, qtrue, extradefines, qtrue, fallbackShader_calclevels4x_vp, fallbackShader_calclevels4x_fp)) { - ri.Error(ERR_FATAL, "Could not load calclevels4x shader!\n"); + ri.Error(ERR_FATAL, "Could not load calclevels4x shader!"); } - GLSL_AddUniform(&tr.calclevels4xShader[i], TEXTURECOLOR_UNIFORM_MODELVIEWPROJECTIONMATRIX, "u_ModelViewProjectionMatrix", GLSL_MAT16); - GLSL_AddUniform(&tr.calclevels4xShader[i], TEXTURECOLOR_UNIFORM_INVTEXRES, "u_InvTexRes", GLSL_VEC2); - GLSL_AddUniform(&tr.calclevels4xShader[i], TEXTURECOLOR_UNIFORM_COLOR, "u_Color", GLSL_VEC4); - - GLSL_AddUniform(&tr.calclevels4xShader[i], TEXTURECOLOR_UNIFORM_TEXTUREMAP, "u_TextureMap", GLSL_INT); - - GLSL_EndUniforms(&tr.calclevels4xShader[i]); + GLSL_InitUniforms(&tr.calclevels4xShader[i]); qglUseProgramObjectARB(tr.calclevels4xShader[i].program); - GLSL_SetUniformInt(&tr.calclevels4xShader[i], TEXTURECOLOR_UNIFORM_TEXTUREMAP, TB_DIFFUSEMAP); + GLSL_SetUniformInt(&tr.calclevels4xShader[i], UNIFORM_TEXTUREMAP, TB_DIFFUSEMAP); qglUseProgramObjectARB(0); GLSL_FinishGPUShader(&tr.calclevels4xShader[i]); @@ -1391,32 +1295,18 @@ void GLSL_InitGPUShaders(void) Q_strcat(extradefines, 1024, va("#define r_shadowCascadeZFar %f\n", r_shadowCascadeZFar->value)); - if (!GLSL_InitGPUShader(&tr.shadowmaskShader, "shadowmask", attribs, qtrue, extradefines, qtrue, fallbackShader_shadowmask_vp, fallbackShader_shadowmask_fp, SHADOWMASK_UNIFORM_COUNT)) + if (!GLSL_InitGPUShader(&tr.shadowmaskShader, "shadowmask", attribs, qtrue, extradefines, qtrue, fallbackShader_shadowmask_vp, fallbackShader_shadowmask_fp)) { - ri.Error(ERR_FATAL, "Could not load shadowmask shader!\n"); + ri.Error(ERR_FATAL, "Could not load shadowmask shader!"); } - GLSL_AddUniform(&tr.shadowmaskShader, SHADOWMASK_UNIFORM_SHADOWMVP, "u_ShadowMvp", GLSL_MAT16); - GLSL_AddUniform(&tr.shadowmaskShader, SHADOWMASK_UNIFORM_SHADOWMVP2, "u_ShadowMvp2", GLSL_MAT16); - GLSL_AddUniform(&tr.shadowmaskShader, SHADOWMASK_UNIFORM_SHADOWMVP3, "u_ShadowMvp3", GLSL_MAT16); - GLSL_AddUniform(&tr.shadowmaskShader, SHADOWMASK_UNIFORM_VIEWORIGIN, "u_ViewOrigin", GLSL_VEC3); - GLSL_AddUniform(&tr.shadowmaskShader, SHADOWMASK_UNIFORM_VIEWINFO, "u_ViewInfo", GLSL_VEC4); - GLSL_AddUniform(&tr.shadowmaskShader, SHADOWMASK_UNIFORM_VIEWFORWARD,"u_ViewForward", GLSL_VEC3); - GLSL_AddUniform(&tr.shadowmaskShader, SHADOWMASK_UNIFORM_VIEWLEFT, "u_ViewLeft", GLSL_VEC3); - GLSL_AddUniform(&tr.shadowmaskShader, SHADOWMASK_UNIFORM_VIEWUP, "u_ViewUp", GLSL_VEC3); - - GLSL_AddUniform(&tr.shadowmaskShader, SHADOWMASK_UNIFORM_SCREENDEPTHMAP, "u_ScreenDepthMap", GLSL_INT); - GLSL_AddUniform(&tr.shadowmaskShader, SHADOWMASK_UNIFORM_SHADOWMAP, "u_ShadowMap", GLSL_INT); - GLSL_AddUniform(&tr.shadowmaskShader, SHADOWMASK_UNIFORM_SHADOWMAP2, "u_ShadowMap2", GLSL_INT); - GLSL_AddUniform(&tr.shadowmaskShader, SHADOWMASK_UNIFORM_SHADOWMAP3, "u_ShadowMap3", GLSL_INT); - - GLSL_EndUniforms(&tr.shadowmaskShader); + GLSL_InitUniforms(&tr.shadowmaskShader); qglUseProgramObjectARB(tr.shadowmaskShader.program); - GLSL_SetUniformInt(&tr.shadowmaskShader, SHADOWMASK_UNIFORM_SCREENDEPTHMAP, TB_COLORMAP); - GLSL_SetUniformInt(&tr.shadowmaskShader, SHADOWMASK_UNIFORM_SHADOWMAP, TB_SHADOWMAP); - GLSL_SetUniformInt(&tr.shadowmaskShader, SHADOWMASK_UNIFORM_SHADOWMAP2, TB_SHADOWMAP2); - GLSL_SetUniformInt(&tr.shadowmaskShader, SHADOWMASK_UNIFORM_SHADOWMAP3, TB_SHADOWMAP3); + GLSL_SetUniformInt(&tr.shadowmaskShader, UNIFORM_SCREENDEPTHMAP, TB_COLORMAP); + GLSL_SetUniformInt(&tr.shadowmaskShader, UNIFORM_SHADOWMAP, TB_SHADOWMAP); + GLSL_SetUniformInt(&tr.shadowmaskShader, UNIFORM_SHADOWMAP2, TB_SHADOWMAP2); + GLSL_SetUniformInt(&tr.shadowmaskShader, UNIFORM_SHADOWMAP3, TB_SHADOWMAP3); qglUseProgramObjectARB(0); GLSL_FinishGPUShader(&tr.shadowmaskShader); @@ -1427,19 +1317,15 @@ void GLSL_InitGPUShaders(void) attribs = ATTR_POSITION | ATTR_TEXCOORD; extradefines[0] = '\0'; - if (!GLSL_InitGPUShader(&tr.ssaoShader, "ssao", attribs, qtrue, extradefines, qtrue, fallbackShader_ssao_vp, fallbackShader_ssao_fp, SSAO_UNIFORM_COUNT)) + if (!GLSL_InitGPUShader(&tr.ssaoShader, "ssao", attribs, qtrue, extradefines, qtrue, fallbackShader_ssao_vp, fallbackShader_ssao_fp)) { - ri.Error(ERR_FATAL, "Could not load ssao shader!\n"); + ri.Error(ERR_FATAL, "Could not load ssao shader!"); } - - GLSL_AddUniform(&tr.ssaoShader, SSAO_UNIFORM_VIEWINFO, "u_ViewInfo", GLSL_VEC4); - GLSL_AddUniform(&tr.ssaoShader, SSAO_UNIFORM_SCREENDEPTHMAP, "u_ScreenDepthMap", GLSL_INT); - - GLSL_EndUniforms(&tr.ssaoShader); + GLSL_InitUniforms(&tr.ssaoShader); qglUseProgramObjectARB(tr.ssaoShader.program); - GLSL_SetUniformInt(&tr.ssaoShader, SSAO_UNIFORM_SCREENDEPTHMAP, TB_COLORMAP); + GLSL_SetUniformInt(&tr.ssaoShader, UNIFORM_SCREENDEPTHMAP, TB_COLORMAP); qglUseProgramObjectARB(0); GLSL_FinishGPUShader(&tr.ssaoShader); @@ -1458,21 +1344,16 @@ void GLSL_InitGPUShaders(void) Q_strcat(extradefines, 1024, "#define USE_HORIZONTAL_BLUR\n"); - if (!GLSL_InitGPUShader(&tr.depthBlurShader[i], "depthBlur", attribs, qtrue, extradefines, qtrue, fallbackShader_depthblur_vp, fallbackShader_depthblur_fp, DEPTHBLUR_UNIFORM_COUNT)) + if (!GLSL_InitGPUShader(&tr.depthBlurShader[i], "depthBlur", attribs, qtrue, extradefines, qtrue, fallbackShader_depthblur_vp, fallbackShader_depthblur_fp)) { - ri.Error(ERR_FATAL, "Could not load depthBlur shader!\n"); + ri.Error(ERR_FATAL, "Could not load depthBlur shader!"); } - GLSL_AddUniform(&tr.depthBlurShader[i], DEPTHBLUR_UNIFORM_VIEWINFO, "u_ViewInfo", GLSL_VEC4); - - GLSL_AddUniform(&tr.depthBlurShader[i], DEPTHBLUR_UNIFORM_SCREENIMAGEMAP, "u_ScreenImageMap", GLSL_INT); - GLSL_AddUniform(&tr.depthBlurShader[i], DEPTHBLUR_UNIFORM_SCREENDEPTHMAP, "u_ScreenDepthMap", GLSL_INT); - - GLSL_EndUniforms(&tr.depthBlurShader[i]); + GLSL_InitUniforms(&tr.depthBlurShader[i]); qglUseProgramObjectARB(tr.depthBlurShader[i].program); - GLSL_SetUniformInt(&tr.depthBlurShader[i], DEPTHBLUR_UNIFORM_SCREENIMAGEMAP, TB_COLORMAP); - GLSL_SetUniformInt(&tr.depthBlurShader[i], DEPTHBLUR_UNIFORM_SCREENDEPTHMAP, TB_LIGHTMAP); + GLSL_SetUniformInt(&tr.depthBlurShader[i], UNIFORM_SCREENIMAGEMAP, TB_COLORMAP); + GLSL_SetUniformInt(&tr.depthBlurShader[i], UNIFORM_SCREENDEPTHMAP, TB_LIGHTMAP); qglUseProgramObjectARB(0); GLSL_FinishGPUShader(&tr.depthBlurShader[i]); @@ -1529,10 +1410,18 @@ void GLSL_ShutdownGPUShaders(void) GLSL_DeleteGPUShader(&tr.shadowmapShader); GLSL_DeleteGPUShader(&tr.pshadowShader); GLSL_DeleteGPUShader(&tr.down4xShader); - + GLSL_DeleteGPUShader(&tr.bokehShader); + GLSL_DeleteGPUShader(&tr.tonemapShader); + for ( i = 0; i < 2; i++) GLSL_DeleteGPUShader(&tr.calclevels4xShader[i]); + GLSL_DeleteGPUShader(&tr.shadowmaskShader); + GLSL_DeleteGPUShader(&tr.ssaoShader); + + for ( i = 0; i < 2; i++) + GLSL_DeleteGPUShader(&tr.depthBlurShader[i]); + glState.currentProgram = 0; qglUseProgramObjectARB(0); } @@ -1765,6 +1654,9 @@ void GLSL_VertexAttribsState(uint32_t stateBits) void GLSL_VertexAttribPointers(uint32_t attribBits) { + qboolean animated; + int newFrame, oldFrame; + if(!glState.currentVBO) { ri.Error(ERR_FATAL, "GL_VertexAttribPointers: no VBO bound"); @@ -1774,11 +1666,16 @@ void GLSL_VertexAttribPointers(uint32_t attribBits) // don't just call LogComment, or we will get a call to va() every frame! GLimp_LogComment(va("--- GL_VertexAttribPointers( %s ) ---\n", glState.currentVBO->name)); - if((attribBits & ATTR_POSITION) && !(glState.vertexAttribPointersSet & ATTR_POSITION)) + // position/normal/tangent/bitangent are always set in case of animation + oldFrame = glState.vertexAttribsOldFrame; + newFrame = glState.vertexAttribsNewFrame; + animated = (oldFrame != newFrame) && (glState.vertexAttribsInterpolation > 0.0f); + + if((attribBits & ATTR_POSITION) && (!(glState.vertexAttribPointersSet & ATTR_POSITION) || animated)) { GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_POSITION )\n"); - qglVertexAttribPointerARB(ATTR_INDEX_POSITION, 3, GL_FLOAT, 0, glState.currentVBO->stride_xyz, BUFFER_OFFSET(glState.currentVBO->ofs_xyz + glState.vertexAttribsNewFrame * glState.currentVBO->size_xyz)); + qglVertexAttribPointerARB(ATTR_INDEX_POSITION, 3, GL_FLOAT, 0, glState.currentVBO->stride_xyz, BUFFER_OFFSET(glState.currentVBO->ofs_xyz + newFrame * glState.currentVBO->size_xyz)); glState.vertexAttribPointersSet |= ATTR_POSITION; } @@ -1798,28 +1695,28 @@ void GLSL_VertexAttribPointers(uint32_t attribBits) glState.vertexAttribPointersSet |= ATTR_LIGHTCOORD; } - if((attribBits & ATTR_NORMAL) && !(glState.vertexAttribPointersSet & ATTR_NORMAL)) + if((attribBits & ATTR_NORMAL) && (!(glState.vertexAttribPointersSet & ATTR_NORMAL) || animated)) { GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_NORMAL )\n"); - qglVertexAttribPointerARB(ATTR_INDEX_NORMAL, 3, GL_FLOAT, 0, glState.currentVBO->stride_normal, BUFFER_OFFSET(glState.currentVBO->ofs_normal + glState.vertexAttribsNewFrame * glState.currentVBO->size_normal)); + qglVertexAttribPointerARB(ATTR_INDEX_NORMAL, 3, GL_FLOAT, 0, glState.currentVBO->stride_normal, BUFFER_OFFSET(glState.currentVBO->ofs_normal + newFrame * glState.currentVBO->size_normal)); glState.vertexAttribPointersSet |= ATTR_NORMAL; } #ifdef USE_VERT_TANGENT_SPACE - if((attribBits & ATTR_TANGENT) && !(glState.vertexAttribPointersSet & ATTR_TANGENT)) + if((attribBits & ATTR_TANGENT) && (!(glState.vertexAttribPointersSet & ATTR_TANGENT) || animated)) { GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_TANGENT )\n"); - qglVertexAttribPointerARB(ATTR_INDEX_TANGENT, 3, GL_FLOAT, 0, glState.currentVBO->stride_tangent, BUFFER_OFFSET(glState.currentVBO->ofs_tangent + glState.vertexAttribsNewFrame * glState.currentVBO->size_normal)); // FIXME + qglVertexAttribPointerARB(ATTR_INDEX_TANGENT, 3, GL_FLOAT, 0, glState.currentVBO->stride_tangent, BUFFER_OFFSET(glState.currentVBO->ofs_tangent + newFrame * glState.currentVBO->size_normal)); // FIXME glState.vertexAttribPointersSet |= ATTR_TANGENT; } - if((attribBits & ATTR_BITANGENT) && !(glState.vertexAttribPointersSet & ATTR_BITANGENT)) + if((attribBits & ATTR_BITANGENT) && (!(glState.vertexAttribPointersSet & ATTR_BITANGENT) || animated)) { GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_BITANGENT )\n"); - qglVertexAttribPointerARB(ATTR_INDEX_BITANGENT, 3, GL_FLOAT, 0, glState.currentVBO->stride_bitangent, BUFFER_OFFSET(glState.currentVBO->ofs_bitangent + glState.vertexAttribsNewFrame * glState.currentVBO->size_normal)); // FIXME + qglVertexAttribPointerARB(ATTR_INDEX_BITANGENT, 3, GL_FLOAT, 0, glState.currentVBO->stride_bitangent, BUFFER_OFFSET(glState.currentVBO->ofs_bitangent + newFrame * glState.currentVBO->size_normal)); // FIXME glState.vertexAttribPointersSet |= ATTR_BITANGENT; } #endif @@ -1840,42 +1737,43 @@ void GLSL_VertexAttribPointers(uint32_t attribBits) glState.vertexAttribPointersSet |= ATTR_LIGHTDIRECTION; } - if((attribBits & ATTR_POSITION2) && !(glState.vertexAttribPointersSet & ATTR_POSITION2)) + if((attribBits & ATTR_POSITION2) && (!(glState.vertexAttribPointersSet & ATTR_POSITION2) || animated)) { GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_POSITION2 )\n"); - qglVertexAttribPointerARB(ATTR_INDEX_POSITION2, 3, GL_FLOAT, 0, glState.currentVBO->stride_xyz, BUFFER_OFFSET(glState.currentVBO->ofs_xyz + glState.vertexAttribsOldFrame * glState.currentVBO->size_xyz)); + qglVertexAttribPointerARB(ATTR_INDEX_POSITION2, 3, GL_FLOAT, 0, glState.currentVBO->stride_xyz, BUFFER_OFFSET(glState.currentVBO->ofs_xyz + oldFrame * glState.currentVBO->size_xyz)); glState.vertexAttribPointersSet |= ATTR_POSITION2; } - if((attribBits & ATTR_NORMAL2) && !(glState.vertexAttribPointersSet & ATTR_NORMAL2)) + if((attribBits & ATTR_NORMAL2) && (!(glState.vertexAttribPointersSet & ATTR_NORMAL2) || animated)) { GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_NORMAL2 )\n"); - qglVertexAttribPointerARB(ATTR_INDEX_NORMAL2, 3, GL_FLOAT, 0, glState.currentVBO->stride_normal, BUFFER_OFFSET(glState.currentVBO->ofs_normal + glState.vertexAttribsOldFrame * glState.currentVBO->size_normal)); + qglVertexAttribPointerARB(ATTR_INDEX_NORMAL2, 3, GL_FLOAT, 0, glState.currentVBO->stride_normal, BUFFER_OFFSET(glState.currentVBO->ofs_normal + oldFrame * glState.currentVBO->size_normal)); glState.vertexAttribPointersSet |= ATTR_NORMAL2; } #ifdef USE_VERT_TANGENT_SPACE - if((attribBits & ATTR_TANGENT2) && !(glState.vertexAttribPointersSet & ATTR_TANGENT2)) + if((attribBits & ATTR_TANGENT2) && (!(glState.vertexAttribPointersSet & ATTR_TANGENT2) || animated)) { GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_TANGENT2 )\n"); - qglVertexAttribPointerARB(ATTR_INDEX_TANGENT2, 3, GL_FLOAT, 0, glState.currentVBO->stride_tangent, BUFFER_OFFSET(glState.currentVBO->ofs_tangent + glState.vertexAttribsOldFrame * glState.currentVBO->size_normal)); // FIXME + qglVertexAttribPointerARB(ATTR_INDEX_TANGENT2, 3, GL_FLOAT, 0, glState.currentVBO->stride_tangent, BUFFER_OFFSET(glState.currentVBO->ofs_tangent + oldFrame * glState.currentVBO->size_normal)); // FIXME glState.vertexAttribPointersSet |= ATTR_TANGENT2; } - if((attribBits & ATTR_BITANGENT2) && !(glState.vertexAttribPointersSet & ATTR_BITANGENT2)) + if((attribBits & ATTR_BITANGENT2) && (!(glState.vertexAttribPointersSet & ATTR_BITANGENT2) || animated)) { GLimp_LogComment("qglVertexAttribPointerARB( ATTR_INDEX_BITANGENT2 )\n"); - qglVertexAttribPointerARB(ATTR_INDEX_BITANGENT2, 3, GL_FLOAT, 0, glState.currentVBO->stride_bitangent, BUFFER_OFFSET(glState.currentVBO->ofs_bitangent + glState.vertexAttribsOldFrame * glState.currentVBO->size_normal)); // FIXME + qglVertexAttribPointerARB(ATTR_INDEX_BITANGENT2, 3, GL_FLOAT, 0, glState.currentVBO->stride_bitangent, BUFFER_OFFSET(glState.currentVBO->ofs_bitangent + oldFrame * glState.currentVBO->size_normal)); // FIXME glState.vertexAttribPointersSet |= ATTR_BITANGENT2; } #endif } + shaderProgram_t *GLSL_GetGenericShaderProgram(int stage) { shaderStage_t *pStage = tess.xstages[stage]; diff --git a/code/rend2/tr_image.c b/code/renderergl2/tr_image.c similarity index 96% rename from code/rend2/tr_image.c rename to code/renderergl2/tr_image.c index 20edb0af..c9ca6ce6 100644 --- a/code/rend2/tr_image.c +++ b/code/renderergl2/tr_image.c @@ -146,7 +146,6 @@ R_ImageList_f =============== */ void R_ImageList_f( void ) { -#if 1 int i; int estTotalSize = 0; @@ -283,107 +282,6 @@ void R_ImageList_f( void ) { ri.Printf (PRINT_ALL, " ---------\n"); ri.Printf (PRINT_ALL, " approx %i bytes\n", estTotalSize); ri.Printf (PRINT_ALL, " %i total images\n\n", tr.numImages ); -#else - int i; - image_t *image; - int texels; - const char *yesno[] = { - "no ", "yes" - }; - - ri.Printf (PRINT_ALL, "\n -w-- -h-- -mm- -TMU- -if-- wrap --name-------\n"); - texels = 0; - - for ( i = 0 ; i < tr.numImages ; i++ ) { - image = tr.images[ i ]; - - texels += image->uploadWidth*image->uploadHeight; - ri.Printf (PRINT_ALL, "%4i: %4i %4i %s %d ", - i, image->uploadWidth, image->uploadHeight, yesno[(image->flags & IMGFLAG_MIPMAP) ? 1 : 0], image->TMU ); - switch ( image->internalFormat ) { - case 1: - ri.Printf( PRINT_ALL, "I " ); - break; - case 2: - ri.Printf( PRINT_ALL, "IA " ); - break; - case 3: - ri.Printf( PRINT_ALL, "RGB " ); - break; - case 4: - ri.Printf( PRINT_ALL, "RGBA " ); - break; - case GL_RGBA8: - ri.Printf( PRINT_ALL, "RGBA8" ); - break; - case GL_RGB8: - ri.Printf( PRINT_ALL, "RGB8" ); - break; - case GL_RGB4_S3TC: - ri.Printf( PRINT_ALL, "S3TC " ); - break; - case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: - ri.Printf( PRINT_ALL, "DXT1 " ); - break; - case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: - ri.Printf( PRINT_ALL, "DXT5 " ); - break; - case GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT: - ri.Printf( PRINT_ALL, "LATC " ); - break; - case GL_RGBA4: - ri.Printf( PRINT_ALL, "RGBA4" ); - break; - case GL_RGB5: - ri.Printf( PRINT_ALL, "RGB5 " ); - break; - case GL_SRGB_EXT: - ri.Printf( PRINT_ALL, "sRGB " ); - break; - case GL_SRGB8_EXT: - ri.Printf( PRINT_ALL, "sRGB8" ); - break; - case GL_SRGB_ALPHA_EXT: - case GL_SRGB8_ALPHA8_EXT: - ri.Printf( PRINT_ALL, "sRGBA" ); - break; - /* - case GL_SLUMINANCE_EXT: - break; - case GL_SLUMINANCE8_EXT: - break; - case GL_SLUMINANCE_ALPHA_EXT: - break; - case GL_SLUMINANCE8_ALPHA8_EXT: - break; - */ - case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: - ri.Printf( PRINT_ALL, "sDXT1" ); - break; - case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: - ri.Printf( PRINT_ALL, "sDXT5" ); - break; - case GL_COMPRESSED_RGBA_BPTC_UNORM_ARB: - ri.Printf( PRINT_ALL, "BPTC " ); - break; - case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB: - ri.Printf( PRINT_ALL, "sBPTC" ); - break; - default: - ri.Printf( PRINT_ALL, "???? " ); - } - - if (image->flags & IMGFLAG_CLAMPTOEDGE) - ri.Printf( PRINT_ALL, "clmp " ); - else - ri.Printf( PRINT_ALL, "rept " ); - - ri.Printf( PRINT_ALL, " %s\n", image->imgName ); - } - ri.Printf (PRINT_ALL, " ---------\n"); - ri.Printf (PRINT_ALL, " %i total texels (not including mipmaps)\n", texels); - ri.Printf (PRINT_ALL, " %i total images\n\n", tr.numImages ); -#endif } //======================================================================= @@ -428,7 +326,6 @@ static void ResampleTexture( byte *in, int inwidth, int inheight, byte *out, for (i=0 ; i> 1; for (j=0 ; jinteger) internalFormat = GL_LUMINANCE; else @@ -2959,9 +2855,9 @@ void R_CreateBuiltinImages( void ) { hdrFormat = GL_RGB16F_ARB; tr.renderImage = R_CreateImage("_render", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, hdrFormat); -#ifdef REACTION - tr.godRaysImage = R_CreateImage("*godRays", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_RGBA8); -#endif + + if (r_drawSunRays->integer) + tr.sunRaysImage = R_CreateImage("*sunRays", NULL, width, height, IMGTYPE_COLORALPHA, IMGFLAG_NO_COMPRESSION | IMGFLAG_CLAMPTOEDGE, GL_RGBA8); if (r_softOverbright->integer) { @@ -3349,8 +3245,7 @@ qhandle_t RE_RegisterSkin( const char *name ) { Q_strncpyz( skin->name, name, sizeof( skin->name ) ); skin->numSurfaces = 0; - // make sure the render thread is stopped - R_SyncRenderThread(); + R_IssuePendingRenderCommands(); // If not a .skin file, load as a single shader if ( strcmp( name + strlen( name ) - 5, ".skin" ) ) { diff --git a/code/rend2/tr_init.c b/code/renderergl2/tr_init.c similarity index 96% rename from code/rend2/tr_init.c rename to code/renderergl2/tr_init.c index 2ee6ff32..d5330248 100644 --- a/code/rend2/tr_init.c +++ b/code/renderergl2/tr_init.c @@ -55,8 +55,6 @@ cvar_t *r_znear; cvar_t *r_zproj; cvar_t *r_stereoSeparation; -cvar_t *r_smp; -cvar_t *r_showSmp; cvar_t *r_skipBackEnd; cvar_t *r_stereoEnabled; @@ -146,6 +144,8 @@ cvar_t *r_forceSun; cvar_t *r_forceSunMapLightScale; cvar_t *r_forceSunLightScale; cvar_t *r_forceSunAmbientScale; +cvar_t *r_sunlightMode; +cvar_t *r_drawSunRays; cvar_t *r_sunShadows; cvar_t *r_shadowFilter; cvar_t *r_shadowMapSize; @@ -268,9 +268,6 @@ static void InitOpenGL( void ) } } - // init command buffers and SMP - R_InitCommandBuffers(); - // set default state GL_SetDefaultState(); } @@ -542,7 +539,11 @@ const void *RB_TakeScreenshotCmd( const void *data ) { const screenshotCommand_t *cmd; cmd = (const screenshotCommand_t *)data; - + + // finish any 2D drawing if needed + if(tess.numIndexes) + RB_EndSurface(); + if (cmd->jpeg) RB_TakeScreenshotJPEG( cmd->x, cmd->y, cmd->width, cmd->height, cmd->fileName); else @@ -824,7 +825,11 @@ const void *RB_TakeVideoFrameCmd( const void *data ) size_t memcount, linelen; int padwidth, avipadwidth, padlen, avipadlen; GLint packAlign; - + + // finish any 2D drawing if needed + if(tess.numIndexes) + RB_EndSurface(); + cmd = (const videoFrameCommand_t *)data; qglGetIntegerv(GL_PACK_ALIGNMENT, &packAlign); @@ -940,6 +945,16 @@ void GL_SetDefaultState( void ) qglEnable( GL_SCISSOR_TEST ); qglDisable( GL_CULL_FACE ); qglDisable( GL_BLEND ); + + qglColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE ); + qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); + qglClearDepth( 1.0 ); + + qglDrawBuffer( GL_FRONT ); + qglClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_ACCUM_BUFFER_BIT|GL_STENCIL_BUFFER_BIT ); + + qglDrawBuffer( GL_BACK ); + qglClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_ACCUM_BUFFER_BIT|GL_STENCIL_BUFFER_BIT ); } /* @@ -1028,9 +1043,6 @@ void GfxInfo_f( void ) { ri.Printf( PRINT_ALL, "HACK: riva128 approximations\n" ); } - if ( glConfig.smpActive ) { - ri.Printf( PRINT_ALL, "Using dual processor acceleration\n" ); - } if ( r_finish->integer ) { ri.Printf( PRINT_ALL, "Forcing glFinish\n" ); } @@ -1142,7 +1154,6 @@ void R_Register( void ) r_vertexLight = ri.Cvar_Get( "r_vertexLight", "0", CVAR_ARCHIVE | CVAR_LATCH ); r_uiFullScreen = ri.Cvar_Get( "r_uifullscreen", "0", 0); r_subdivisions = ri.Cvar_Get ("r_subdivisions", "4", CVAR_ARCHIVE | CVAR_LATCH); - r_smp = ri.Cvar_Get( "r_smp", "0", CVAR_ARCHIVE | CVAR_LATCH); r_stereoEnabled = ri.Cvar_Get( "r_stereoEnabled", "0", CVAR_ARCHIVE | CVAR_LATCH); r_greyscale = ri.Cvar_Get("r_greyscale", "0", CVAR_ARCHIVE | CVAR_LATCH); ri.Cvar_CheckRange(r_greyscale, 0, 1, qfalse); @@ -1185,9 +1196,12 @@ void R_Register( void ) r_genNormalMaps = ri.Cvar_Get( "r_genNormalMaps", "0", CVAR_ARCHIVE | CVAR_LATCH ); r_forceSun = ri.Cvar_Get( "r_forceSun", "0", CVAR_CHEAT ); - r_forceSunMapLightScale = ri.Cvar_Get( "r_forceSunMapLightScale", "0.5", CVAR_CHEAT ); - r_forceSunLightScale = ri.Cvar_Get( "r_forceSunLightScale", "0.5", CVAR_CHEAT ); - r_forceSunAmbientScale = ri.Cvar_Get( "r_forceSunAmbientScale", "0.2", CVAR_CHEAT ); + r_forceSunMapLightScale = ri.Cvar_Get( "r_forceSunMapLightScale", "1.0", CVAR_CHEAT ); + r_forceSunLightScale = ri.Cvar_Get( "r_forceSunLightScale", "1.0", CVAR_CHEAT ); + r_forceSunAmbientScale = ri.Cvar_Get( "r_forceSunAmbientScale", "0.5", CVAR_CHEAT ); + r_drawSunRays = ri.Cvar_Get( "r_drawSunRays", "0", CVAR_ARCHIVE | CVAR_LATCH ); + r_sunlightMode = ri.Cvar_Get( "r_sunlightMode", "1", CVAR_ARCHIVE | CVAR_LATCH ); + r_sunShadows = ri.Cvar_Get( "r_sunShadows", "1", CVAR_ARCHIVE | CVAR_LATCH ); r_shadowFilter = ri.Cvar_Get( "r_shadowFilter", "1", CVAR_ARCHIVE | CVAR_LATCH ); r_shadowMapSize = ri.Cvar_Get( "r_shadowMapSize", "1024", CVAR_ARCHIVE | CVAR_LATCH ); @@ -1256,7 +1270,6 @@ void R_Register( void ) r_flareFade = ri.Cvar_Get ("r_flareFade", "7", CVAR_CHEAT); r_flareCoeff = ri.Cvar_Get ("r_flareCoeff", FLARE_STDCOEFF, CVAR_CHEAT); - r_showSmp = ri.Cvar_Get ("r_showSmp", "0", CVAR_CHEAT); r_skipBackEnd = ri.Cvar_Get ("r_skipBackEnd", "0", CVAR_CHEAT); r_measureOverdraw = ri.Cvar_Get( "r_measureOverdraw", "0", CVAR_CHEAT ); @@ -1310,9 +1323,8 @@ void R_InitQueries(void) if (!glRefConfig.occlusionQuery) return; -#ifdef REACTION - qglGenQueriesARB(ARRAY_LEN(tr.sunFlareQuery), tr.sunFlareQuery); -#endif + if (r_drawSunRays->integer) + qglGenQueriesARB(ARRAY_LEN(tr.sunFlareQuery), tr.sunFlareQuery); } void R_ShutDownQueries(void) @@ -1320,9 +1332,8 @@ void R_ShutDownQueries(void) if (!glRefConfig.occlusionQuery) return; -#ifdef REACTION - qglDeleteQueriesARB(ARRAY_LEN(tr.sunFlareQuery), tr.sunFlareQuery); -#endif + if (r_drawSunRays->integer) + qglDeleteQueriesARB(ARRAY_LEN(tr.sunFlareQuery), tr.sunFlareQuery); } /* @@ -1393,19 +1404,11 @@ void R_Init( void ) { if (max_polyverts < MAX_POLYVERTS) max_polyverts = MAX_POLYVERTS; - ptr = ri.Hunk_Alloc( sizeof( *backEndData[0] ) + sizeof(srfPoly_t) * max_polys + sizeof(polyVert_t) * max_polyverts, h_low); - backEndData[0] = (backEndData_t *) ptr; - backEndData[0]->polys = (srfPoly_t *) ((char *) ptr + sizeof( *backEndData[0] )); - backEndData[0]->polyVerts = (polyVert_t *) ((char *) ptr + sizeof( *backEndData[0] ) + sizeof(srfPoly_t) * max_polys); - if ( r_smp->integer ) { - ptr = ri.Hunk_Alloc( sizeof( *backEndData[1] ) + sizeof(srfPoly_t) * max_polys + sizeof(polyVert_t) * max_polyverts, h_low); - backEndData[1] = (backEndData_t *) ptr; - backEndData[1]->polys = (srfPoly_t *) ((char *) ptr + sizeof( *backEndData[1] )); - backEndData[1]->polyVerts = (polyVert_t *) ((char *) ptr + sizeof( *backEndData[1] ) + sizeof(srfPoly_t) * max_polys); - } else { - backEndData[1] = NULL; - } - R_ToggleSmpFrame(); + ptr = ri.Hunk_Alloc( sizeof( *backEndData ) + sizeof(srfPoly_t) * max_polys + sizeof(polyVert_t) * max_polyverts, h_low); + backEndData = (backEndData_t *) ptr; + backEndData->polys = (srfPoly_t *) ((char *) ptr + sizeof( *backEndData )); + backEndData->polyVerts = (polyVert_t *) ((char *) ptr + sizeof( *backEndData ) + sizeof(srfPoly_t) * max_polys); + R_InitNextFrame(); InitOpenGL(); @@ -1461,8 +1464,7 @@ void RE_Shutdown( qboolean destroyWindow ) { if ( tr.registered ) { - R_SyncRenderThread(); - R_ShutdownCommandBuffers(); + R_IssuePendingRenderCommands(); R_ShutDownQueries(); if (glRefConfig.framebufferObject) FBO_Shutdown(); @@ -1476,6 +1478,9 @@ void RE_Shutdown( qboolean destroyWindow ) { // shut down platform specific OpenGL stuff if ( destroyWindow ) { GLimp_Shutdown(); + + Com_Memset( &glConfig, 0, sizeof( glConfig ) ); + Com_Memset( &glState, 0, sizeof( glState ) ); } tr.registered = qfalse; @@ -1490,7 +1495,7 @@ Touch all images to make sure they are resident ============= */ void RE_EndRegistration( void ) { - R_SyncRenderThread(); + R_IssuePendingRenderCommands(); if (!ri.Sys_LowPhysicalMemory()) { RB_ShowImages(); } @@ -1504,7 +1509,7 @@ GetRefAPI @@@@@@@@@@@@@@@@@@@@@ */ #ifdef USE_RENDERER_DLOPEN -Q_EXPORT refexport_t QDECL *GetRefAPI ( int apiVersion, refimport_t *rimp ) { +Q_EXPORT refexport_t* QDECL GetRefAPI ( int apiVersion, refimport_t *rimp ) { #else refexport_t *GetRefAPI ( int apiVersion, refimport_t *rimp ) { #endif diff --git a/code/rend2/tr_light.c b/code/renderergl2/tr_light.c similarity index 97% rename from code/rend2/tr_light.c rename to code/renderergl2/tr_light.c index 9c15982a..a34d9bab 100644 --- a/code/rend2/tr_light.c +++ b/code/renderergl2/tr_light.c @@ -95,11 +95,11 @@ void R_DlightBmodel( bmodel_t *bmodel ) { surf = tr.world->surfaces + bmodel->firstSurface + i; if ( *surf->data == SF_FACE ) { - ((srfSurfaceFace_t *)surf->data)->dlightBits[ tr.smpFrame ] = mask; + ((srfSurfaceFace_t *)surf->data)->dlightBits = mask; } else if ( *surf->data == SF_GRID ) { - ((srfGridMesh_t *)surf->data)->dlightBits[ tr.smpFrame ] = mask; + ((srfGridMesh_t *)surf->data)->dlightBits = mask; } else if ( *surf->data == SF_TRIANGLES ) { - ((srfTriangles_t *)surf->data)->dlightBits[ tr.smpFrame ] = mask; + ((srfTriangles_t *)surf->data)->dlightBits = mask; } } } @@ -441,7 +441,11 @@ int R_LightDirForPoint( vec3_t point, vec3_t lightDir, vec3_t normal, world_t *w Com_Memset(&ent, 0, sizeof(ent)); VectorCopy( point, ent.e.origin ); R_SetupEntityLightingGrid( &ent, world ); - VectorCopy(ent.lightDir, lightDir); + + if (DotProduct(ent.lightDir, normal) > 0.2f) + VectorCopy(ent.lightDir, lightDir); + else + VectorCopy(normal, lightDir); return qtrue; -} \ No newline at end of file +} diff --git a/code/rend2/tr_local.h b/code/renderergl2/tr_local.h similarity index 87% rename from code/rend2/tr_local.h rename to code/renderergl2/tr_local.h index 3d756b79..144b16eb 100644 --- a/code/rend2/tr_local.h +++ b/code/renderergl2/tr_local.h @@ -27,24 +27,20 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "../qcommon/q_shared.h" #include "../qcommon/qfiles.h" #include "../qcommon/qcommon.h" -#include "../renderer/tr_public.h" +#include "../renderercommon/tr_public.h" +#include "../renderercommon/tr_common.h" #include "tr_extratypes.h" #include "tr_extramath.h" #include "tr_fbo.h" #include "tr_postprocess.h" -#include "qgl.h" -#include "../renderer/iqm.h" +#include "../renderercommon/iqm.h" +#include "../renderercommon/qgl.h" #define GL_INDEX_TYPE GL_UNSIGNED_INT typedef unsigned int glIndex_t; #define BUFFER_OFFSET(i) ((char *)NULL + (i)) -// everything that is needed by the backend needs -// to be double buffered to allow it to run in -// parallel on a dual cpu machine -#define SMP_FRAMES 2 - // 14 bits // can't be increased without changing bit packing for drawsurfs // see QSORT_SHADERNUM_SHIFT @@ -85,10 +81,7 @@ typedef struct { qboolean needDlights; // true for bmodels that touch a dlight qboolean lightingCalculated; -#ifdef REACTION - // JBravo: Mirrored models qboolean mirrored; // mirrored matrix, needs reversed culling -#endif vec3_t lightDir; // normalized direction towards light vec3_t ambientLight; // color normalized to 0-255 int ambientLightInt; // 32 bit rgba packed @@ -104,44 +97,6 @@ typedef struct { float transformMatrix[16]; } orientationr_t; -typedef enum -{ - IMGTYPE_COLORALPHA, // for color, lightmap, diffuse, and specular - IMGTYPE_NORMAL, - IMGTYPE_NORMALHEIGHT, - IMGTYPE_DELUXE, // normals are swizzled, deluxe are not -} imgType_t; - -typedef enum -{ - IMGFLAG_NONE = 0x0000, - IMGFLAG_MIPMAP = 0x0001, - IMGFLAG_PICMIP = 0x0002, - IMGFLAG_CUBEMAP = 0x0004, - IMGFLAG_NO_COMPRESSION = 0x0010, - IMGFLAG_NOLIGHTSCALE = 0x0020, - IMGFLAG_CLAMPTOEDGE = 0x0040, - IMGFLAG_SRGB = 0x0080, - IMGFLAG_GENNORMALMAP = 0x0100, -} imgFlags_t; - -typedef struct image_s { - char imgName[MAX_QPATH]; // game path, including extension - int width, height; // source image - int uploadWidth, uploadHeight; // after power of two and picmip but not including clamp to MAX_TEXTURE_SIZE - GLuint texnum; // gl texture binding - - int frameUsed; // for texture usage in frame statistics - - int internalFormat; - int TMU; // only needed for voodoo2 - - imgType_t type; - imgFlags_t flags; - - struct image_s* next; -} image_t; - typedef enum { VBO_USAGE_STATIC, @@ -407,12 +362,12 @@ enum TB_DIFFUSEMAP = 0, TB_LIGHTMAP = 1, TB_LEVELSMAP = 1, - TB_SHADOWMAP = 1, + TB_SHADOWMAP3 = 1, TB_NORMALMAP = 2, TB_DELUXEMAP = 3, TB_SHADOWMAP2 = 3, TB_SPECULARMAP = 4, - TB_SHADOWMAP3 = 5, + TB_SHADOWMAP = 5, NUM_TEXTURE_BUNDLES = 6 }; @@ -454,13 +409,6 @@ typedef struct { struct shaderCommands_s; -// any change in the LIGHTMAP_* defines here MUST be reflected in -// R_FindShader() in tr_bsp.c -#define LIGHTMAP_2D -4 // shader is for 2D rendering -#define LIGHTMAP_BY_VERTEX -3 // pre-lit triangle models -#define LIGHTMAP_WHITEIMAGE -2 -#define LIGHTMAP_NONE -1 - typedef enum { CT_FRONT_SIDED, CT_BACK_SIDED, @@ -770,7 +718,87 @@ enum GLSL_MAT16 }; -// Tr3B - shaderProgram_t represents a pair of one +typedef enum +{ + UNIFORM_DIFFUSEMAP = 0, + UNIFORM_LIGHTMAP, + UNIFORM_NORMALMAP, + UNIFORM_DELUXEMAP, + UNIFORM_SPECULARMAP, + + UNIFORM_TEXTUREMAP, + UNIFORM_LEVELSMAP, + + UNIFORM_SCREENIMAGEMAP, + UNIFORM_SCREENDEPTHMAP, + + UNIFORM_SHADOWMAP, + UNIFORM_SHADOWMAP2, + UNIFORM_SHADOWMAP3, + + UNIFORM_SHADOWMVP, + UNIFORM_SHADOWMVP2, + UNIFORM_SHADOWMVP3, + + UNIFORM_DIFFUSETEXMATRIX, + UNIFORM_DIFFUSETEXOFFTURB, + UNIFORM_TEXTURE1ENV, + + UNIFORM_TCGEN0, + UNIFORM_TCGEN0VECTOR0, + UNIFORM_TCGEN0VECTOR1, + + UNIFORM_DEFORMGEN, + UNIFORM_DEFORMPARAMS, + + UNIFORM_COLORGEN, + UNIFORM_ALPHAGEN, + UNIFORM_COLOR, + UNIFORM_BASECOLOR, + UNIFORM_VERTCOLOR, + + UNIFORM_DLIGHTINFO, + UNIFORM_LIGHTFORWARD, + UNIFORM_LIGHTUP, + UNIFORM_LIGHTRIGHT, + UNIFORM_LIGHTORIGIN, + UNIFORM_LIGHTRADIUS, + UNIFORM_AMBIENTLIGHT, + UNIFORM_DIRECTEDLIGHT, + + UNIFORM_PORTALRANGE, + + UNIFORM_FOGDISTANCE, + UNIFORM_FOGDEPTH, + UNIFORM_FOGEYET, + UNIFORM_FOGCOLORMASK, + + UNIFORM_MODELMATRIX, + UNIFORM_MODELVIEWPROJECTIONMATRIX, + + UNIFORM_TIME, + UNIFORM_VERTEXLERP, + UNIFORM_MATERIALINFO, + + UNIFORM_VIEWINFO, // znear, zfar, width/2, height/2 + UNIFORM_VIEWORIGIN, + UNIFORM_VIEWFORWARD, + UNIFORM_VIEWLEFT, + UNIFORM_VIEWUP, + + UNIFORM_INVTEXRES, + UNIFORM_AUTOEXPOSUREMINMAX, + UNIFORM_TONEMINAVGMAXLINEAR, + + UNIFORM_PRIMARYLIGHTORIGIN, + UNIFORM_PRIMARYLIGHTCOLOR, + UNIFORM_PRIMARYLIGHTAMBIENT, + UNIFORM_PRIMARYLIGHTRADIUS, + + UNIFORM_COUNT +} uniform_t; + +// shaderProgram_t represents a pair of one // GLSL vertex and one GLSL fragment shader typedef struct shaderProgram_s { @@ -782,146 +810,11 @@ typedef struct shaderProgram_s uint32_t attribs; // vertex array attributes // uniform parameters - int numUniforms; - GLint *uniforms; - char *uniformTypes; // max 127 uniform types - short *uniformBufferOffsets; // max 32767/64=511 uniforms + GLint uniforms[UNIFORM_COUNT]; + short uniformBufferOffsets[UNIFORM_COUNT]; // max 32767/64=511 uniforms char *uniformBuffer; } shaderProgram_t; - -enum -{ - TEXTURECOLOR_UNIFORM_MODELVIEWPROJECTIONMATRIX = 0, - TEXTURECOLOR_UNIFORM_INVTEXRES, - TEXTURECOLOR_UNIFORM_AUTOEXPOSUREMINMAX, - TEXTURECOLOR_UNIFORM_TONEMINAVGMAXLINEAR, - TEXTURECOLOR_UNIFORM_TEXTUREMAP, - TEXTURECOLOR_UNIFORM_LEVELSMAP, - TEXTURECOLOR_UNIFORM_COLOR, - TEXTURECOLOR_UNIFORM_COUNT -}; - - -enum -{ - FOGPASS_UNIFORM_FOGDISTANCE = 0, - FOGPASS_UNIFORM_FOGDEPTH, - FOGPASS_UNIFORM_FOGEYET, - FOGPASS_UNIFORM_DEFORMGEN, - FOGPASS_UNIFORM_DEFORMPARAMS, - FOGPASS_UNIFORM_TIME, - FOGPASS_UNIFORM_COLOR, - FOGPASS_UNIFORM_MODELVIEWPROJECTIONMATRIX, - FOGPASS_UNIFORM_VERTEXLERP, - FOGPASS_UNIFORM_COUNT -}; - - -enum -{ - DLIGHT_UNIFORM_DIFFUSEMAP = 0, - DLIGHT_UNIFORM_DLIGHTINFO, - DLIGHT_UNIFORM_DEFORMGEN, - DLIGHT_UNIFORM_DEFORMPARAMS, - DLIGHT_UNIFORM_TIME, - DLIGHT_UNIFORM_COLOR, - DLIGHT_UNIFORM_MODELVIEWPROJECTIONMATRIX, - DLIGHT_UNIFORM_VERTEXLERP, - DLIGHT_UNIFORM_COUNT -}; - - -enum -{ - PSHADOW_UNIFORM_SHADOWMAP = 0, - PSHADOW_UNIFORM_MODELVIEWPROJECTIONMATRIX, - PSHADOW_UNIFORM_LIGHTFORWARD, - PSHADOW_UNIFORM_LIGHTUP, - PSHADOW_UNIFORM_LIGHTRIGHT, - PSHADOW_UNIFORM_LIGHTORIGIN, - PSHADOW_UNIFORM_LIGHTRADIUS, - PSHADOW_UNIFORM_COUNT -}; - - -enum -{ - GENERIC_UNIFORM_DIFFUSEMAP = 0, - GENERIC_UNIFORM_LIGHTMAP, - GENERIC_UNIFORM_NORMALMAP, - GENERIC_UNIFORM_DELUXEMAP, - GENERIC_UNIFORM_SPECULARMAP, - GENERIC_UNIFORM_SHADOWMAP, - GENERIC_UNIFORM_DIFFUSETEXMATRIX, - GENERIC_UNIFORM_DIFFUSETEXOFFTURB, - //GENERIC_UNIFORM_NORMALTEXMATRIX, - //GENERIC_UNIFORM_SPECULARTEXMATRIX, - GENERIC_UNIFORM_TEXTURE1ENV, - GENERIC_UNIFORM_VIEWORIGIN, - GENERIC_UNIFORM_TCGEN0, - GENERIC_UNIFORM_TCGEN0VECTOR0, - GENERIC_UNIFORM_TCGEN0VECTOR1, - GENERIC_UNIFORM_DEFORMGEN, - GENERIC_UNIFORM_DEFORMPARAMS, - GENERIC_UNIFORM_COLORGEN, - GENERIC_UNIFORM_ALPHAGEN, - GENERIC_UNIFORM_BASECOLOR, - GENERIC_UNIFORM_VERTCOLOR, - GENERIC_UNIFORM_AMBIENTLIGHT, - GENERIC_UNIFORM_DIRECTEDLIGHT, - GENERIC_UNIFORM_LIGHTORIGIN, - GENERIC_UNIFORM_LIGHTRADIUS, - GENERIC_UNIFORM_PORTALRANGE, - GENERIC_UNIFORM_FOGDISTANCE, - GENERIC_UNIFORM_FOGDEPTH, - GENERIC_UNIFORM_FOGEYET, - GENERIC_UNIFORM_FOGCOLORMASK, - GENERIC_UNIFORM_MODELMATRIX, - GENERIC_UNIFORM_MODELVIEWPROJECTIONMATRIX, - GENERIC_UNIFORM_TIME, - GENERIC_UNIFORM_VERTEXLERP, - GENERIC_UNIFORM_MATERIALINFO, - GENERIC_UNIFORM_COUNT -}; - -enum -{ - SHADOWMASK_UNIFORM_SCREENDEPTHMAP = 0, - SHADOWMASK_UNIFORM_SHADOWMAP, - SHADOWMASK_UNIFORM_SHADOWMAP2, - SHADOWMASK_UNIFORM_SHADOWMAP3, - SHADOWMASK_UNIFORM_SHADOWMVP, - SHADOWMASK_UNIFORM_SHADOWMVP2, - SHADOWMASK_UNIFORM_SHADOWMVP3, - SHADOWMASK_UNIFORM_VIEWORIGIN, - SHADOWMASK_UNIFORM_VIEWINFO, // znear, zfar, width/2, height/2 - SHADOWMASK_UNIFORM_VIEWFORWARD, - SHADOWMASK_UNIFORM_VIEWLEFT, - SHADOWMASK_UNIFORM_VIEWUP, - SHADOWMASK_UNIFORM_COUNT -}; - -enum -{ - SSAO_UNIFORM_SCREENDEPTHMAP = 0, - SSAO_UNIFORM_VIEWINFO, // znear, zfar, width/2, height/2 - SSAO_UNIFORM_COUNT -}; - -enum -{ - DEPTHBLUR_UNIFORM_SCREENIMAGEMAP = 0, - DEPTHBLUR_UNIFORM_SCREENDEPTHMAP, - DEPTHBLUR_UNIFORM_VIEWINFO, // znear, zfar, width/2, height/2 - DEPTHBLUR_UNIFORM_COUNT -}; - -// -// Tr3B: these are fire wall functions to avoid expensive redundant glUniform* calls -//#define USE_UNIFORM_FIREWALL 1 -//#define LOG_GLSL_UNIFORMS 1 - // trRefdef_t holds everything that comes in refdef_t, // as well as the locally generated scene information typedef struct { @@ -1002,12 +895,13 @@ typedef struct { } fog_t; typedef enum { - VPF_NONE = 0x00, - VPF_SHADOWMAP = 0x01, - VPF_DEPTHSHADOW = 0x02, - VPF_DEPTHCLAMP = 0x04, - VPF_ORTHOGRAPHIC = 0x08, - VPF_USESUNLIGHT = 0x10, + VPF_NONE = 0x00, + VPF_SHADOWMAP = 0x01, + VPF_DEPTHSHADOW = 0x02, + VPF_DEPTHCLAMP = 0x04, + VPF_ORTHOGRAPHIC = 0x08, + VPF_USESUNLIGHT = 0x10, + VPF_FARPLANEFRUSTUM = 0x20 } viewParmFlags_t; typedef struct { @@ -1051,9 +945,7 @@ typedef enum { SF_POLY, SF_MDV, SF_MD4, -#ifdef RAVENMD4 SF_MDR, -#endif SF_IQM, SF_FLARE, SF_ENTITY, // beams, rails, lightning, etc that can be determined by entity @@ -1137,8 +1029,8 @@ typedef struct srfGridMesh_s surfaceType_t surfaceType; // dynamic lighting information - int dlightBits[SMP_FRAMES]; - int pshadowBits[SMP_FRAMES]; + int dlightBits; + int pshadowBits; // culling information vec3_t meshBounds[2]; @@ -1181,8 +1073,8 @@ typedef struct surfaceType_t surfaceType; // dynamic lighting information - int dlightBits[SMP_FRAMES]; - int pshadowBits[SMP_FRAMES]; + int dlightBits; + int pshadowBits; // culling information cplane_t plane; @@ -1213,8 +1105,8 @@ typedef struct surfaceType_t surfaceType; // dynamic lighting information - int dlightBits[SMP_FRAMES]; - int pshadowBits[SMP_FRAMES]; + int dlightBits; + int pshadowBits; // culling information // vec3_t bounds[2]; @@ -1256,6 +1148,7 @@ typedef struct { int *triangles; int *jointParents; + float *jointMats; float *poseMats; float *bounds; char *names; @@ -1279,8 +1172,8 @@ typedef struct srfVBOMesh_s int fogIndex; // dynamic lighting information - int dlightBits[SMP_FRAMES]; - int pshadowBits[SMP_FRAMES]; + int dlightBits; + int pshadowBits; // culling information vec3_t bounds[2]; @@ -1555,9 +1448,7 @@ typedef enum { MOD_BRUSH, MOD_MESH, MOD_MD4, -#ifdef RAVENMD4 MOD_MDR, -#endif MOD_IQM } modtype_t; @@ -1586,7 +1477,6 @@ void R_ModelBounds( qhandle_t handle, vec3_t mins, vec3_t maxs ); void R_Modellist_f (void); //==================================================== -extern refimport_t ri; #define MAX_DRAWIMAGES 2048 #define MAX_SKINS 1024 @@ -1751,7 +1641,6 @@ typedef struct { // all state modified by the back end is seperated // from the front end state typedef struct { - int smpFrame; trRefdef_t refdef; viewParms_t viewParms; orientationr_t or; @@ -1760,12 +1649,6 @@ typedef struct { trRefEntity_t *currentEntity; qboolean skyRenderedThisView; // flag for drawing sun -#ifdef REACTION - vec3_t sunFlarePos; - qboolean viewHasSunFlare; - qboolean frameHasSunFlare; -#endif - qboolean projection2D; // if qtrue, drawstretchpic doesn't need to change modes byte color2D[4]; qboolean vertexes2D; // shader needs to be finished @@ -1797,8 +1680,6 @@ typedef struct { int viewCount; // incremented every view (twice a scene if portaled) // and every R_MarkFragments call - int smpFrame; // toggles from 0 to 1 every endFrame - int frameSceneNum; // zeroed at RE_BeginFrame qboolean worldMapLoaded; @@ -1821,7 +1702,7 @@ typedef struct { image_t *renderImage; - image_t *godRaysImage; + image_t *sunRaysImage; image_t *renderDepthImage; image_t *pshadowMaps[MAX_DRAWN_PSHADOWS]; image_t *textureScratchImage[2]; @@ -1839,7 +1720,7 @@ typedef struct { FBO_t *renderFbo; FBO_t *msaaResolveFbo; - FBO_t *godRaysFbo; + FBO_t *sunRaysFbo; FBO_t *depthFbo; FBO_t *pshadowFbos[MAX_DRAWN_PSHADOWS]; FBO_t *textureScratchFbo[2]; @@ -1858,6 +1739,7 @@ typedef struct { shader_t *flareShader; shader_t *sunShader; + shader_t *sunFlareShader; int numLightmaps; int lightmapSize; @@ -1907,10 +1789,10 @@ typedef struct { int viewCluster; float mapLightScale; + float sunShadowScale; qboolean sunShadows; vec3_t sunLight; // from the sky shader for this level - vec3_t sunAmbient; vec3_t sunDirection; frontEndCounters_t pc; @@ -1945,11 +1827,9 @@ typedef struct { int numSkins; skin_t *skins[MAX_SKINS]; -#ifdef REACTION GLuint sunFlareQuery[2]; int sunFlareQueryIndex; qboolean sunFlareQueryActive[2]; -#endif float sinTable[FUNCTABLE_SIZE]; float squareTable[FUNCTABLE_SIZE]; @@ -1961,17 +1841,8 @@ typedef struct { extern backEndState_t backEnd; extern trGlobals_t tr; -extern glconfig_t glConfig; // outside of TR since it shouldn't be cleared during ref re-init extern glstate_t glState; // outside of TR since it shouldn't be cleared during ref re-init - -// These three variables should live inside glConfig but can't because of compatibility issues to the original ID vms. -// If you release a stand-alone game and your mod uses tr_types.h from this build you can safely move them to -// the glconfig_t struct. -extern qboolean textureFilterAnisotropic; -extern int maxAnisotropy; extern glRefConfig_t glRefConfig; -extern float displayAspect; - // // cvars @@ -1993,16 +1864,6 @@ extern cvar_t *r_znear; // near Z clip plane extern cvar_t *r_zproj; // z distance of projection plane extern cvar_t *r_stereoSeparation; // separation of cameras for stereo rendering -extern cvar_t *r_stencilbits; // number of desired stencil bits -extern cvar_t *r_depthbits; // number of desired depth bits -extern cvar_t *r_colorbits; // number of desired color bits, only relevant for fullscreen -extern cvar_t *r_texturebits; // number of desired texture bits -extern cvar_t *r_ext_multisample; - // 0 = use framebuffer depth - // 16 = use 16-bit textures - // 32 = use 32-bit textures - // all else = error - extern cvar_t *r_measureOverdraw; // enables stencil buffer overdraw measurement extern cvar_t *r_lodbias; // push/pull LOD transitions @@ -2025,20 +1886,7 @@ extern cvar_t *r_facePlaneCull; // enables culling of planar surfaces with back extern cvar_t *r_nocurves; extern cvar_t *r_showcluster; -extern cvar_t *r_mode; // video mode -extern cvar_t *r_fullscreen; -extern cvar_t *r_noborder; extern cvar_t *r_gamma; -extern cvar_t *r_ignorehwgamma; // overrides hardware gamma capabilities - -extern cvar_t *r_allowExtensions; // global enable/disable of OpenGL extensions -extern cvar_t *r_ext_compressed_textures; // these control use of specific extensions -extern cvar_t *r_ext_multitexture; -extern cvar_t *r_ext_compiled_vertex_array; -extern cvar_t *r_ext_texture_env_add; - -extern cvar_t *r_ext_texture_filter_anisotropic; -extern cvar_t *r_ext_max_anisotropy; extern cvar_t *r_ext_draw_range_elements; extern cvar_t *r_ext_multi_draw_arrays; @@ -2053,8 +1901,6 @@ extern cvar_t *r_roundImagesDown; extern cvar_t *r_colorMipLevels; // development aid to see texture mip usage extern cvar_t *r_picmip; // controls picmip values extern cvar_t *r_finish; -extern cvar_t *r_drawBuffer; -extern cvar_t *r_swapInterval; extern cvar_t *r_textureMode; extern cvar_t *r_offsetFactor; extern cvar_t *r_offsetUnits; @@ -2081,11 +1927,8 @@ extern cvar_t *r_portalOnly; extern cvar_t *r_subdivisions; extern cvar_t *r_lodCurveError; -extern cvar_t *r_smp; -extern cvar_t *r_showSmp; extern cvar_t *r_skipBackEnd; -extern cvar_t *r_stereoEnabled; extern cvar_t *r_anaglyphMode; extern cvar_t *r_mergeMultidraws; @@ -2131,6 +1974,8 @@ extern cvar_t *r_forceSun; extern cvar_t *r_forceSunMapLightScale; extern cvar_t *r_forceSunLightScale; extern cvar_t *r_forceSunAmbientScale; +extern cvar_t *r_sunlightMode; +extern cvar_t *r_drawSunRays; extern cvar_t *r_sunShadows; extern cvar_t *r_shadowFilter; extern cvar_t *r_shadowMapSize; @@ -2152,15 +1997,11 @@ extern cvar_t *r_showImages; extern cvar_t *r_debugSort; extern cvar_t *r_printShaders; -extern cvar_t *r_saveFontData; extern cvar_t *r_marksOnTriangleMeshes; //==================================================================== -float R_NoiseGet4f( float x, float y, float z, float t ); -void R_NoiseInit( void ); - void R_SwapBuffers( int ); void R_RenderView( viewParms_t *parms ); @@ -2272,10 +2113,7 @@ qboolean R_GetEntityToken( char *buffer, int size ); model_t *R_AllocModel( void ); void R_Init( void ); -image_t *R_FindImageFile( const char *name, imgType_t type, imgFlags_t flags ); -image_t *R_CreateImage( const char *name, byte *pic, int width, int height, imgType_t type, imgFlags_t flags, int internalFormat ); void R_UpdateSubImage( image_t *image, byte *pic, int x, int y, int width, int height ); -qboolean R_GetModeInfo( int *width, int *height, float *windowAspect, int mode ); void R_SetColorMappings( void ); void R_GammaCorrect( byte *buffer, int bufSize ); @@ -2301,11 +2139,6 @@ const void *RB_TakeVideoFrameCmd( const void *data ); // // tr_shader.c // -qhandle_t RE_RegisterShaderLightMap( const char *name, int lightmapIndex ); -qhandle_t RE_RegisterShader( const char *name ); -qhandle_t RE_RegisterShaderNoMip( const char *name ); -qhandle_t RE_RegisterShaderFromImage(const char *name, int lightmapIndex, image_t *image, qboolean mipRawImage); - shader_t *R_FindShader( const char *name, int lightmapIndex, qboolean mipRawImage ); shader_t *R_GetShaderByHandle( qhandle_t hShader ); shader_t *R_GetShaderByState( int index, long *cycleTime ); @@ -2322,26 +2155,8 @@ IMPLEMENTATION SPECIFIC FUNCTIONS ==================================================================== */ -void GLimp_Init( void ); -void GLimp_Shutdown( void ); -void GLimp_EndFrame( void ); - -qboolean GLimp_SpawnRenderThread( void (*function)( void ) ); -void *GLimp_RendererSleep( void ); -void GLimp_FrontEndSleep( void ); -void GLimp_WakeRenderer( void *data ); - -void GLimp_LogComment( char *comment ); -void GLimp_Minimize(void); - -// NOTE TTimo linux works with float gamma value, not the gamma table -// the params won't be used, getting the r_gamma cvar directly -void GLimp_SetGamma( unsigned char red[256], - unsigned char green[256], - unsigned char blue[256] ); - - void GLimp_InitExtraExtensions( void ); + /* ==================================================================== @@ -2493,7 +2308,7 @@ SKIES void R_BuildCloudData( shaderCommands_t *shader ); void R_InitSkyTexCoords( float cloudLayerHeight ); void R_DrawSkyBox( shaderCommands_t *shader ); -void RB_DrawSun( void ); +void RB_DrawSun( float scale, shader_t *shader ); void RB_ClipSkyPolygons( shaderCommands_t *shader ); /* @@ -2565,8 +2380,6 @@ void GLSL_VertexAttribPointers(uint32_t attribBits); void GLSL_BindProgram(shaderProgram_t * program); void GLSL_BindNullProgram(void); -void GLSL_SetNumUniforms(shaderProgram_t *program, int numUniforms); -void GLSL_SetUniformName(shaderProgram_t *program, int uniformNum, const char *name); void GLSL_SetUniformInt(shaderProgram_t *program, int uniformNum, GLint value); void GLSL_SetUniformFloat(shaderProgram_t *program, int uniformNum, GLfloat value); void GLSL_SetUniformFloat5(shaderProgram_t *program, int uniformNum, const vec5_t v); @@ -2585,7 +2398,7 @@ SCENE GENERATION ============================================================ */ -void R_ToggleSmpFrame( void ); +void R_InitNextFrame( void ); void RE_ClearScene( void ); void RE_AddRefEntityToScene( const refEntity_t *ent ); @@ -2594,7 +2407,6 @@ void RE_AddLightToScene( const vec3_t org, float intensity, float r, float g, fl void RE_AddAdditiveLightToScene( const vec3_t org, float intensity, float r, float g, float b ); void RE_RenderScene( const refdef_t *fd ); -#ifdef RAVENMD4 /* ============================================================= @@ -2613,7 +2425,6 @@ UNCOMPRESSING BONES #define MC_SCALE_Z (1.0f/64) void MC_UnCompress(float mat[3][4],const unsigned char * comp); -#endif /* ============================================================= @@ -2626,10 +2437,8 @@ ANIMATED MODELS // void R_MakeAnimModel( model_t *model ); haven't seen this one really, so not needed I guess. void R_AddAnimSurfaces( trRefEntity_t *ent ); void RB_SurfaceAnim( md4Surface_t *surfType ); -#ifdef RAVENMD4 void R_MDRAddAnimSurfaces( trRefEntity_t *ent ); void RB_MDRSurfaceAnim( md4Surface_t *surface ); -#endif qboolean R_LoadIQM (model_t *mod, void *buffer, int filesize, const char *name ); void R_AddIQMSurfaces( trRefEntity_t *ent ); void RB_IQMSurfaceAnim( surfaceType_t *surface ); @@ -2699,7 +2508,6 @@ RENDERER BACK END FUNCTIONS ============================================================= */ -void RB_RenderThread( void ); void RB_ExecuteRenderCommands( const void *data ); /* @@ -2827,9 +2635,7 @@ typedef enum { #define MAX_POLYVERTS 3000 // all of the information needed by the back end must be -// contained in a backEndData_t. This entire structure is -// duplicated so the front and back end can run in parallel -// on an SMP machine +// contained in a backEndData_t typedef struct { drawSurf_t drawSurfs[MAX_DRAWSURFS]; dlight_t dlights[MAX_DLIGHTS]; @@ -2843,20 +2649,13 @@ typedef struct { extern int max_polys; extern int max_polyverts; -extern backEndData_t *backEndData[SMP_FRAMES]; // the second one may not be allocated - -extern volatile renderCommandList_t *renderCommandList; - -extern volatile qboolean renderThreadActive; +extern backEndData_t *backEndData; // the second one may not be allocated void *R_GetCommandBuffer( int bytes ); void RB_ExecuteRenderCommands( const void *data ); -void R_InitCommandBuffers( void ); -void R_ShutdownCommandBuffers( void ); - -void R_SyncRenderThread( void ); +void R_IssuePendingRenderCommands( void ); void R_AddDrawSurfCmd( drawSurf_t *drawSurfs, int numDrawSurfs ); void R_AddCapShadowmapCmd( int dlight, int cubeSide ); @@ -2874,10 +2673,5 @@ size_t RE_SaveJPGToBuffer(byte *buffer, size_t bufSize, int quality, void RE_TakeVideoFrame( int width, int height, byte *captureBuffer, byte *encodeBuffer, qboolean motionJpeg ); -// font stuff -void R_InitFreeType( void ); -void R_DoneFreeType( void ); -void RE_RegisterFont(const char *fontName, int pointSize, fontInfo_t *font); - #endif //TR_LOCAL_H diff --git a/code/rend2/tr_main.c b/code/renderergl2/tr_main.c similarity index 99% rename from code/rend2/tr_main.c rename to code/renderergl2/tr_main.c index f91c943a..b67c5fa4 100644 --- a/code/rend2/tr_main.c +++ b/code/renderergl2/tr_main.c @@ -495,7 +495,8 @@ qboolean R_CalcTangentVectors(srfVert_t * dv[3]) /* ================= R_FindSurfaceTriangleWithEdge -Tr3B - recoded from Q2E + +Recoded from Q2E ================= */ static int R_FindSurfaceTriangleWithEdge(int numTriangles, srfTriangle_t * triangles, int start, int end, int ignore) @@ -539,7 +540,8 @@ static int R_FindSurfaceTriangleWithEdge(int numTriangles, srfTriangle_t * trian /* ================= R_CalcSurfaceTriangleNeighbors -Tr3B - recoded from Q2E + +Recoded from Q2E ================= */ void R_CalcSurfaceTriangleNeighbors(int numTriangles, srfTriangle_t * triangles) @@ -685,11 +687,13 @@ int R_CullBox(vec3_t worldBounds[2]) { int i; cplane_t *frust; qboolean anyClip; - int r; + int r, numPlanes; + + numPlanes = (tr.viewParms.flags & VPF_FARPLANEFRUSTUM) ? 5 : 4; // check against frustum planes anyClip = qfalse; - for(i = 0; i < 4 /*FRUSTUM_PLANES*/; i++) + for(i = 0; i < numPlanes; i++) { frust = &tr.viewParms.frustum[i]; @@ -771,7 +775,7 @@ int R_CullPointAndRadiusEx( const vec3_t pt, float radius, const cplane_t* frust */ int R_CullPointAndRadius( const vec3_t pt, float radius ) { - return R_CullPointAndRadiusEx(pt, radius, tr.viewParms.frustum, ARRAY_LEN(tr.viewParms.frustum)); + return R_CullPointAndRadiusEx(pt, radius, tr.viewParms.frustum, (tr.viewParms.flags & VPF_FARPLANEFRUSTUM) ? 5 : 4); } /* @@ -1132,6 +1136,7 @@ void R_SetupFrustum (viewParms_t *dest, float xmin, float xmax, float ymax, floa dest->frustum[4].type = PLANE_NON_AXIAL; dest->frustum[4].dist = DotProduct (farpoint, dest->frustum[4].normal); SetPlaneSignbits( &dest->frustum[4] ); + dest->flags |= VPF_FARPLANEFRUSTUM; } } @@ -1316,6 +1321,8 @@ void R_SetupProjectionOrtho(viewParms_t *dest, vec3_t viewBounds[2]) dest->frustum[i].type = PLANE_NON_AXIAL; SetPlaneSignbits (&dest->frustum[i]); } + + dest->flags |= VPF_FARPLANEFRUSTUM; } /* @@ -1550,10 +1557,6 @@ static qboolean IsMirror( const drawSurf_t *drawSurf, int entityNum ) // translate the original plane originalPlane.dist = originalPlane.dist + DotProduct( originalPlane.normal, tr.or.origin ); } - else - { - plane = originalPlane; - } // locate the portal entity closest to this plane. // origin will be the origin of the portal, origin2 will be @@ -1601,10 +1604,6 @@ static qboolean SurfIsOffscreen( const drawSurf_t *drawSurf, vec4_t clipDest[128 unsigned int pointOr = 0; unsigned int pointAnd = (unsigned int)~0; - if ( glConfig.smpActive ) { // FIXME! we can't do RB_BeginSurface/RB_EndSurface stuff with smp! - return qfalse; - } - R_RotateForViewer(); R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted, &pshadowed ); @@ -1719,6 +1718,8 @@ qboolean R_MirrorViewBySurface (drawSurf_t *drawSurf, int entityNum) { newParms = tr.viewParms; newParms.isPortal = qtrue; + newParms.zFar = 0.0f; + newParms.flags &= ~VPF_FARPLANEFRUSTUM; if ( !R_GetPortalOrientations( drawSurf, entityNum, &surface, &camera, newParms.pvsOrigin, &newParms.isMirror ) ) { return qfalse; // bad portal, no portalentity @@ -1996,11 +1997,9 @@ static void R_AddEntitySurface (int entityNum) case MOD_MD4: R_AddAnimSurfaces( ent ); break; -#ifdef RAVENMD4 case MOD_MDR: R_MDRAddAnimSurfaces( ent ); break; -#endif case MOD_IQM: R_AddIQMSurfaces( ent ); break; @@ -2115,8 +2114,7 @@ void R_DebugGraphics( void ) { return; } - // the render thread can't make callbacks to the main thread - R_SyncRenderThread(); + R_IssuePendingRenderCommands(); GL_Bind( tr.whiteImage); GL_Cull( CT_FRONT_SIDED ); @@ -2291,7 +2289,6 @@ void R_RenderPshadowMaps(const refdef_t *fd) radius = r_pshadowDist->value / 2.0f; } break; -#ifdef RAVENMD4 case MOD_MDR: { // FIXME: never actually tested this @@ -2302,7 +2299,6 @@ void R_RenderPshadowMaps(const refdef_t *fd) radius = frame->radius; } break; -#endif case MOD_IQM: { // FIXME: never actually tested this @@ -2572,6 +2568,8 @@ void R_RenderPshadowMaps(const refdef_t *fd) dest->frustum[j].type = PLANE_NON_AXIAL; SetPlaneSignbits (&dest->frustum[j]); } + + dest->flags |= VPF_FARPLANEFRUSTUM; } for (j = 0; j < shadow->numEntities; j++) diff --git a/code/rend2/tr_marks.c b/code/renderergl2/tr_marks.c similarity index 99% rename from code/rend2/tr_marks.c rename to code/renderergl2/tr_marks.c index f24459e2..4d070565 100644 --- a/code/rend2/tr_marks.c +++ b/code/renderergl2/tr_marks.c @@ -41,8 +41,8 @@ Out must have space for two more vertexes than in static void R_ChopPolyBehindPlane( int numInPoints, vec3_t inPoints[MAX_VERTS_ON_POLY], int *numOutPoints, vec3_t outPoints[MAX_VERTS_ON_POLY], vec3_t normal, vec_t dist, vec_t epsilon) { - float dists[MAX_VERTS_ON_POLY+4]; - int sides[MAX_VERTS_ON_POLY+4]; + float dists[MAX_VERTS_ON_POLY+4] = { 0 }; + int sides[MAX_VERTS_ON_POLY+4] = { 0 }; int counts[3]; float dot; int i, j; diff --git a/code/rend2/tr_mesh.c b/code/renderergl2/tr_mesh.c similarity index 99% rename from code/rend2/tr_mesh.c rename to code/renderergl2/tr_mesh.c index 342854bf..28c2e5fb 100644 --- a/code/rend2/tr_mesh.c +++ b/code/renderergl2/tr_mesh.c @@ -168,10 +168,8 @@ int R_ComputeLOD( trRefEntity_t *ent ) { float flod, lodscale; float projectedRadius; mdvFrame_t *frame; -#ifdef RAVENMD4 mdrHeader_t *mdr; mdrFrame_t *mdrframe; -#endif int lod; if ( tr.currentModel->numLods < 2 ) @@ -184,7 +182,6 @@ int R_ComputeLOD( trRefEntity_t *ent ) { // multiple LODs exist, so compute projected bounding sphere // and use that as a criteria for selecting LOD -#ifdef RAVENMD4 if(tr.currentModel->type == MOD_MDR) { int frameSize; @@ -196,7 +193,6 @@ int R_ComputeLOD( trRefEntity_t *ent ) { radius = RadiusFromBounds(mdrframe->bounds[0], mdrframe->bounds[1]); } else -#endif { //frame = ( md3Frame_t * ) ( ( ( unsigned char * ) tr.currentModel->md3[0] ) + tr.currentModel->md3[0]->ofsFrames ); frame = tr.currentModel->mdv[0]->frames; diff --git a/code/rend2/tr_model.c b/code/renderergl2/tr_model.c similarity index 96% rename from code/rend2/tr_model.c rename to code/renderergl2/tr_model.c index b77e10a1..8feeab0e 100644 --- a/code/rend2/tr_model.c +++ b/code/renderergl2/tr_model.c @@ -27,9 +27,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA static qboolean R_LoadMD3(model_t *mod, int lod, void *buffer, int bufferSize, const char *modName); static qboolean R_LoadMD4(model_t *mod, void *buffer, const char *name ); -#ifdef RAVENMD4 static qboolean R_LoadMDR(model_t *mod, void *buffer, int filesize, const char *name ); -#endif /* ==================== @@ -117,7 +115,6 @@ qhandle_t R_RegisterMD3(const char *name, model_t *mod) return 0; } -#ifdef RAVENMD4 /* ==================== R_RegisterMDR @@ -155,7 +152,6 @@ qhandle_t R_RegisterMDR(const char *name, model_t *mod) return mod->index; } -#endif /* ==================== @@ -204,9 +200,7 @@ typedef struct static modelExtToLoaderMap_t modelLoaders[ ] = { { "iqm", R_RegisterIQM }, -#ifdef RAVENMD4 { "mdr", R_RegisterMDR }, -#endif { "md4", R_RegisterMD3 }, { "md3", R_RegisterMD3 } }; @@ -307,8 +301,7 @@ qhandle_t RE_RegisterModel( const char *name ) { Q_strncpyz( mod->name, name, sizeof( mod->name ) ); - // make sure the render thread is stopped - R_SyncRenderThread(); + R_IssuePendingRenderCommands(); mod->type = MOD_BAD; mod->numLods = 0; @@ -502,16 +495,18 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, int bufferSize, LL(md3Surf->ofsXyzNormals); LL(md3Surf->ofsEnd); - if(md3Surf->numVerts > SHADER_MAX_VERTEXES) + if(md3Surf->numVerts >= SHADER_MAX_VERTEXES) { - ri.Printf(PRINT_WARNING, "R_LoadMD3: %s has more than %i verts on a surface (%i)", - modName, SHADER_MAX_VERTEXES, md3Surf->numVerts); + ri.Printf(PRINT_WARNING, "R_LoadMD3: %s has more than %i verts on %s (%i).\n", + modName, SHADER_MAX_VERTEXES - 1, md3Surf->name[0] ? md3Surf->name : "a surface", + md3Surf->numVerts ); return qfalse; } - if(md3Surf->numTriangles * 3 > SHADER_MAX_INDEXES) + if(md3Surf->numTriangles * 3 >= SHADER_MAX_INDEXES) { - ri.Printf(PRINT_WARNING, "R_LoadMD3: %s has more than %i triangles on a surface (%i)", - modName, SHADER_MAX_INDEXES / 3, md3Surf->numTriangles); + ri.Printf(PRINT_WARNING, "R_LoadMD3: %s has more than %i triangles on %s (%i).\n", + modName, ( SHADER_MAX_INDEXES / 3 ) - 1, md3Surf->name[0] ? md3Surf->name : "a surface", + md3Surf->numTriangles ); return qfalse; } @@ -797,7 +792,6 @@ static qboolean R_LoadMD3(model_t * mod, int lod, void *buffer, int bufferSize, } -#ifdef RAVENMD4 /* ================= @@ -1002,16 +996,18 @@ static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char // numBoneReferences and BoneReferences generally seem to be unused // now do the checks that may fail. - if ( surf->numVerts > SHADER_MAX_VERTEXES ) + if ( surf->numVerts >= SHADER_MAX_VERTEXES ) { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has more than %i verts on a surface (%i).\n", - mod_name, SHADER_MAX_VERTEXES, surf->numVerts ); + ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has more than %i verts on %s (%i).\n", + mod_name, SHADER_MAX_VERTEXES - 1, surf->name[0] ? surf->name : "a surface", + surf->numVerts ); return qfalse; } - if ( surf->numTriangles*3 > SHADER_MAX_INDEXES ) + if ( surf->numTriangles*3 >= SHADER_MAX_INDEXES ) { - ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has more than %i triangles on a surface (%i).\n", - mod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles ); + ri.Printf(PRINT_WARNING, "R_LoadMDR: %s has more than %i triangles on %s (%i).\n", + mod_name, ( SHADER_MAX_INDEXES / 3 ) - 1, surf->name[0] ? surf->name : "a surface", + surf->numTriangles ); return qfalse; } // lowercase the surface name so skin compares are faster @@ -1136,7 +1132,6 @@ static qboolean R_LoadMDR( model_t *mod, void *buffer, int filesize, const char return qtrue; } -#endif /* ================= @@ -1218,14 +1213,16 @@ static qboolean R_LoadMD4( model_t *mod, void *buffer, const char *mod_name ) { LL(surf->ofsVerts); LL(surf->ofsEnd); - if ( surf->numVerts > SHADER_MAX_VERTEXES ) { - ri.Printf(PRINT_WARNING, "R_LoadMD4: %s has more than %i verts on a surface (%i).\n", - mod_name, SHADER_MAX_VERTEXES, surf->numVerts ); + if ( surf->numVerts >= SHADER_MAX_VERTEXES ) { + ri.Printf(PRINT_WARNING, "R_LoadMD4: %s has more than %i verts on %s (%i).\n", + mod_name, SHADER_MAX_VERTEXES - 1, surf->name[0] ? surf->name : "a surface", + surf->numVerts ); return qfalse; } - if ( surf->numTriangles*3 > SHADER_MAX_INDEXES ) { - ri.Printf(PRINT_WARNING, "R_LoadMD4: %s has more than %i triangles on a surface (%i).\n", - mod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles ); + if ( surf->numTriangles*3 >= SHADER_MAX_INDEXES ) { + ri.Printf(PRINT_WARNING, "R_LoadMD4: %s has more than %i triangles on %s (%i).\n", + mod_name, ( SHADER_MAX_INDEXES / 3 ) - 1, surf->name[0] ? surf->name : "a surface", + surf->numTriangles ); return qfalse; } @@ -1305,7 +1302,7 @@ void RE_BeginRegistration( glconfig_t *glconfigOut ) { *glconfigOut = glConfig; - R_SyncRenderThread(); + R_IssuePendingRenderCommands(); tr.visIndex = 0; memset(tr.visClusters, -2, sizeof(tr.visClusters)); // force markleafs to regenerate @@ -1403,8 +1400,7 @@ static mdvTag_t *R_GetTag( mdvModel_t *mod, int frame, const char *_tagName ) { return NULL; } -#ifdef RAVENMD4 -void R_GetAnimTag( mdrHeader_t *mod, int framenum, const char *tagName, md3Tag_t * dest) +void R_GetAnimTag( mdrHeader_t *mod, int framenum, const char *tagName, mdvTag_t * dest) { int i, j, k; int frameSize; @@ -1422,8 +1418,6 @@ void R_GetAnimTag( mdrHeader_t *mod, int framenum, const char *tagName, md3Tag_t { if ( !strcmp( tag->name, tagName ) ) { - Q_strncpyz(dest->name, tag->name, sizeof(dest->name)); - // uncompressed model... // frameSize = (intptr_t)( &((mdrFrame_t *)0)->bones[ mod->numBones ] ); @@ -1445,9 +1439,7 @@ void R_GetAnimTag( mdrHeader_t *mod, int framenum, const char *tagName, md3Tag_t AxisClear( dest->axis ); VectorClear( dest->origin ); - strcpy(dest->name,""); } -#endif /* ================ @@ -1457,9 +1449,7 @@ R_LerpTag int R_LerpTag( orientation_t *tag, qhandle_t handle, int startFrame, int endFrame, float frac, const char *tagName ) { mdvTag_t *start, *end; -#ifdef RAVENMD4 - md3Tag_t start_space, end_space; -#endif + mdvTag_t start_space, end_space; int i; float frontLerp, backLerp; model_t *model; @@ -1467,7 +1457,6 @@ int R_LerpTag( orientation_t *tag, qhandle_t handle, int startFrame, int endFram model = R_GetModelByHandle( handle ); if ( !model->mdv[0] ) { -#ifdef RAVENMD4 if(model->type == MOD_MDR) { start = &start_space; @@ -1475,9 +1464,7 @@ int R_LerpTag( orientation_t *tag, qhandle_t handle, int startFrame, int endFram R_GetAnimTag((mdrHeader_t *) model->modelData, startFrame, tagName, start); R_GetAnimTag((mdrHeader_t *) model->modelData, endFrame, tagName, end); } - else -#endif - if( model->type == MOD_IQM ) { + else if( model->type == MOD_IQM ) { return R_IQMLerpTag( tag, model->modelData, startFrame, endFrame, frac, tagName ); @@ -1553,7 +1540,6 @@ void R_ModelBounds( qhandle_t handle, vec3_t mins, vec3_t maxs ) { VectorCopy( frame->bounds[1], maxs ); return; -#ifdef RAVENMD4 } else if (model->type == MOD_MDR) { mdrHeader_t *header; mdrFrame_t *frame; @@ -1565,7 +1551,6 @@ void R_ModelBounds( qhandle_t handle, vec3_t mins, vec3_t maxs ) { VectorCopy( frame->bounds[1], maxs ); return; -#endif } else if(model->type == MOD_IQM) { iqmData_t *iqmData; diff --git a/code/rend2/tr_model_iqm.c b/code/renderergl2/tr_model_iqm.c similarity index 84% rename from code/rend2/tr_model_iqm.c rename to code/renderergl2/tr_model_iqm.c index 1f1bf747..30b8ff07 100644 --- a/code/rend2/tr_model_iqm.c +++ b/code/renderergl2/tr_model_iqm.c @@ -51,6 +51,11 @@ static void Matrix34Multiply( float *a, float *b, float *out ) { out[10] = a[8] * b[2] + a[9] * b[6] + a[10] * b[10]; out[11] = a[8] * b[3] + a[9] * b[7] + a[10] * b[11] + a[11]; } +static void Matrix34Multiply_OnlySetOrigin( float *a, float *b, float *out ) { + out[ 3] = a[0] * b[3] + a[1] * b[7] + a[ 2] * b[11] + a[ 3]; + out[ 7] = a[4] * b[3] + a[5] * b[7] + a[ 6] * b[11] + a[ 7]; + out[11] = a[8] * b[3] + a[9] * b[7] + a[10] * b[11] + a[11]; +} static void InterpolateMatrix( float *a, float *b, float lerp, float *mat ) { float unLerp = 1.0f - lerp; @@ -132,11 +137,12 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na unsigned short *framedata; char *str; int i, j; - float jointMats[IQM_MAX_JOINTS * 2 * 12]; - float *mat; + float jointInvMats[IQM_MAX_JOINTS * 12]; + float *mat, *matInv; size_t size, joint_names; iqmData_t *iqmData; srfIQModel_t *surface; + char meshName[MAX_QPATH]; if( filesize < sizeof(iqmHeader_t) ) { return qfalse; @@ -200,7 +206,7 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na } vertexarray = (iqmVertexArray_t *)((byte *)header + header->ofs_vertexarrays); for( i = 0; i < header->num_vertexarrays; i++, vertexarray++ ) { - int j, n, *intPtr; + int n, *intPtr; if( vertexarray->size <= 0 || vertexarray->size > 4 ) { return qfalse; @@ -305,17 +311,25 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na LL( mesh->first_triangle ); LL( mesh->num_triangles ); + if ( mesh->name < header->num_text ) { + Q_strncpyz( meshName, (char*)header + header->ofs_text + mesh->name, sizeof (meshName) ); + } else { + meshName[0] = '\0'; + } + // check ioq3 limits - if ( mesh->num_vertexes > SHADER_MAX_VERTEXES ) + if ( mesh->num_vertexes >= SHADER_MAX_VERTEXES ) { - ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has more than %i verts on a surface (%i).\n", - mod_name, SHADER_MAX_VERTEXES, mesh->num_vertexes ); + ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has more than %i verts on %s (%i).\n", + mod_name, SHADER_MAX_VERTEXES - 1, meshName[0] ? meshName : "a surface", + mesh->num_vertexes ); return qfalse; } - if ( mesh->num_triangles*3 > SHADER_MAX_INDEXES ) + if ( mesh->num_triangles*3 >= SHADER_MAX_INDEXES ) { - ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has more than %i triangles on a surface (%i).\n", - mod_name, SHADER_MAX_INDEXES / 3, mesh->num_triangles ); + ri.Printf(PRINT_WARNING, "R_LoadIQM: %s has more than %i triangles on %s (%i).\n", + mod_name, ( SHADER_MAX_INDEXES / 3 ) - 1, meshName[0] ? meshName : "a surface", + mesh->num_triangles ); return qfalse; } @@ -329,68 +343,73 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na } } - // check and swap joints - if( IQM_CheckRange( header, header->ofs_joints, - header->num_joints, sizeof(iqmJoint_t) ) ) { - return qfalse; - } - joint = (iqmJoint_t *)((byte *)header + header->ofs_joints); - joint_names = 0; - for( i = 0; i < header->num_joints; i++, joint++ ) { - LL( joint->name ); - LL( joint->parent ); - LL( joint->translate[0] ); - LL( joint->translate[1] ); - LL( joint->translate[2] ); - LL( joint->rotate[0] ); - LL( joint->rotate[1] ); - LL( joint->rotate[2] ); - LL( joint->rotate[3] ); - LL( joint->scale[0] ); - LL( joint->scale[1] ); - LL( joint->scale[2] ); - - if( joint->parent < -1 || - joint->parent >= (int)header->num_joints || - joint->name >= (int)header->num_text ) { - return qfalse; - } - joint_names += strlen( (char *)header + header->ofs_text + - joint->name ) + 1; - } - - // check and swap poses if( header->num_poses != header->num_joints ) { return qfalse; } - if( IQM_CheckRange( header, header->ofs_poses, - header->num_poses, sizeof(iqmPose_t) ) ) { - return qfalse; - } - pose = (iqmPose_t *)((byte *)header + header->ofs_poses); - for( i = 0; i < header->num_poses; i++, pose++ ) { - LL( pose->parent ); - LL( pose->mask ); - LL( pose->channeloffset[0] ); - LL( pose->channeloffset[1] ); - LL( pose->channeloffset[2] ); - LL( pose->channeloffset[3] ); - LL( pose->channeloffset[4] ); - LL( pose->channeloffset[5] ); - LL( pose->channeloffset[6] ); - LL( pose->channeloffset[7] ); - LL( pose->channeloffset[8] ); - LL( pose->channeloffset[9] ); - LL( pose->channelscale[0] ); - LL( pose->channelscale[1] ); - LL( pose->channelscale[2] ); - LL( pose->channelscale[3] ); - LL( pose->channelscale[4] ); - LL( pose->channelscale[5] ); - LL( pose->channelscale[6] ); - LL( pose->channelscale[7] ); - LL( pose->channelscale[8] ); - LL( pose->channelscale[9] ); + + joint_names = 0; + + if ( header->num_joints ) + { + // check and swap joints + if( IQM_CheckRange( header, header->ofs_joints, + header->num_joints, sizeof(iqmJoint_t) ) ) { + return qfalse; + } + joint = (iqmJoint_t *)((byte *)header + header->ofs_joints); + for( i = 0; i < header->num_joints; i++, joint++ ) { + LL( joint->name ); + LL( joint->parent ); + LL( joint->translate[0] ); + LL( joint->translate[1] ); + LL( joint->translate[2] ); + LL( joint->rotate[0] ); + LL( joint->rotate[1] ); + LL( joint->rotate[2] ); + LL( joint->rotate[3] ); + LL( joint->scale[0] ); + LL( joint->scale[1] ); + LL( joint->scale[2] ); + + if( joint->parent < -1 || + joint->parent >= (int)header->num_joints || + joint->name >= (int)header->num_text ) { + return qfalse; + } + joint_names += strlen( (char *)header + header->ofs_text + + joint->name ) + 1; + } + + // check and swap poses + if( IQM_CheckRange( header, header->ofs_poses, + header->num_poses, sizeof(iqmPose_t) ) ) { + return qfalse; + } + pose = (iqmPose_t *)((byte *)header + header->ofs_poses); + for( i = 0; i < header->num_poses; i++, pose++ ) { + LL( pose->parent ); + LL( pose->mask ); + LL( pose->channeloffset[0] ); + LL( pose->channeloffset[1] ); + LL( pose->channeloffset[2] ); + LL( pose->channeloffset[3] ); + LL( pose->channeloffset[4] ); + LL( pose->channeloffset[5] ); + LL( pose->channeloffset[6] ); + LL( pose->channeloffset[7] ); + LL( pose->channeloffset[8] ); + LL( pose->channeloffset[9] ); + LL( pose->channelscale[0] ); + LL( pose->channelscale[1] ); + LL( pose->channelscale[2] ); + LL( pose->channelscale[3] ); + LL( pose->channelscale[4] ); + LL( pose->channelscale[5] ); + LL( pose->channelscale[6] ); + LL( pose->channelscale[7] ); + LL( pose->channelscale[8] ); + LL( pose->channelscale[9] ); + } } if (header->ofs_bounds) @@ -418,7 +437,8 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na // allocate the model and copy the data size = sizeof(iqmData_t); size += header->num_meshes * sizeof( srfIQModel_t ); - size += header->num_joints * header->num_frames * 12 * sizeof( float ); + size += header->num_joints * 12 * sizeof( float ); // joint mats + size += header->num_joints * header->num_frames * 12 * sizeof( float ); // pose mats if(header->ofs_bounds) size += header->num_frames * 6 * sizeof(float); // model bounds size += header->num_vertexes * 3 * sizeof(float); // positions @@ -443,7 +463,8 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na iqmData->num_surfaces = header->num_meshes; iqmData->num_joints = header->num_joints; iqmData->surfaces = (srfIQModel_t *)(iqmData + 1); - iqmData->poseMats = (float *) (iqmData->surfaces + iqmData->num_surfaces); + iqmData->jointMats = (float *) (iqmData->surfaces + iqmData->num_surfaces); + iqmData->poseMats = iqmData->jointMats + 12 * header->num_joints; if(header->ofs_bounds) { iqmData->bounds = iqmData->poseMats + 12 * header->num_joints * header->num_frames; @@ -461,9 +482,13 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na iqmData->triangles = iqmData->jointParents + header->num_joints; iqmData->names = (char *)(iqmData->triangles + 3 * header->num_triangles); + if ( header->num_joints == 0 ) + iqmData->jointMats = iqmData->poseMats = NULL; + // calculate joint matrices and their inverses - // they are needed only until the pose matrices are calculated - mat = jointMats; + // joint inverses are needed only until the pose matrices are calculated + mat = iqmData->jointMats; + matInv = jointInvMats; joint = (iqmJoint_t *)((byte *)header + header->ofs_joints); for( i = 0; i < header->num_joints; i++, joint++ ) { float baseFrame[12], invBaseFrame[12]; @@ -473,17 +498,17 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na if ( joint->parent >= 0 ) { - Matrix34Multiply( jointMats + 2 * 12 * joint->parent, baseFrame, mat ); - mat += 12; - Matrix34Multiply( invBaseFrame, jointMats + 2 * 12 * joint->parent + 12, mat ); + Matrix34Multiply( iqmData->jointMats + 12 * joint->parent, baseFrame, mat ); mat += 12; + Matrix34Multiply( invBaseFrame, jointInvMats + 12 * joint->parent, matInv ); + matInv += 12; } else { Com_Memcpy( mat, baseFrame, sizeof(baseFrame) ); mat += 12; - Com_Memcpy( mat, invBaseFrame, sizeof(invBaseFrame) ); - mat += 12; + Com_Memcpy( matInv, invBaseFrame, sizeof(invBaseFrame) ); + matInv += 12; } } @@ -535,13 +560,13 @@ qboolean R_LoadIQM( model_t *mod, void *buffer, int filesize, const char *mod_na JointToMatrix( rotate, scale, translate, mat1 ); if( pose->parent >= 0 ) { - Matrix34Multiply( jointMats + 12 * 2 * pose->parent, + Matrix34Multiply( iqmData->jointMats + 12 * pose->parent, mat1, mat2 ); } else { Com_Memcpy( mat2, mat1, sizeof(mat1) ); } - Matrix34Multiply( mat2, jointMats + 12 * (2 * j + 1), mat ); + Matrix34Multiply( mat2, jointInvMats + 12 * j, mat ); mat += 12; } } @@ -861,7 +886,7 @@ void R_AddIQMSurfaces( trRefEntity_t *ent ) { } -static void ComputeJointMats( iqmData_t *data, int frame, int oldframe, +static void ComputePoseMats( iqmData_t *data, int frame, int oldframe, float backlerp, float *mat ) { float *mat1, *mat2; int *joint = data->jointParents; @@ -897,6 +922,23 @@ static void ComputeJointMats( iqmData_t *data, int frame, int oldframe, } } +static void ComputeJointMats( iqmData_t *data, int frame, int oldframe, + float backlerp, float *mat ) { + float *mat1; + int i; + + ComputePoseMats( data, frame, oldframe, backlerp, mat ); + + for( i = 0; i < data->num_joints; i++ ) { + float outmat[12]; + mat1 = mat + 12 * i; + + Com_Memcpy(outmat, mat1, sizeof(outmat)); + + Matrix34Multiply_OnlySetOrigin( outmat, data->jointMats + 12 * i, mat1 ); + } +} + /* ================= @@ -911,13 +953,13 @@ void RB_IQMSurfaceAnim( surfaceType_t *surface ) { float jointMats[IQM_MAX_JOINTS * 12]; int i; - vec4_t *outXYZ = &tess.xyz[tess.numVertexes]; - vec4_t *outNormal = &tess.normal[tess.numVertexes]; - vec2_t (*outTexCoord)[2] = &tess.texCoords[tess.numVertexes]; - vec4_t *outColor = &tess.vertexColors[tess.numVertexes]; + vec4_t *outXYZ; + vec4_t *outNormal; + vec2_t (*outTexCoord)[2]; + vec4_t *outColor; - int frame = backEnd.currentEntity->e.frame % data->num_frames; - int oldframe = backEnd.currentEntity->e.oldframe % data->num_frames; + int frame = data->num_frames ? backEnd.currentEntity->e.frame % data->num_frames : 0; + int oldframe = data->num_frames ? backEnd.currentEntity->e.oldframe % data->num_frames : 0; float backlerp = backEnd.currentEntity->e.backlerp; int *tri; @@ -926,8 +968,15 @@ void RB_IQMSurfaceAnim( surfaceType_t *surface ) { RB_CHECKOVERFLOW( surf->num_vertexes, surf->num_triangles * 3 ); + outXYZ = &tess.xyz[tess.numVertexes]; + outNormal = &tess.normal[tess.numVertexes]; + outTexCoord = &tess.texCoords[tess.numVertexes]; + outColor = &tess.vertexColors[tess.numVertexes]; + // compute interpolated joint matrices - ComputeJointMats( data, frame, oldframe, backlerp, jointMats ); + if ( data->num_joints > 0 ) { + ComputePoseMats( data, frame, oldframe, backlerp, jointMats ); + } // transform vertexes and fill other data for( i = 0; i < surf->num_vertexes; @@ -937,20 +986,28 @@ void RB_IQMSurfaceAnim( surfaceType_t *surface ) { float nrmMat[9]; int vtx = i + surf->first_vertex; - // compute the vertex matrix by blending the up to - // four blend weights - for( k = 0; k < 12; k++ ) - vtxMat[k] = data->blendWeights[4*vtx] - * jointMats[12*data->blendIndexes[4*vtx] + k]; - for( j = 1; j < 4; j++ ) { - if( data->blendWeights[4*vtx + j] <= 0 ) - break; + if ( data->num_joints == 0 || data->blendWeights[4*vtx] <= 0 ) { + // no blend joint, use identity matrix. + for( j = 0; j < 3; j++ ) { + for( k = 0; k < 4; k++ ) + vtxMat[4*j+k] = ( k == j ) ? 1 : 0; + } + } else { + // compute the vertex matrix by blending the up to + // four blend weights for( k = 0; k < 12; k++ ) - vtxMat[k] += data->blendWeights[4*vtx + j] - * jointMats[12*data->blendIndexes[4*vtx + j] + k]; + vtxMat[k] = data->blendWeights[4*vtx] + * jointMats[12*data->blendIndexes[4*vtx] + k]; + for( j = 1; j < 4; j++ ) { + if( data->blendWeights[4*vtx + j] <= 0 ) + break; + for( k = 0; k < 12; k++ ) + vtxMat[k] += data->blendWeights[4*vtx + j] + * jointMats[12*data->blendIndexes[4*vtx + j] + k]; + } + for( k = 0; k < 12; k++ ) + vtxMat[k] *= 1.0f / 255.0f; } - for( k = 0; k < 12; k++ ) - vtxMat[k] *= 1.0f / 255.0f; // compute the normal matrix as transpose of the adjoint // of the vertex matrix diff --git a/code/rend2/tr_postprocess.c b/code/renderergl2/tr_postprocess.c similarity index 79% rename from code/rend2/tr_postprocess.c rename to code/renderergl2/tr_postprocess.c index 73fa7175..cab9d42b 100644 --- a/code/rend2/tr_postprocess.c +++ b/code/renderergl2/tr_postprocess.c @@ -22,7 +22,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "tr_local.h" -void RB_ToneMap(FBO_t *hdrFbo, int autoExposure) +void RB_ToneMap(FBO_t *hdrFbo, vec4i_t hdrBox, FBO_t *ldrFbo, vec4i_t ldrBox, int autoExposure) { vec4i_t srcBox, dstBox; vec4_t color; @@ -40,9 +40,7 @@ void RB_ToneMap(FBO_t *hdrFbo, int autoExposure) VectorSet4(dstBox, 0, 0, size, size); - srcFbo = hdrFbo; - dstFbo = tr.textureScratchFbo[0]; - FBO_Blit(srcFbo, NULL, NULL, dstFbo, dstBox, &tr.calclevels4xShader[0], NULL, 0); + FBO_Blit(hdrFbo, hdrBox, NULL, tr.textureScratchFbo[0], dstBox, &tr.calclevels4xShader[0], NULL, 0); srcFbo = tr.textureScratchFbo[0]; dstFbo = tr.textureScratchFbo[1]; @@ -92,11 +90,20 @@ void RB_ToneMap(FBO_t *hdrFbo, int autoExposure) else GL_BindToTMU(tr.fixedLevelsImage, TB_LEVELSMAP); - FBO_Blit(hdrFbo, NULL, NULL, tr.screenScratchFbo, NULL, &tr.tonemapShader, color, 0); + FBO_Blit(hdrFbo, hdrBox, NULL, ldrFbo, ldrBox, &tr.tonemapShader, color, 0); } +/* +============= +RB_BokehBlur -void RB_BokehBlur(float blur) + +Blurs a part of one framebuffer to another. + +Framebuffers can be identical. +============= +*/ +void RB_BokehBlur(FBO_t *src, vec4i_t srcBox, FBO_t *dst, vec4i_t dstBox, float blur) { // vec4i_t srcBox, dstBox; vec4_t color; @@ -111,9 +118,16 @@ void RB_BokehBlur(float blur) // bokeh blur if (blur > 0.0f) { + vec4i_t quarterBox; + + quarterBox[0] = 0; + quarterBox[1] = tr.quarterFbo[0]->height; + quarterBox[2] = tr.quarterFbo[0]->width; + quarterBox[3] = -tr.quarterFbo[0]->height; + // create a quarter texture //FBO_Blit(NULL, NULL, NULL, tr.quarterFbo[0], NULL, NULL, NULL, 0); - FBO_FastBlit(tr.screenScratchFbo, NULL, tr.quarterFbo[0], NULL, GL_COLOR_BUFFER_BIT, GL_LINEAR); + FBO_FastBlit(src, srcBox, tr.quarterFbo[0], quarterBox, GL_COLOR_BUFFER_BIT, GL_LINEAR); } #ifndef HQ_BLUR @@ -130,18 +144,18 @@ void RB_BokehBlur(float blur) // Crossfade original with quarter texture VectorSet4(color, 1, 1, 1, blur); - FBO_Blit(tr.quarterFbo[0], NULL, NULL, tr.screenScratchFbo, NULL, NULL, color, GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA); + FBO_Blit(tr.quarterFbo[0], NULL, NULL, dst, dstBox, NULL, color, GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA); } #ifndef HQ_BLUR // ok blur, but can see some pixelization else if (blur > 1.0f && blur <= 2.0f) { // crossfade quarter texture with 1/16th texture - FBO_Blit(tr.quarterFbo[0], NULL, NULL, tr.screenScratchFbo, NULL, NULL, NULL, 0); + FBO_Blit(tr.quarterFbo[0], NULL, NULL, dst, dstBox, NULL, NULL, 0); VectorSet4(color, 1, 1, 1, blur - 1.0f); - FBO_Blit(tr.textureScratchFbo[0], NULL, NULL, tr.screenScratchFbo, NULL, NULL, color, GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA); + FBO_Blit(tr.textureScratchFbo[0], NULL, NULL, dst, dstBox, NULL, color, GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA); } else if (blur > 2.0f) { @@ -169,7 +183,7 @@ void RB_BokehBlur(float blur) FBO_Blit(tr.textureScratchFbo[0], NULL, blurTexScale, tr.textureScratchFbo[1], NULL, &tr.bokehShader, color, 0); } - FBO_Blit(tr.textureScratchFbo[1], NULL, NULL, tr.screenScratchFbo, NULL, &tr.textureColorShader, NULL, 0); + FBO_Blit(tr.textureScratchFbo[1], NULL, NULL, dst, dstBox, &tr.textureColorShader, NULL, 0); } #else // higher quality blur, but slower else if (blur > 1.0f) @@ -203,14 +217,13 @@ void RB_BokehBlur(float blur) FBO_Blit(tr.quarterFbo[0], NULL, blurTexScale, tr.quarterFbo[1], NULL, &tr.bokehShader, color, GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA); } - FBO_Blit(tr.quarterFbo[1], NULL, NULL, tr.screenScratchFbo, NULL, &tr.textureColorShader, NULL, 0); + FBO_Blit(tr.quarterFbo[1], NULL, NULL, dst, dstBox, &tr.textureColorShader, NULL, 0); } #endif } } -#ifdef REACTION static void RB_RadialBlur(FBO_t *srcFbo, FBO_t *dstFbo, int passes, float stretch, float x, float y, float w, float h, float xcenter, float ycenter, float alpha) { vec4i_t srcBox, dstBox; @@ -285,11 +298,9 @@ static qboolean RB_UpdateSunFlareVis(void) return sampleCount > 0; } -void RB_GodRays(void) +void RB_SunRays(FBO_t *srcFbo, vec4i_t srcBox, FBO_t *dstFbo, vec4i_t dstBox) { - vec4i_t srcBox, dstBox; vec4_t color; - vec3_t dir; float dot; const float cutoff = 0.25f; qboolean colorize = qtrue; @@ -298,58 +309,67 @@ void RB_GodRays(void) matrix_t mvp; vec4_t pos, hpos; - if (!backEnd.viewHasSunFlare) - return; - - VectorSubtract(backEnd.sunFlarePos, backEnd.viewParms.or.origin, dir); - VectorNormalize(dir); - - dot = DotProduct(dir, backEnd.viewParms.or.axis[0]); + dot = DotProduct(tr.sunDirection, backEnd.viewParms.or.axis[0]); if (dot < cutoff) return; if (!RB_UpdateSunFlareVis()) return; - VectorCopy(backEnd.sunFlarePos, pos); - pos[3] = 1.f; + // From RB_DrawSun() + { + float dist; + matrix_t trans, model, mvp; + + Matrix16Translation( backEnd.viewParms.or.origin, trans ); + Matrix16Multiply( backEnd.viewParms.world.modelMatrix, trans, model ); + Matrix16Multiply(backEnd.viewParms.projectionMatrix, model, mvp); + + dist = backEnd.viewParms.zFar / 1.75; // div sqrt(3) + + VectorScale( tr.sunDirection, dist, pos ); + } // project sun point - Matrix16Multiply(backEnd.viewParms.projectionMatrix, backEnd.viewParms.world.modelMatrix, mvp); + //Matrix16Multiply(backEnd.viewParms.projectionMatrix, backEnd.viewParms.world.modelMatrix, mvp); Matrix16Transform(mvp, pos, hpos); - + // transform to UV coords hpos[3] = 0.5f / hpos[3]; pos[0] = 0.5f + hpos[0] * hpos[3]; - pos[1] = 0.5f - hpos[1] * hpos[3]; - - // viewport dimensions - // JBravo: Apparently not used -/* w = glConfig.vidWidth; - h = glConfig.vidHeight; - w2 = glConfig.vidWidth / 2; - h2 = glConfig.vidHeight / 2; */ + pos[1] = 0.5f + hpos[1] * hpos[3]; // initialize quarter buffers { float mul = 1.f; vec2_t texScale; + vec4i_t rayBox, quarterBox; texScale[0] = texScale[1] = 1.0f; VectorSet4(color, mul, mul, mul, 1); + rayBox[0] = srcBox[0] * tr.sunRaysFbo->width / srcFbo->width; + rayBox[1] = srcBox[1] * tr.sunRaysFbo->height / srcFbo->height; + rayBox[2] = srcBox[2] * tr.sunRaysFbo->width / srcFbo->width; + rayBox[3] = srcBox[3] * tr.sunRaysFbo->height / srcFbo->height; + + quarterBox[0] = 0; + quarterBox[1] = tr.quarterFbo[0]->height; + quarterBox[2] = tr.quarterFbo[0]->width; + quarterBox[3] = -tr.quarterFbo[0]->height; + // first, downsample the framebuffer if (colorize) { - FBO_FastBlit(tr.screenScratchFbo, NULL, tr.quarterFbo[0], NULL, GL_COLOR_BUFFER_BIT, GL_LINEAR); - FBO_Blit(tr.godRaysFbo, NULL, NULL, tr.quarterFbo[0], NULL, NULL, color, GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO); + FBO_FastBlit(srcFbo, srcBox, tr.quarterFbo[0], quarterBox, GL_COLOR_BUFFER_BIT, GL_LINEAR); + FBO_Blit(tr.sunRaysFbo, rayBox, NULL, tr.quarterFbo[0], quarterBox, NULL, color, GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO); } else { - FBO_FastBlit(tr.godRaysFbo, NULL, tr.quarterFbo[0], NULL, GL_COLOR_BUFFER_BIT, GL_LINEAR); + FBO_FastBlit(tr.sunRaysFbo, rayBox, tr.quarterFbo[0], quarterBox, GL_COLOR_BUFFER_BIT, GL_LINEAR); } } @@ -375,12 +395,9 @@ void RB_GodRays(void) VectorSet4(color, mul, mul, mul, 1); - VectorSet4(srcBox, 0, 0, tr.quarterFbo[0]->width, tr.quarterFbo[0]->height); - VectorSet4(dstBox, 0, 0, glConfig.vidWidth, glConfig.vidHeight); - FBO_Blit(tr.quarterFbo[0], srcBox, texScale, tr.screenScratchFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE); + FBO_Blit(tr.quarterFbo[0], NULL, texScale, dstFbo, dstBox, &tr.textureColorShader, color, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE); } } -#endif static void RB_BlurAxis(FBO_t *srcFbo, FBO_t *dstFbo, float strength, qboolean horizontal) { diff --git a/code/rend2/tr_postprocess.h b/code/renderergl2/tr_postprocess.h similarity index 80% rename from code/rend2/tr_postprocess.h rename to code/renderergl2/tr_postprocess.h index d4c22658..6c34ecc2 100644 --- a/code/rend2/tr_postprocess.h +++ b/code/renderergl2/tr_postprocess.h @@ -25,9 +25,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "tr_fbo.h" -void RB_ToneMap(FBO_t *hdrFbo, int autoExposure); -void RB_BokehBlur(float blur); -void RB_GodRays(void); +void RB_ToneMap(FBO_t *hdrFbo, vec4i_t hdrBox, FBO_t *ldrFbo, vec4i_t ldrBox, int autoExposure); +void RB_BokehBlur(FBO_t *src, vec4i_t srcBox, FBO_t *dst, vec4i_t dstBox, float blur); +void RB_SunRays(FBO_t *srcFbo, vec4i_t srcBox, FBO_t *dstFbo, vec4i_t dstBox); void RB_GaussianBlur(float blur); #endif diff --git a/code/rend2/tr_scene.c b/code/renderergl2/tr_scene.c similarity index 87% rename from code/rend2/tr_scene.c rename to code/renderergl2/tr_scene.c index f134c997..7e774185 100644 --- a/code/rend2/tr_scene.c +++ b/code/renderergl2/tr_scene.c @@ -38,20 +38,12 @@ int r_numpolyverts; /* ==================== -R_ToggleSmpFrame +R_InitNextFrame ==================== */ -void R_ToggleSmpFrame( void ) { - if ( r_smp->integer ) { - // use the other buffers next frame, because another CPU - // may still be rendering into the current ones - tr.smpFrame ^= 1; - } else { - tr.smpFrame = 0; - } - - backEndData[tr.smpFrame]->commands.used = 0; +void R_InitNextFrame( void ) { + backEndData->commands.used = 0; r_firstSceneDrawSurf = 0; @@ -99,7 +91,6 @@ void R_AddPolygonSurfaces( void ) { int i; shader_t *sh; srfPoly_t *poly; -// JBravo: Fog fixes int fogMask; tr.currentEntityNum = REFENTITYNUM_WORLD; @@ -148,11 +139,11 @@ void RE_AddPolyToScene( qhandle_t hShader, int numVerts, const polyVert_t *verts return; } - poly = &backEndData[tr.smpFrame]->polys[r_numpolys]; + poly = &backEndData->polys[r_numpolys]; poly->surfaceType = SF_POLY; poly->hShader = hShader; poly->numVerts = numVerts; - poly->verts = &backEndData[tr.smpFrame]->polyVerts[r_numpolyverts]; + poly->verts = &backEndData->polyVerts[r_numpolyverts]; Com_Memcpy( poly->verts, &verts[numVerts*j], numVerts * sizeof( *verts ) ); @@ -210,10 +201,7 @@ RE_AddRefEntityToScene ===================== */ void RE_AddRefEntityToScene( const refEntity_t *ent ) { -#ifdef REACTION - // JBravo: Mirrored models vec3_t cross; -#endif if ( !tr.registered ) { return; @@ -234,14 +222,11 @@ void RE_AddRefEntityToScene( const refEntity_t *ent ) { ri.Error( ERR_DROP, "RE_AddRefEntityToScene: bad reType %i", ent->reType ); } - backEndData[tr.smpFrame]->entities[r_numentities].e = *ent; - backEndData[tr.smpFrame]->entities[r_numentities].lightingCalculated = qfalse; + backEndData->entities[r_numentities].e = *ent; + backEndData->entities[r_numentities].lightingCalculated = qfalse; -#ifdef REACTION - // JBravo: Mirrored models CrossProduct(ent->axis[0], ent->axis[1], cross); - backEndData[tr.smpFrame]->entities[r_numentities].mirrored = (DotProduct(ent->axis[2], cross) < 0.f); -#endif + backEndData->entities[r_numentities].mirrored = (DotProduct(ent->axis[2], cross) < 0.f); r_numentities++; } @@ -269,7 +254,7 @@ void RE_AddDynamicLightToScene( const vec3_t org, float intensity, float r, floa if ( glConfig.hardwareType == GLHW_RIVA128 || glConfig.hardwareType == GLHW_PERMEDIA2 ) { return; } - dl = &backEndData[tr.smpFrame]->dlights[r_numdlights++]; + dl = &backEndData->dlights[r_numdlights++]; VectorCopy (org, dl->origin); dl->radius = intensity; dl->color[0] = r; @@ -375,19 +360,34 @@ void RE_RenderScene( const refdef_t *fd ) { VectorSet(tr.refdef.sunCol, 0, 0, 0); VectorSet(tr.refdef.sunAmbCol, 0, 0, 0); } - else if (r_forceSun->integer == 1) - { - float scale = pow(2, r_mapOverBrightBits->integer - tr.overbrightBits - 8); - tr.refdef.colorScale = r_forceSunMapLightScale->value; - VectorScale(tr.sunLight, scale * r_forceSunLightScale->value, tr.refdef.sunCol); - VectorScale(tr.sunLight, scale * r_forceSunAmbientScale->value, tr.refdef.sunAmbCol); - } else { - float scale = pow(2, r_mapOverBrightBits->integer - tr.overbrightBits - 8); - tr.refdef.colorScale = tr.mapLightScale; - VectorScale(tr.sunLight, scale, tr.refdef.sunCol); - VectorScale(tr.sunAmbient, scale, tr.refdef.sunAmbCol); + tr.refdef.colorScale = r_forceSun->integer ? r_forceSunMapLightScale->value : tr.mapLightScale; + + if (r_sunlightMode->integer == 1) + { + tr.refdef.sunCol[0] = + tr.refdef.sunCol[1] = + tr.refdef.sunCol[2] = 1.0f; + + tr.refdef.sunAmbCol[0] = + tr.refdef.sunAmbCol[1] = + tr.refdef.sunAmbCol[2] = r_forceSun->integer ? r_forceSunAmbientScale->value : tr.sunShadowScale; + } + else + { + float scale = pow(2, r_mapOverBrightBits->integer - tr.overbrightBits - 8); + if (r_forceSun->integer) + { + VectorScale(tr.sunLight, scale * r_forceSunLightScale->value, tr.refdef.sunCol); + VectorScale(tr.sunLight, scale * r_forceSunAmbientScale->value, tr.refdef.sunAmbCol); + } + else + { + VectorScale(tr.sunLight, scale, tr.refdef.sunCol); + VectorScale(tr.sunLight, scale * tr.sunShadowScale, tr.refdef.sunAmbCol); + } + } } if (r_forceAutoExposure->integer) @@ -414,7 +414,6 @@ void RE_RenderScene( const refdef_t *fd ) { tr.refdef.toneMinAvgMaxLinear[2] = pow(2, tr.toneMinAvgMaxLevel[2]); } -//#ifdef REACTION // Makro - copy exta info if present if (fd->rdflags & RDF_EXTRA) { const refdefex_t* extra = (const refdefex_t*) (fd+1); @@ -432,26 +431,25 @@ void RE_RenderScene( const refdef_t *fd ) { { tr.refdef.blurFactor = 0.0f; } -//#endif // derived info tr.refdef.floatTime = tr.refdef.time * 0.001f; tr.refdef.numDrawSurfs = r_firstSceneDrawSurf; - tr.refdef.drawSurfs = backEndData[tr.smpFrame]->drawSurfs; + tr.refdef.drawSurfs = backEndData->drawSurfs; tr.refdef.num_entities = r_numentities - r_firstSceneEntity; - tr.refdef.entities = &backEndData[tr.smpFrame]->entities[r_firstSceneEntity]; + tr.refdef.entities = &backEndData->entities[r_firstSceneEntity]; tr.refdef.num_dlights = r_numdlights - r_firstSceneDlight; - tr.refdef.dlights = &backEndData[tr.smpFrame]->dlights[r_firstSceneDlight]; + tr.refdef.dlights = &backEndData->dlights[r_firstSceneDlight]; tr.refdef.numPolys = r_numpolys - r_firstScenePoly; - tr.refdef.polys = &backEndData[tr.smpFrame]->polys[r_firstScenePoly]; + tr.refdef.polys = &backEndData->polys[r_firstScenePoly]; tr.refdef.num_pshadows = 0; - tr.refdef.pshadows = &backEndData[tr.smpFrame]->pshadows[0]; + tr.refdef.pshadows = &backEndData->pshadows[0]; // turn off dynamic lighting globally by clearing all the // dlights if it needs to be disabled or if vertex lighting is enabled diff --git a/code/rend2/tr_shade.c b/code/renderergl2/tr_shade.c similarity index 73% rename from code/rend2/tr_shade.c rename to code/renderergl2/tr_shade.c index 6698b41b..633b3f43 100644 --- a/code/rend2/tr_shade.c +++ b/code/renderergl2/tr_shade.c @@ -148,9 +148,9 @@ static void DrawTris (shaderCommands_t *input) { GLSL_VertexAttribsState(ATTR_POSITION); GLSL_BindProgram(sp); - GLSL_SetUniformMatrix16(sp, TEXTURECOLOR_UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); + GLSL_SetUniformMatrix16(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); VectorSet4(color, 1, 1, 1, 1); - GLSL_SetUniformVec4(sp, TEXTURECOLOR_UNIFORM_COLOR, color); + GLSL_SetUniformVec4(sp, UNIFORM_COLOR, color); if (input->multiDrawPrimitives) { @@ -288,7 +288,7 @@ static void ComputeTexMatrix( shaderStage_t *pStage, int bundleNum, float *outma break; default: - ri.Error( ERR_DROP, "ERROR: unknown texmod '%d' in shader '%s'\n", bundle->texMods[tm].type, tess.shader->name ); + ri.Error( ERR_DROP, "ERROR: unknown texmod '%d' in shader '%s'", bundle->texMods[tm].type, tess.shader->name ); break; } } @@ -369,28 +369,28 @@ static void ProjectDlightTexture( void ) { GLSL_BindProgram(sp); - GLSL_SetUniformMatrix16(sp, DLIGHT_UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); + GLSL_SetUniformMatrix16(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); - GLSL_SetUniformFloat(sp, DLIGHT_UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation); + GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation); - GLSL_SetUniformInt(sp, DLIGHT_UNIFORM_DEFORMGEN, deformGen); + GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen); if (deformGen != DGEN_NONE) { - GLSL_SetUniformFloat5(sp, DLIGHT_UNIFORM_DEFORMPARAMS, deformParams); - GLSL_SetUniformFloat(sp, DLIGHT_UNIFORM_TIME, tess.shaderTime); + GLSL_SetUniformFloat5(sp, UNIFORM_DEFORMPARAMS, deformParams); + GLSL_SetUniformFloat(sp, UNIFORM_TIME, tess.shaderTime); } vector[0] = dl->color[0]; vector[1] = dl->color[1]; vector[2] = dl->color[2]; vector[3] = 1.0f; - GLSL_SetUniformVec4(sp, DLIGHT_UNIFORM_COLOR, vector); + GLSL_SetUniformVec4(sp, UNIFORM_COLOR, vector); vector[0] = origin[0]; vector[1] = origin[1]; vector[2] = origin[2]; vector[3] = scale; - GLSL_SetUniformVec4(sp, DLIGHT_UNIFORM_DLIGHTINFO, vector); + GLSL_SetUniformVec4(sp, UNIFORM_DLIGHTINFO, vector); GL_Bind( tr.dlightImage ); @@ -415,6 +415,7 @@ static void ProjectDlightTexture( void ) { backEnd.pc.c_totalIndexes += tess.numIndexes; backEnd.pc.c_dlightIndexes += tess.numIndexes; + backEnd.pc.c_dlightVertexes += tess.numVertexes; } } @@ -772,28 +773,28 @@ static void ForwardDlight( void ) { GLSL_BindProgram(sp); - GLSL_SetUniformMatrix16(sp, GENERIC_UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); - GLSL_SetUniformVec3(sp, GENERIC_UNIFORM_VIEWORIGIN, backEnd.viewParms.or.origin); + GLSL_SetUniformMatrix16(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); + GLSL_SetUniformVec3(sp, UNIFORM_VIEWORIGIN, backEnd.viewParms.or.origin); - GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation); + GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation); - GLSL_SetUniformInt(sp, GENERIC_UNIFORM_DEFORMGEN, deformGen); + GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen); if (deformGen != DGEN_NONE) { - GLSL_SetUniformFloat5(sp, GENERIC_UNIFORM_DEFORMPARAMS, deformParams); - GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_TIME, tess.shaderTime); + GLSL_SetUniformFloat5(sp, UNIFORM_DEFORMPARAMS, deformParams); + GLSL_SetUniformFloat(sp, UNIFORM_TIME, tess.shaderTime); } if ( input->fogNum ) { vec4_t fogColorMask; - GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_FOGDISTANCE, fogDistanceVector); - GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_FOGDEPTH, fogDepthVector); - GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_FOGEYET, eyeT); + GLSL_SetUniformVec4(sp, UNIFORM_FOGDISTANCE, fogDistanceVector); + GLSL_SetUniformVec4(sp, UNIFORM_FOGDEPTH, fogDepthVector); + GLSL_SetUniformFloat(sp, UNIFORM_FOGEYET, eyeT); ComputeFogColorMask(pStage, fogColorMask); - GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_FOGCOLORMASK, fogColorMask); + GLSL_SetUniformVec4(sp, UNIFORM_FOGCOLORMASK, fogColorMask); } { @@ -802,36 +803,36 @@ static void ForwardDlight( void ) { ComputeShaderColors(pStage, baseColor, vertColor); - GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_BASECOLOR, baseColor); - GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_VERTCOLOR, vertColor); + GLSL_SetUniformVec4(sp, UNIFORM_BASECOLOR, baseColor); + GLSL_SetUniformVec4(sp, UNIFORM_VERTCOLOR, vertColor); } if (pStage->alphaGen == AGEN_PORTAL) { - GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_PORTALRANGE, tess.shader->portalRange); + GLSL_SetUniformFloat(sp, UNIFORM_PORTALRANGE, tess.shader->portalRange); } - GLSL_SetUniformInt(sp, GENERIC_UNIFORM_COLORGEN, pStage->rgbGen); - GLSL_SetUniformInt(sp, GENERIC_UNIFORM_ALPHAGEN, pStage->alphaGen); + GLSL_SetUniformInt(sp, UNIFORM_COLORGEN, pStage->rgbGen); + GLSL_SetUniformInt(sp, UNIFORM_ALPHAGEN, pStage->alphaGen); - GLSL_SetUniformVec3(sp, GENERIC_UNIFORM_DIRECTEDLIGHT, dl->color); + GLSL_SetUniformVec3(sp, UNIFORM_DIRECTEDLIGHT, dl->color); VectorSet(vector, 0, 0, 0); - GLSL_SetUniformVec3(sp, GENERIC_UNIFORM_AMBIENTLIGHT, vector); + GLSL_SetUniformVec3(sp, UNIFORM_AMBIENTLIGHT, vector); VectorCopy(dl->origin, vector); vector[3] = 1.0f; - GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_LIGHTORIGIN, vector); + GLSL_SetUniformVec4(sp, UNIFORM_LIGHTORIGIN, vector); - GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_LIGHTRADIUS, radius); + GLSL_SetUniformFloat(sp, UNIFORM_LIGHTRADIUS, radius); - GLSL_SetUniformVec2(sp, GENERIC_UNIFORM_MATERIALINFO, pStage->materialInfo); + GLSL_SetUniformVec2(sp, UNIFORM_MATERIALINFO, pStage->materialInfo); // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light // where they aren't rendered GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); - GLSL_SetUniformMatrix16(sp, GENERIC_UNIFORM_MODELMATRIX, backEnd.or.transformMatrix); + GLSL_SetUniformMatrix16(sp, UNIFORM_MODELMATRIX, backEnd.or.transformMatrix); if (pStage->bundle[TB_DIFFUSEMAP].image[0]) R_BindAnimatedImageToTMU( &pStage->bundle[TB_DIFFUSEMAP], TB_DIFFUSEMAP); @@ -852,215 +853,12 @@ static void ForwardDlight( void ) { ComputeTexMatrix( pStage, TB_DIFFUSEMAP, matrix ); VectorSet4(vector, matrix[0], matrix[1], matrix[4], matrix[5]); - GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_DIFFUSETEXMATRIX, vector); + GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXMATRIX, vector); VectorSet4(vector, matrix[8], matrix[9], matrix[12], matrix[13]); - GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_DIFFUSETEXOFFTURB, vector); + GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXOFFTURB, vector); - GLSL_SetUniformInt(sp, GENERIC_UNIFORM_TCGEN0, pStage->bundle[0].tcGen); - - // - // draw - // - - if (input->multiDrawPrimitives) - { - R_DrawMultiElementsVBO(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex); - } - else - { - R_DrawElementsVBO(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex); - } - - backEnd.pc.c_totalIndexes += tess.numIndexes; - backEnd.pc.c_dlightIndexes += tess.numIndexes; - } -} - - -static void ForwardSunlight( void ) { -// int l; - //vec3_t origin; - //float scale; - int stage; - int stageGlState[2]; - qboolean alphaOverride = qfalse; - - int deformGen; - vec5_t deformParams; - - vec4_t fogDistanceVector, fogDepthVector = {0, 0, 0, 0}; - float eyeT = 0; - - shaderCommands_t *input = &tess; - - ComputeDeformValues(&deformGen, deformParams); - - ComputeFogValues(fogDistanceVector, fogDepthVector, &eyeT); - - // deal with vertex alpha blended surfaces - if (input->xstages[0] && input->xstages[1] && - (input->xstages[1]->alphaGen == AGEN_VERTEX || input->xstages[1]->alphaGen == AGEN_ONE_MINUS_VERTEX)) - { - stageGlState[0] = input->xstages[0]->stateBits & (GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS); - - if (stageGlState[0] == 0 || stageGlState[0] == (GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO)) - { - stageGlState[1] = input->xstages[1]->stateBits & (GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS); - - if (stageGlState[1] == (GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA)) - { - alphaOverride = qtrue; - stageGlState[0] = GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL; - stageGlState[1] = GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL; - } - else if (stageGlState[1] == (GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA | GLS_DSTBLEND_SRC_ALPHA)) - { - alphaOverride = qtrue; - stageGlState[0] = GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL; - stageGlState[1] = GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL; - } - } - } - - if (!alphaOverride) - { - stageGlState[0] = - stageGlState[1] = GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL; - } - - for ( stage = 0; stage < 2 /*MAX_SHADER_STAGES */; stage++ ) - { - shaderStage_t *pStage = input->xstages[stage]; - shaderProgram_t *sp; - vec4_t vector; - matrix_t matrix; - - if ( !pStage ) - { - break; - } - - //VectorCopy( dl->transformed, origin ); - - //if (pStage->glslShaderGroup == tr.lightallShader) - { - int index = pStage->glslShaderIndex; - - index &= ~(LIGHTDEF_LIGHTTYPE_MASK | LIGHTDEF_USE_DELUXEMAP); - index |= LIGHTDEF_USE_LIGHT_VECTOR | LIGHTDEF_USE_SHADOWMAP; - - if (backEnd.currentEntity && backEnd.currentEntity != &tr.worldEntity) - { - index |= LIGHTDEF_ENTITY; - } - - sp = &tr.lightallShader[index]; - } - - backEnd.pc.c_lightallDraws++; - - GLSL_BindProgram(sp); - - GLSL_SetUniformMatrix16(sp, GENERIC_UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); - GLSL_SetUniformVec3(sp, GENERIC_UNIFORM_VIEWORIGIN, backEnd.viewParms.or.origin); - - GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation); - - GLSL_SetUniformInt(sp, GENERIC_UNIFORM_DEFORMGEN, deformGen); - if (deformGen != DGEN_NONE) - { - GLSL_SetUniformFloat5(sp, GENERIC_UNIFORM_DEFORMPARAMS, deformParams); - GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_TIME, tess.shaderTime); - } - - if ( input->fogNum ) { - vec4_t fogColorMask; - - GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_FOGDISTANCE, fogDistanceVector); - GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_FOGDEPTH, fogDepthVector); - GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_FOGEYET, eyeT); - - ComputeFogColorMask(pStage, fogColorMask); - - GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_FOGCOLORMASK, fogColorMask); - } - - { - vec4_t baseColor; - vec4_t vertColor; - - ComputeShaderColors(pStage, baseColor, vertColor); - - if (alphaOverride) - { - if (input->xstages[1]->alphaGen == AGEN_VERTEX) - { - baseColor[3] = 0.0f; - vertColor[3] = 1.0f; - } - else if (input->xstages[1]->alphaGen == AGEN_ONE_MINUS_VERTEX) - { - baseColor[3] = 1.0f; - vertColor[3] = -1.0f; - } - } - - GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_BASECOLOR, baseColor); - GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_VERTCOLOR, vertColor); - } - - if (pStage->alphaGen == AGEN_PORTAL) - { - GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_PORTALRANGE, tess.shader->portalRange); - } - - GLSL_SetUniformInt(sp, GENERIC_UNIFORM_COLORGEN, pStage->rgbGen); - GLSL_SetUniformInt(sp, GENERIC_UNIFORM_ALPHAGEN, pStage->alphaGen); - - GLSL_SetUniformVec3(sp, GENERIC_UNIFORM_DIRECTEDLIGHT, backEnd.refdef.sunCol); - GLSL_SetUniformVec3(sp, GENERIC_UNIFORM_AMBIENTLIGHT, backEnd.refdef.sunAmbCol); - - GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_LIGHTORIGIN, backEnd.refdef.sunDir); - - GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_LIGHTRADIUS, 9999999999.9f); - - GLSL_SetUniformVec2(sp, GENERIC_UNIFORM_MATERIALINFO, pStage->materialInfo); - - GL_State( stageGlState[stage] ); - - GLSL_SetUniformMatrix16(sp, GENERIC_UNIFORM_MODELMATRIX, backEnd.or.transformMatrix); - - if (pStage->bundle[TB_DIFFUSEMAP].image[0]) - R_BindAnimatedImageToTMU( &pStage->bundle[TB_DIFFUSEMAP], TB_DIFFUSEMAP); - - if (pStage->bundle[TB_NORMALMAP].image[0]) - R_BindAnimatedImageToTMU( &pStage->bundle[TB_NORMALMAP], TB_NORMALMAP); - - if (pStage->bundle[TB_SPECULARMAP].image[0]) - R_BindAnimatedImageToTMU( &pStage->bundle[TB_SPECULARMAP], TB_SPECULARMAP); - - /* - { - GL_BindToTMU(tr.sunShadowDepthImage[0], TB_SHADOWMAP); - GL_BindToTMU(tr.sunShadowDepthImage[1], TB_SHADOWMAP2); - GL_BindToTMU(tr.sunShadowDepthImage[2], TB_SHADOWMAP3); - GLSL_SetUniformMatrix16(sp, GENERIC_UNIFORM_SHADOWMVP, backEnd.refdef.sunShadowMvp[0]); - GLSL_SetUniformMatrix16(sp, GENERIC_UNIFORM_SHADOWMVP2, backEnd.refdef.sunShadowMvp[1]); - GLSL_SetUniformMatrix16(sp, GENERIC_UNIFORM_SHADOWMVP3, backEnd.refdef.sunShadowMvp[2]); - } - */ - GL_BindToTMU(tr.screenShadowImage, TB_SHADOWMAP); - - ComputeTexMatrix( pStage, TB_DIFFUSEMAP, matrix ); - - VectorSet4(vector, matrix[0], matrix[1], matrix[4], matrix[5]); - GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_DIFFUSETEXMATRIX, vector); - - VectorSet4(vector, matrix[8], matrix[9], matrix[12], matrix[13]); - GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_DIFFUSETEXOFFTURB, vector); - - GLSL_SetUniformInt(sp, GENERIC_UNIFORM_TCGEN0, pStage->bundle[0].tcGen); + GLSL_SetUniformInt(sp, UNIFORM_TCGEN0, pStage->bundle[0].tcGen); // // draw @@ -1077,6 +875,7 @@ static void ForwardSunlight( void ) { backEnd.pc.c_totalIndexes += tess.numIndexes; backEnd.pc.c_dlightIndexes += tess.numIndexes; + backEnd.pc.c_dlightVertexes += tess.numVertexes; } } @@ -1114,22 +913,22 @@ static void ProjectPshadowVBOGLSL( void ) { GLSL_BindProgram(sp); - GLSL_SetUniformMatrix16(sp, PSHADOW_UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); + GLSL_SetUniformMatrix16(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); VectorCopy(origin, vector); vector[3] = 1.0f; - GLSL_SetUniformVec4(sp, PSHADOW_UNIFORM_LIGHTORIGIN, vector); + GLSL_SetUniformVec4(sp, UNIFORM_LIGHTORIGIN, vector); VectorScale(ps->lightViewAxis[0], 1.0f / ps->viewRadius, vector); - GLSL_SetUniformVec3(sp, PSHADOW_UNIFORM_LIGHTFORWARD, vector); + GLSL_SetUniformVec3(sp, UNIFORM_LIGHTFORWARD, vector); VectorScale(ps->lightViewAxis[1], 1.0f / ps->viewRadius, vector); - GLSL_SetUniformVec3(sp, PSHADOW_UNIFORM_LIGHTRIGHT, vector); + GLSL_SetUniformVec3(sp, UNIFORM_LIGHTRIGHT, vector); VectorScale(ps->lightViewAxis[2], 1.0f / ps->viewRadius, vector); - GLSL_SetUniformVec3(sp, PSHADOW_UNIFORM_LIGHTUP, vector); + GLSL_SetUniformVec3(sp, UNIFORM_LIGHTUP, vector); - GLSL_SetUniformFloat(sp, PSHADOW_UNIFORM_LIGHTRADIUS, radius); + GLSL_SetUniformFloat(sp, UNIFORM_LIGHTRADIUS, radius); // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light // where they aren't rendered @@ -1194,28 +993,28 @@ static void RB_FogPass( void ) { fog = tr.world->fogs + tess.fogNum; - GLSL_SetUniformMatrix16(sp, FOGPASS_UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); + GLSL_SetUniformMatrix16(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); - GLSL_SetUniformFloat(sp, FOGPASS_UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation); + GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation); - GLSL_SetUniformInt(sp, FOGPASS_UNIFORM_DEFORMGEN, deformGen); + GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen); if (deformGen != DGEN_NONE) { - GLSL_SetUniformFloat5(sp, FOGPASS_UNIFORM_DEFORMPARAMS, deformParams); - GLSL_SetUniformFloat(sp, FOGPASS_UNIFORM_TIME, tess.shaderTime); + GLSL_SetUniformFloat5(sp, UNIFORM_DEFORMPARAMS, deformParams); + GLSL_SetUniformFloat(sp, UNIFORM_TIME, tess.shaderTime); } color[0] = ((unsigned char *)(&fog->colorInt))[0] / 255.0f; color[1] = ((unsigned char *)(&fog->colorInt))[1] / 255.0f; color[2] = ((unsigned char *)(&fog->colorInt))[2] / 255.0f; color[3] = ((unsigned char *)(&fog->colorInt))[3] / 255.0f; - GLSL_SetUniformVec4(sp, FOGPASS_UNIFORM_COLOR, color); + GLSL_SetUniformVec4(sp, UNIFORM_COLOR, color); ComputeFogValues(fogDistanceVector, fogDepthVector, &eyeT); - GLSL_SetUniformVec4(sp, FOGPASS_UNIFORM_FOGDISTANCE, fogDistanceVector); - GLSL_SetUniformVec4(sp, FOGPASS_UNIFORM_FOGDEPTH, fogDepthVector); - GLSL_SetUniformFloat(sp, FOGPASS_UNIFORM_FOGEYET, eyeT); + GLSL_SetUniformVec4(sp, UNIFORM_FOGDISTANCE, fogDistanceVector); + GLSL_SetUniformVec4(sp, UNIFORM_FOGDEPTH, fogDepthVector); + GLSL_SetUniformFloat(sp, UNIFORM_FOGEYET, eyeT); if ( tess.shader->fogPass == FP_EQUAL ) { GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_EQUAL ); @@ -1291,6 +1090,11 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) index |= LIGHTDEF_ENTITY; } + if (pStage->stateBits & GLS_ATEST_BITS) + { + index |= LIGHTDEF_USE_TCGEN_AND_TCMOD; + } + sp = &pStage->glslShaderGroup[index]; } else @@ -1307,6 +1111,11 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) shaderAttribs |= GENERICDEF_USE_VERTEX_ANIMATION; } + if (pStage->stateBits & GLS_ATEST_BITS) + { + shaderAttribs |= GENERICDEF_USE_TCGEN_AND_TCMOD; + } + sp = &tr.genericShader[shaderAttribs]; } } @@ -1319,6 +1128,11 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) index |= LIGHTDEF_ENTITY; } + if (r_sunlightMode->integer && (backEnd.viewParms.flags & VPF_USESUNLIGHT) && (index & LIGHTDEF_LIGHTTYPE_MASK)) + { + index |= LIGHTDEF_USE_SHADOWMAP; + } + if (r_lightmap->integer && index & LIGHTDEF_USE_LIGHTMAP) { index = LIGHTDEF_USE_LIGHTMAP; @@ -1340,22 +1154,22 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) GLSL_BindProgram(sp); - GLSL_SetUniformMatrix16(sp, GENERIC_UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); - GLSL_SetUniformVec3(sp, GENERIC_UNIFORM_VIEWORIGIN, backEnd.viewParms.or.origin); + GLSL_SetUniformMatrix16(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); + GLSL_SetUniformVec3(sp, UNIFORM_VIEWORIGIN, backEnd.viewParms.or.origin); - GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation); + GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation); - GLSL_SetUniformInt(sp, GENERIC_UNIFORM_DEFORMGEN, deformGen); + GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen); if (deformGen != DGEN_NONE) { - GLSL_SetUniformFloat5(sp, GENERIC_UNIFORM_DEFORMPARAMS, deformParams); - GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_TIME, tess.shaderTime); + GLSL_SetUniformFloat5(sp, UNIFORM_DEFORMPARAMS, deformParams); + GLSL_SetUniformFloat(sp, UNIFORM_TIME, tess.shaderTime); } if ( input->fogNum ) { - GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_FOGDISTANCE, fogDistanceVector); - GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_FOGDEPTH, fogDepthVector); - GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_FOGEYET, eyeT); + GLSL_SetUniformVec4(sp, UNIFORM_FOGDISTANCE, fogDistanceVector); + GLSL_SetUniformVec4(sp, UNIFORM_FOGDEPTH, fogDepthVector); + GLSL_SetUniformFloat(sp, UNIFORM_FOGEYET, eyeT); } GL_State( pStage->stateBits ); @@ -1402,8 +1216,8 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) VectorScale(vertColor, backEnd.refdef.colorScale, vertColor); } - GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_BASECOLOR, baseColor); - GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_VERTCOLOR, vertColor); + GLSL_SetUniformVec4(sp, UNIFORM_BASECOLOR, baseColor); + GLSL_SetUniformVec4(sp, UNIFORM_VERTCOLOR, vertColor); } if (pStage->rgbGen == CGEN_LIGHTING_DIFFUSE) @@ -1411,25 +1225,25 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) vec4_t vec; VectorScale(backEnd.currentEntity->ambientLight, 1.0f / 255.0f, vec); - GLSL_SetUniformVec3(sp, GENERIC_UNIFORM_AMBIENTLIGHT, vec); + GLSL_SetUniformVec3(sp, UNIFORM_AMBIENTLIGHT, vec); VectorScale(backEnd.currentEntity->directedLight, 1.0f / 255.0f, vec); - GLSL_SetUniformVec3(sp, GENERIC_UNIFORM_DIRECTEDLIGHT, vec); + GLSL_SetUniformVec3(sp, UNIFORM_DIRECTEDLIGHT, vec); VectorCopy(backEnd.currentEntity->lightDir, vec); vec[3] = 0.0f; - GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_LIGHTORIGIN, vec); + GLSL_SetUniformVec4(sp, UNIFORM_LIGHTORIGIN, vec); - GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_LIGHTRADIUS, 999999.0f); + GLSL_SetUniformFloat(sp, UNIFORM_LIGHTRADIUS, 999999.0f); } if (pStage->alphaGen == AGEN_PORTAL) { - GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_PORTALRANGE, tess.shader->portalRange); + GLSL_SetUniformFloat(sp, UNIFORM_PORTALRANGE, tess.shader->portalRange); } - GLSL_SetUniformInt(sp, GENERIC_UNIFORM_COLORGEN, pStage->rgbGen); - GLSL_SetUniformInt(sp, GENERIC_UNIFORM_ALPHAGEN, pStage->alphaGen); + GLSL_SetUniformInt(sp, UNIFORM_COLORGEN, pStage->rgbGen); + GLSL_SetUniformInt(sp, UNIFORM_ALPHAGEN, pStage->alphaGen); if ( input->fogNum ) { @@ -1437,7 +1251,7 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) ComputeFogColorMask(pStage, fogColorMask); - GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_FOGCOLORMASK, fogColorMask); + GLSL_SetUniformVec4(sp, UNIFORM_FOGCOLORMASK, fogColorMask); } ComputeTexMatrix( pStage, TB_DIFFUSEMAP, matrix ); @@ -1445,28 +1259,28 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) { vec4_t vector; VectorSet4(vector, matrix[0], matrix[1], matrix[4], matrix[5]); - GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_DIFFUSETEXMATRIX, vector); + GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXMATRIX, vector); VectorSet4(vector, matrix[8], matrix[9], matrix[12], matrix[13]); - GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_DIFFUSETEXOFFTURB, vector); + GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXOFFTURB, vector); } - GLSL_SetUniformInt(sp, GENERIC_UNIFORM_TCGEN0, pStage->bundle[0].tcGen); + GLSL_SetUniformInt(sp, UNIFORM_TCGEN0, pStage->bundle[0].tcGen); if (pStage->bundle[0].tcGen == TCGEN_VECTOR) { vec3_t vec; VectorCopy(pStage->bundle[0].tcGenVectors[0], vec); - GLSL_SetUniformVec3(sp, GENERIC_UNIFORM_TCGEN0VECTOR0, vec); + GLSL_SetUniformVec3(sp, UNIFORM_TCGEN0VECTOR0, vec); VectorCopy(pStage->bundle[0].tcGenVectors[1], vec); - GLSL_SetUniformVec3(sp, GENERIC_UNIFORM_TCGEN0VECTOR1, vec); + GLSL_SetUniformVec3(sp, UNIFORM_TCGEN0VECTOR1, vec); } - GLSL_SetUniformMatrix16(sp, GENERIC_UNIFORM_MODELMATRIX, backEnd.or.transformMatrix); + GLSL_SetUniformMatrix16(sp, UNIFORM_MODELMATRIX, backEnd.or.transformMatrix); - GLSL_SetUniformVec2(sp, GENERIC_UNIFORM_MATERIALINFO, pStage->materialInfo); + GLSL_SetUniformVec2(sp, UNIFORM_MATERIALINFO, pStage->materialInfo); - //GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_MAPLIGHTSCALE, backEnd.refdef.mapLightScale); + //GLSL_SetUniformFloat(sp, UNIFORM_MAPLIGHTSCALE, backEnd.refdef.mapLightScale); // // do multitexture @@ -1482,6 +1296,14 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) { int i; + if ((backEnd.viewParms.flags & VPF_USESUNLIGHT) && (pStage->glslShaderIndex & LIGHTDEF_LIGHTTYPE_MASK)) + { + GL_BindToTMU(tr.screenShadowImage, TB_SHADOWMAP); + GLSL_SetUniformVec3(sp, UNIFORM_PRIMARYLIGHTAMBIENT, backEnd.refdef.sunAmbCol); + GLSL_SetUniformVec3(sp, UNIFORM_PRIMARYLIGHTCOLOR, backEnd.refdef.sunCol); + GLSL_SetUniformVec4(sp, UNIFORM_PRIMARYLIGHTORIGIN, backEnd.refdef.sunDir); + } + if ((r_lightmap->integer == 1 || r_lightmap->integer == 2) && pStage->bundle[TB_LIGHTMAP].image[0]) { for (i = 0; i < NUM_TEXTURE_BUNDLES; i++) @@ -1529,9 +1351,9 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) // lightmap/secondary pass // if ( r_lightmap->integer ) { - GLSL_SetUniformInt(sp, GENERIC_UNIFORM_TEXTURE1ENV, GL_REPLACE); + GLSL_SetUniformInt(sp, UNIFORM_TEXTURE1ENV, GL_REPLACE); } else { - GLSL_SetUniformInt(sp, GENERIC_UNIFORM_TEXTURE1ENV, tess.shader->multitextureEnv); + GLSL_SetUniformInt(sp, UNIFORM_TEXTURE1ENV, tess.shader->multitextureEnv); } R_BindAnimatedImageToTMU( &pStage->bundle[1], 1 ); @@ -1548,7 +1370,7 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) else R_BindAnimatedImageToTMU( &pStage->bundle[0], 0 ); - GLSL_SetUniformInt(sp, GENERIC_UNIFORM_TEXTURE1ENV, 0); + GLSL_SetUniformInt(sp, UNIFORM_TEXTURE1ENV, 0); } // @@ -1589,23 +1411,23 @@ static void RB_RenderShadowmap( shaderCommands_t *input ) GLSL_BindProgram(sp); - GLSL_SetUniformMatrix16(sp, GENERIC_UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); + GLSL_SetUniformMatrix16(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); - GLSL_SetUniformMatrix16(sp, GENERIC_UNIFORM_MODELMATRIX, backEnd.or.transformMatrix); + GLSL_SetUniformMatrix16(sp, UNIFORM_MODELMATRIX, backEnd.or.transformMatrix); - GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation); + GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation); - GLSL_SetUniformInt(sp, GENERIC_UNIFORM_DEFORMGEN, deformGen); + GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen); if (deformGen != DGEN_NONE) { - GLSL_SetUniformFloat5(sp, GENERIC_UNIFORM_DEFORMPARAMS, deformParams); - GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_TIME, tess.shaderTime); + GLSL_SetUniformFloat5(sp, UNIFORM_DEFORMPARAMS, deformParams); + GLSL_SetUniformFloat(sp, UNIFORM_TIME, tess.shaderTime); } VectorCopy(backEnd.viewParms.or.origin, vector); vector[3] = 1.0f; - GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_LIGHTORIGIN, vector); - GLSL_SetUniformFloat(sp, GENERIC_UNIFORM_LIGHTRADIUS, backEnd.viewParms.zFar); + GLSL_SetUniformVec4(sp, UNIFORM_LIGHTORIGIN, vector); + GLSL_SetUniformFloat(sp, UNIFORM_LIGHTRADIUS, backEnd.viewParms.zFar); GL_State( 0 ); @@ -1772,12 +1594,6 @@ void RB_StageIteratorGeneric( void ) } } - if ((backEnd.viewParms.flags & VPF_USESUNLIGHT) && tess.shader->sort <= SS_OPAQUE - //if ((tr.sunShadows || r_forceSunlight->value > 0.0f) && tess.shader->sort <= SS_OPAQUE - && !(tess.shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY) ) && tess.xstages[0]->glslShaderGroup == tr.lightallShader) { - ForwardSunlight(); - } - // // now do fog // diff --git a/code/rend2/tr_shade_calc.c b/code/renderergl2/tr_shade_calc.c similarity index 99% rename from code/rend2/tr_shade_calc.c rename to code/renderergl2/tr_shade_calc.c index 9421f646..a5c4e9ab 100644 --- a/code/rend2/tr_shade_calc.c +++ b/code/renderergl2/tr_shade_calc.c @@ -456,10 +456,10 @@ static void Autosprite2Deform( void ) { vec3_t forward; if ( tess.numVertexes & 3 ) { - ri.Printf( PRINT_WARNING, "Autosprite2 shader %s had odd vertex count", tess.shader->name ); + ri.Printf( PRINT_WARNING, "Autosprite2 shader %s had odd vertex count\n", tess.shader->name ); } if ( tess.numIndexes != ( tess.numVertexes >> 2 ) * 6 ) { - ri.Printf( PRINT_WARNING, "Autosprite2 shader %s had odd index count", tess.shader->name ); + ri.Printf( PRINT_WARNING, "Autosprite2 shader %s had odd index count\n", tess.shader->name ); } if ( backEnd.currentEntity != &tr.worldEntity ) { diff --git a/code/rend2/tr_shader.c b/code/renderergl2/tr_shader.c similarity index 96% rename from code/rend2/tr_shader.c rename to code/renderergl2/tr_shader.c index d66b5408..da2a7c60 100644 --- a/code/rend2/tr_shader.c +++ b/code/renderergl2/tr_shader.c @@ -693,7 +693,7 @@ static qboolean ParseStage( shaderStage_t *stage, char **text ) else if ( !Q_stricmp( token, "clampmap" ) ) { imgType_t type = IMGTYPE_COLORALPHA; - imgFlags_t flags = IMGFLAG_CLAMPTOEDGE | IMGFLAG_SRGB; + imgFlags_t flags = IMGFLAG_CLAMPTOEDGE; token = COM_ParseExt( text, qfalse ); if ( !token[0] ) @@ -756,7 +756,7 @@ static qboolean ParseStage( shaderStage_t *stage, char **text ) } num = stage->bundle[0].numImageAnimations; if ( num < MAX_IMAGE_ANIMATIONS ) { - imgFlags_t flags = IMGFLAG_SRGB; + imgFlags_t flags = IMGFLAG_NONE; if (!shader.noMipMaps) flags |= IMGFLAG_MIPMAP; @@ -764,6 +764,9 @@ static qboolean ParseStage( shaderStage_t *stage, char **text ) if (!shader.noPicMip) flags |= IMGFLAG_PICMIP; + if (r_srgb->integer) + flags |= IMGFLAG_SRGB; + stage->bundle[0].image[num] = R_FindImageFile( token, IMGTYPE_COLORALPHA, flags ); if ( !stage->bundle[0].image[num] ) { @@ -1376,6 +1379,10 @@ static void ParseSkyParms( char **text ) { static char *suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"}; char pathname[MAX_QPATH]; int i; + imgFlags_t imgFlags = IMGFLAG_MIPMAP | IMGFLAG_PICMIP; + + if (r_srgb->integer) + imgFlags |= IMGFLAG_SRGB; // outerbox token = COM_ParseExt( text, qfalse ); @@ -1387,7 +1394,7 @@ static void ParseSkyParms( char **text ) { for (i=0 ; i<6 ; i++) { Com_sprintf( pathname, sizeof(pathname), "%s_%s.tga" , token, suf[i] ); - shader.sky.outerbox[i] = R_FindImageFile( ( char * ) pathname, IMGTYPE_COLORALPHA, IMGFLAG_SRGB | IMGFLAG_MIPMAP | IMGFLAG_PICMIP | IMGFLAG_CLAMPTOEDGE ); + shader.sky.outerbox[i] = R_FindImageFile( ( char * ) pathname, IMGTYPE_COLORALPHA, imgFlags | IMGFLAG_CLAMPTOEDGE ); if ( !shader.sky.outerbox[i] ) { shader.sky.outerbox[i] = tr.defaultImage; @@ -1418,7 +1425,7 @@ static void ParseSkyParms( char **text ) { for (i=0 ; i<6 ; i++) { Com_sprintf( pathname, sizeof(pathname), "%s_%s.tga" , token, suf[i] ); - shader.sky.innerbox[i] = R_FindImageFile( ( char * ) pathname, IMGTYPE_COLORALPHA, IMGFLAG_SRGB | IMGFLAG_MIPMAP | IMGFLAG_PICMIP ); + shader.sky.innerbox[i] = R_FindImageFile( ( char * ) pathname, IMGTYPE_COLORALPHA, imgFlags ); if ( !shader.sky.innerbox[i] ) { shader.sky.innerbox[i] = tr.defaultImage; } @@ -1629,8 +1636,6 @@ static qboolean ParseShader( char **text ) a = atof( token ); VectorScale( tr.sunLight, a, tr.sunLight); - VectorSet( tr.sunAmbient, 0.0f, 0.0f, 0.0f); - token = COM_ParseExt( text, qfalse ); a = atof( token ); a = a / 180 * M_PI; @@ -1649,7 +1654,7 @@ static qboolean ParseShader( char **text ) tr.mapLightScale = atof(token); token = COM_ParseExt( text, qfalse ); - VectorScale( tr.sunLight, atof(token), tr.sunAmbient ); + tr.sunShadowScale = atof(token); } SkipRestOfLine( text ); @@ -1759,7 +1764,7 @@ static qboolean ParseShader( char **text ) // light determines flaring in q3map, not needed here else if ( !Q_stricmp(token, "light") ) { - token = COM_ParseExt( text, qfalse ); + COM_ParseExt( text, qfalse ); continue; } // cull @@ -2156,7 +2161,7 @@ static qboolean CollapseMultitexture( void ) { static void CollapseStagesToLightall(shaderStage_t *diffuse, shaderStage_t *normal, shaderStage_t *specular, shaderStage_t *lightmap, - qboolean useLightVector, qboolean useLightVertex, qboolean parallax, qboolean environment) + qboolean useLightVector, qboolean useLightVertex, qboolean parallax, qboolean tcgen) { int defs = 0; @@ -2234,7 +2239,7 @@ static void CollapseStagesToLightall(shaderStage_t *diffuse, } } - if (environment || diffuse->bundle[0].numTexMods) + if (tcgen || diffuse->bundle[0].numTexMods) { defs |= LIGHTDEF_USE_TCGEN_AND_TCMOD; } @@ -2340,7 +2345,7 @@ static qboolean CollapseStagesToGLSL(void) { shaderStage_t *pStage = &stages[i]; shaderStage_t *diffuse, *normal, *specular, *lightmap; - qboolean parallax, environment, diffuselit, vertexlit; + qboolean parallax, tcgen, diffuselit, vertexlit; if (!pStage->active) continue; @@ -2403,10 +2408,12 @@ static qboolean CollapseStagesToGLSL(void) } } - environment = qfalse; - if (diffuse->bundle[0].tcGen == TCGEN_ENVIRONMENT_MAPPED) + tcgen = qfalse; + if (diffuse->bundle[0].tcGen == TCGEN_ENVIRONMENT_MAPPED + || diffuse->bundle[0].tcGen == TCGEN_LIGHTMAP + || diffuse->bundle[0].tcGen == TCGEN_VECTOR) { - environment = qtrue; + tcgen = qtrue; } diffuselit = qfalse; @@ -2421,7 +2428,7 @@ static qboolean CollapseStagesToGLSL(void) vertexlit = qtrue; } - CollapseStagesToLightall(diffuse, normal, specular, lightmap, diffuselit, vertexlit, parallax, environment); + CollapseStagesToLightall(diffuse, normal, specular, lightmap, diffuselit, vertexlit, parallax, tcgen); } // deactivate lightmap stages @@ -2484,6 +2491,30 @@ static qboolean CollapseStagesToGLSL(void) if (numStages == i && i >= 2 && CollapseMultitexture()) numStages--; + // convert any remaining lightmap stages to a lighting pass with a white texture + // only do this with r_sunlightMode non-zero, as it's only for correct shadows. + if (r_sunlightMode->integer) + { + for (i = 0; i < MAX_SHADER_STAGES; i++) + { + shaderStage_t *pStage = &stages[i]; + + if (!pStage->active) + continue; + + if (pStage->bundle[TB_DIFFUSEMAP].isLightmap) + { + pStage->glslShaderGroup = tr.lightallShader; + pStage->glslShaderIndex = LIGHTDEF_USE_LIGHTMAP; + if (r_deluxeMapping->integer && tr.worldDeluxeMapping) + pStage->glslShaderIndex |= LIGHTDEF_USE_DELUXEMAP; + pStage->bundle[TB_LIGHTMAP] = pStage->bundle[TB_DIFFUSEMAP]; + pStage->bundle[TB_DIFFUSEMAP].image[0] = tr.whiteImage; + pStage->bundle[TB_DIFFUSEMAP].isLightmap = qfalse; + } + } + } + return numStages; } @@ -2499,7 +2530,7 @@ sortedIndex. ============== */ static void FixRenderCommandList( int newShader ) { - renderCommandList_t *cmdList = &backEndData[tr.smpFrame]->commands; + renderCommandList_t *cmdList = &backEndData->commands; if( cmdList ) { const void *curCmd = cmdList->cmds; @@ -2898,7 +2929,6 @@ static shader_t *FinishShader( void ) { // if ( stage > 1 && ( (r_vertexLight->integer && !r_uiFullScreen->integer) || glConfig.hardwareType == GLHW_PERMEDIA2 ) ) { VertexLightingCollapse(); - stage = 1; hasLightmapStage = qfalse; } @@ -2988,7 +3018,7 @@ static char *FindShaderInShaderText( const char *shadername ) { } else { // skip the definition - SkipBracedSection( &p ); + SkipBracedSection( &p, 0 ); } } @@ -3103,12 +3133,6 @@ shader_t *R_FindShader( const char *name, int lightmapIndex, qboolean mipRawImag } } - // make sure the render thread is stopped, because we are probably - // going to have to upload an image - if (r_smp->integer) { - R_SyncRenderThread(); - } - // clear the global shader Com_Memset( &shader, 0, sizeof( shader ) ); Com_Memset( &stages, 0, sizeof( stages ) ); @@ -3254,12 +3278,6 @@ qhandle_t RE_RegisterShaderFromImage(const char *name, int lightmapIndex, image_ } } - // make sure the render thread is stopped, because we are probably - // going to have to upload an image - if (r_smp->integer) { - R_SyncRenderThread(); - } - // clear the global shader Com_Memset( &shader, 0, sizeof( shader ) ); Com_Memset( &stages, 0, sizeof( stages ) ); @@ -3524,6 +3542,8 @@ static void ScanAndLoadShaderFiles( void ) int i; char *oldp, *token, *hashMem, *textEnd; int shaderTextHashTableSizes[MAX_SHADERTEXT_HASH], hash, size; + char shaderName[MAX_QPATH]; + int shaderLine; long sum = 0, summand; // scan for shader files @@ -3567,26 +3587,40 @@ static void ScanAndLoadShaderFiles( void ) // Do a simple check on the shader structure in that file to make sure one bad shader file cannot fuck up all other shaders. p = buffers[i]; + COM_BeginParseSession(filename); while(1) { token = COM_ParseExt(&p, qtrue); if(!*token) break; - - oldp = p; - + + Q_strncpyz(shaderName, token, sizeof(shaderName)); + shaderLine = COM_GetCurrentParseLine(); + token = COM_ParseExt(&p, qtrue); - if(token[0] != '{' && token[1] != '\0') + if(token[0] != '{' || token[1] != '\0') { - ri.Printf(PRINT_WARNING, "WARNING: Bad shader file %s has incorrect syntax.\n", filename); + ri.Printf(PRINT_WARNING, "WARNING: Ignoring shader file %s. Shader \"%s\" on line %d missing opening brace", + filename, shaderName, shaderLine); + if (token[0]) + { + ri.Printf(PRINT_WARNING, " (found \"%s\" on line %d)", token, COM_GetCurrentParseLine()); + } + ri.Printf(PRINT_WARNING, ".\n"); ri.FS_FreeFile(buffers[i]); buffers[i] = NULL; break; } - SkipBracedSection(&oldp); - p = oldp; + if(!SkipBracedSection(&p, 1)) + { + ri.Printf(PRINT_WARNING, "WARNING: Ignoring shader file %s. Shader \"%s\" on line %d missing closing brace.\n", + filename, shaderName, shaderLine); + ri.FS_FreeFile(buffers[i]); + buffers[i] = NULL; + break; + } } @@ -3630,7 +3664,7 @@ static void ScanAndLoadShaderFiles( void ) hash = generateHashValue(token, MAX_SHADERTEXT_HASH); shaderTextHashTableSizes[hash]++; size++; - SkipBracedSection(&p); + SkipBracedSection(&p, 0); } size += MAX_SHADERTEXT_HASH; @@ -3656,7 +3690,7 @@ static void ScanAndLoadShaderFiles( void ) hash = generateHashValue(token, MAX_SHADERTEXT_HASH); shaderTextHashTable[hash][shaderTextHashTableSizes[hash]++] = oldp; - SkipBracedSection(&p); + SkipBracedSection(&p, 0); } return; @@ -3708,6 +3742,31 @@ static void CreateExternalShaders( void ) { } tr.sunShader = R_FindShader( "sun", LIGHTMAP_NONE, qtrue ); + + tr.sunFlareShader = R_FindShader( "gfx/2d/sunflare", LIGHTMAP_NONE, qtrue); + + // HACK: if sunflare is missing, make one using the flare image or dlight image + if (tr.sunFlareShader->defaultShader) + { + image_t *image; + + if (!tr.flareShader->defaultShader && tr.flareShader->stages[0] && tr.flareShader->stages[0]->bundle[0].image[0]) + image = tr.flareShader->stages[0]->bundle[0].image[0]; + else + image = tr.dlightImage; + + Com_Memset( &shader, 0, sizeof( shader ) ); + Com_Memset( &stages, 0, sizeof( stages ) ); + + Q_strncpyz( shader.name, "gfx/2d/sunflare", sizeof( shader.name ) ); + + shader.lightmapIndex = LIGHTMAP_NONE; + stages[0].bundle[0].image[0] = image; + stages[0].active = qtrue; + stages[0].stateBits = GLS_DEFAULT; + tr.sunFlareShader = FinishShader(); + } + } /* diff --git a/code/renderer/tr_shadows.c b/code/renderergl2/tr_shadows.c similarity index 100% rename from code/renderer/tr_shadows.c rename to code/renderergl2/tr_shadows.c diff --git a/code/rend2/tr_sky.c b/code/renderergl2/tr_sky.c similarity index 88% rename from code/rend2/tr_sky.c rename to code/renderergl2/tr_sky.c index 62f0cadd..f1e5249d 100644 --- a/code/rend2/tr_sky.c +++ b/code/renderergl2/tr_sky.c @@ -393,7 +393,7 @@ static void DrawSkySide( struct image_s *image, const int mins[2], const int max if(tess.numVertexes >= SHADER_MAX_VERTEXES) { - ri.Error(ERR_DROP, "SHADER_MAX_VERTEXES hit in DrawSkySideVBO()\n"); + ri.Error(ERR_DROP, "SHADER_MAX_VERTEXES hit in DrawSkySideVBO()"); } } } @@ -404,7 +404,7 @@ static void DrawSkySide( struct image_s *image, const int mins[2], const int max { if (tess.numIndexes + 6 >= SHADER_MAX_INDEXES) { - ri.Error(ERR_DROP, "SHADER_MAX_INDEXES hit in DrawSkySideVBO()\n"); + ri.Error(ERR_DROP, "SHADER_MAX_INDEXES hit in DrawSkySideVBO()"); } tess.indexes[tess.numIndexes++] = s + t * (maxs[0] - mins[0] + 1) + firstVertex; @@ -429,13 +429,13 @@ static void DrawSkySide( struct image_s *image, const int mins[2], const int max GLSL_VertexAttribsState(ATTR_POSITION | ATTR_TEXCOORD); GLSL_BindProgram(sp); - GLSL_SetUniformMatrix16(sp, TEXTURECOLOR_UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); + GLSL_SetUniformMatrix16(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); color[0] = color[1] = color[2] = tr.identityLight; color[3] = 1.0f; - GLSL_SetUniformVec4(sp, TEXTURECOLOR_UNIFORM_COLOR, color); + GLSL_SetUniformVec4(sp, UNIFORM_COLOR, color); } */ { @@ -445,25 +445,25 @@ static void DrawSkySide( struct image_s *image, const int mins[2], const int max GLSL_VertexAttribsState(ATTR_POSITION | ATTR_TEXCOORD); GLSL_BindProgram(sp); - GLSL_SetUniformMatrix16(sp, GENERIC_UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); + GLSL_SetUniformMatrix16(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); color[0] = color[1] = color[2] = tr.identityLight; color[3] = 1.0f; - GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_BASECOLOR, color); + GLSL_SetUniformVec4(sp, UNIFORM_BASECOLOR, color); color[0] = color[1] = color[2] = color[3] = 0.0f; - GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_VERTCOLOR, color); + GLSL_SetUniformVec4(sp, UNIFORM_VERTCOLOR, color); VectorSet4(vector, 1.0, 0.0, 0.0, 1.0); - GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_DIFFUSETEXMATRIX, vector); + GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXMATRIX, vector); VectorSet4(vector, 0.0, 0.0, 0.0, 0.0); - GLSL_SetUniformVec4(sp, GENERIC_UNIFORM_DIFFUSETEXOFFTURB, vector); + GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXOFFTURB, vector); } R_DrawElementsVBO(tess.numIndexes - tess.firstIndex, tess.firstIndex, tess.minIndex, tess.maxIndex); @@ -793,32 +793,28 @@ void R_InitSkyTexCoords( float heightCloud ) /* ** RB_DrawSun */ -void RB_DrawSun( void ) { +void RB_DrawSun( float scale, shader_t *shader ) { float size; float dist; vec3_t origin, vec1, vec2; - vec3_t temp; if ( !backEnd.skyRenderedThisView ) { return; } - if ( !r_drawSun->integer ) { - return; - } //qglLoadMatrixf( backEnd.viewParms.world.modelMatrix ); //qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]); { // FIXME: this could be a lot cleaner - matrix_t trans, product; + matrix_t translation, modelview; - Matrix16Translation( backEnd.viewParms.or.origin, trans ); - Matrix16Multiply( backEnd.viewParms.world.modelMatrix, trans, product ); - GL_SetModelviewMatrix( product ); + Matrix16Translation( backEnd.viewParms.or.origin, translation ); + Matrix16Multiply( backEnd.viewParms.world.modelMatrix, translation, modelview ); + GL_SetModelviewMatrix( modelview ); } dist = backEnd.viewParms.zFar / 1.75; // div sqrt(3) - size = dist * 0.4; + size = dist * scale; VectorScale( tr.sunDirection, dist, origin ); PerpendicularVector( vec1, tr.sunDirection ); @@ -830,58 +826,9 @@ void RB_DrawSun( void ) { // farthest depth range qglDepthRange( 1.0, 1.0 ); - // FIXME: use quad stamp - RB_BeginSurface( tr.sunShader, tess.fogNum ); - VectorCopy( origin, temp ); - VectorSubtract( temp, vec1, temp ); - VectorSubtract( temp, vec2, temp ); - VectorCopy( temp, tess.xyz[tess.numVertexes] ); - tess.texCoords[tess.numVertexes][0][0] = 0; - tess.texCoords[tess.numVertexes][0][1] = 0; - tess.vertexColors[tess.numVertexes][0] = 1.0f; - tess.vertexColors[tess.numVertexes][1] = 1.0f; - tess.vertexColors[tess.numVertexes][2] = 1.0f; - tess.numVertexes++; + RB_BeginSurface( shader, 0 ); - VectorCopy( origin, temp ); - VectorAdd( temp, vec1, temp ); - VectorSubtract( temp, vec2, temp ); - VectorCopy( temp, tess.xyz[tess.numVertexes] ); - tess.texCoords[tess.numVertexes][0][0] = 0; - tess.texCoords[tess.numVertexes][0][1] = 1; - tess.vertexColors[tess.numVertexes][0] = 1.0f; - tess.vertexColors[tess.numVertexes][1] = 1.0f; - tess.vertexColors[tess.numVertexes][2] = 1.0f; - tess.numVertexes++; - - VectorCopy( origin, temp ); - VectorAdd( temp, vec1, temp ); - VectorAdd( temp, vec2, temp ); - VectorCopy( temp, tess.xyz[tess.numVertexes] ); - tess.texCoords[tess.numVertexes][0][0] = 1; - tess.texCoords[tess.numVertexes][0][1] = 1; - tess.vertexColors[tess.numVertexes][0] = 1.0f; - tess.vertexColors[tess.numVertexes][1] = 1.0f; - tess.vertexColors[tess.numVertexes][2] = 1.0f; - tess.numVertexes++; - - VectorCopy( origin, temp ); - VectorSubtract( temp, vec1, temp ); - VectorAdd( temp, vec2, temp ); - VectorCopy( temp, tess.xyz[tess.numVertexes] ); - tess.texCoords[tess.numVertexes][0][0] = 1; - tess.texCoords[tess.numVertexes][0][1] = 0; - tess.vertexColors[tess.numVertexes][0] = 1.0f; - tess.vertexColors[tess.numVertexes][1] = 1.0f; - tess.vertexColors[tess.numVertexes][2] = 1.0f; - tess.numVertexes++; - - tess.indexes[tess.numIndexes++] = 0; - tess.indexes[tess.numIndexes++] = 1; - tess.indexes[tess.numIndexes++] = 2; - tess.indexes[tess.numIndexes++] = 0; - tess.indexes[tess.numIndexes++] = 2; - tess.indexes[tess.numIndexes++] = 3; + RB_AddQuadStamp(origin, vec1, vec2, colorWhite); RB_EndSurface(); diff --git a/code/renderer/tr_subs.c b/code/renderergl2/tr_subs.c similarity index 100% rename from code/renderer/tr_subs.c rename to code/renderergl2/tr_subs.c diff --git a/code/rend2/tr_surface.c b/code/renderergl2/tr_surface.c similarity index 89% rename from code/rend2/tr_surface.c rename to code/renderergl2/tr_surface.c index aeba2c81..427d153d 100644 --- a/code/rend2/tr_surface.c +++ b/code/renderergl2/tr_surface.c @@ -124,44 +124,30 @@ void RB_AddQuadStampExt( vec3_t origin, vec3_t left, vec3_t up, float color[4], // constant normal all the way around VectorSubtract( vec3_origin, backEnd.viewParms.or.axis[0], normal ); - tess.normal[ndx][0] = tess.normal[ndx+1][0] = tess.normal[ndx+2][0] = tess.normal[ndx+3][0] = normal[0]; - tess.normal[ndx][1] = tess.normal[ndx+1][1] = tess.normal[ndx+2][1] = tess.normal[ndx+3][1] = normal[1]; - tess.normal[ndx][2] = tess.normal[ndx+1][2] = tess.normal[ndx+2][2] = tess.normal[ndx+3][2] = normal[2]; + VectorCopy(normal, tess.normal[ndx]); + VectorCopy(normal, tess.normal[ndx+1]); + VectorCopy(normal, tess.normal[ndx+2]); + VectorCopy(normal, tess.normal[ndx+3]); // standard square texture coordinates - tess.texCoords[ndx][0][0] = tess.texCoords[ndx][1][0] = s1; - tess.texCoords[ndx][0][1] = tess.texCoords[ndx][1][1] = t1; + VectorSet2(tess.texCoords[ndx ][0], s1, t1); + VectorSet2(tess.texCoords[ndx ][1], s1, t1); - tess.texCoords[ndx+1][0][0] = tess.texCoords[ndx+1][1][0] = s2; - tess.texCoords[ndx+1][0][1] = tess.texCoords[ndx+1][1][1] = t1; + VectorSet2(tess.texCoords[ndx+1][0], s2, t1); + VectorSet2(tess.texCoords[ndx+1][1], s2, t1); - tess.texCoords[ndx+2][0][0] = tess.texCoords[ndx+2][1][0] = s2; - tess.texCoords[ndx+2][0][1] = tess.texCoords[ndx+2][1][1] = t2; + VectorSet2(tess.texCoords[ndx+2][0], s2, t2); + VectorSet2(tess.texCoords[ndx+2][1], s2, t2); - tess.texCoords[ndx+3][0][0] = tess.texCoords[ndx+3][1][0] = s1; - tess.texCoords[ndx+3][0][1] = tess.texCoords[ndx+3][1][1] = t2; + VectorSet2(tess.texCoords[ndx+3][0], s1, t2); + VectorSet2(tess.texCoords[ndx+3][1], s1, t2); // constant color all the way around // should this be identity and let the shader specify from entity? - tess.vertexColors[ndx][0] = color[0]; - tess.vertexColors[ndx][1] = color[1]; - tess.vertexColors[ndx][2] = color[2]; - tess.vertexColors[ndx][3] = color[3]; - - tess.vertexColors[ndx+1][0] = color[0]; - tess.vertexColors[ndx+1][1] = color[1]; - tess.vertexColors[ndx+1][2] = color[2]; - tess.vertexColors[ndx+1][3] = color[3]; - - tess.vertexColors[ndx+2][0] = color[0]; - tess.vertexColors[ndx+2][1] = color[1]; - tess.vertexColors[ndx+2][2] = color[2]; - tess.vertexColors[ndx+2][3] = color[3]; - - tess.vertexColors[ndx+3][0] = color[0]; - tess.vertexColors[ndx+3][1] = color[1]; - tess.vertexColors[ndx+3][2] = color[2]; - tess.vertexColors[ndx+3][3] = color[3]; + VectorCopy4(color, tess.vertexColors[ndx]); + VectorCopy4(color, tess.vertexColors[ndx+1]); + VectorCopy4(color, tess.vertexColors[ndx+2]); + VectorCopy4(color, tess.vertexColors[ndx+3]); tess.numVertexes += 4; tess.numIndexes += 6; @@ -233,36 +219,19 @@ void RB_InstantQuad2(vec4_t quadVerts[4], vec2_t texCoords[4]) void RB_InstantQuad(vec4_t quadVerts[4]) { - vec4_t color; vec2_t texCoords[4]; - vec2_t invTexRes; - VectorSet4(color, 1, 1, 1, 1); - - texCoords[0][0] = 0; - texCoords[0][1] = 0; - - texCoords[1][0] = 1; - texCoords[1][1] = 0; - - texCoords[2][0] = 1; - texCoords[2][1] = 1; - - texCoords[3][0] = 0; - texCoords[3][1] = 1; - - invTexRes[0] = 1.0f / 256.0f; - invTexRes[1] = 1.0f / 256.0f; + VectorSet2(texCoords[0], 0.0f, 0.0f); + VectorSet2(texCoords[1], 1.0f, 0.0f); + VectorSet2(texCoords[2], 1.0f, 1.0f); + VectorSet2(texCoords[3], 0.0f, 1.0f); GLSL_BindProgram(&tr.textureColorShader); - GLSL_SetUniformMatrix16(&tr.textureColorShader, TEXTURECOLOR_UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); - GLSL_SetUniformVec4(&tr.textureColorShader, TEXTURECOLOR_UNIFORM_COLOR, color); - GLSL_SetUniformVec2(&tr.textureColorShader, TEXTURECOLOR_UNIFORM_INVTEXRES, invTexRes); - GLSL_SetUniformVec2(&tr.textureColorShader, TEXTURECOLOR_UNIFORM_AUTOEXPOSUREMINMAX, tr.refdef.autoExposureMinMax); - GLSL_SetUniformVec3(&tr.textureColorShader, TEXTURECOLOR_UNIFORM_TONEMINAVGMAXLINEAR, tr.refdef.toneMinAvgMaxLinear); + GLSL_SetUniformMatrix16(&tr.textureColorShader, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); + GLSL_SetUniformVec4(&tr.textureColorShader, UNIFORM_COLOR, colorWhite); - RB_InstantQuad2(quadVerts, texCoords); //, color, &tr.textureColorShader, invTexRes); + RB_InstantQuad2(quadVerts, texCoords); } @@ -300,27 +269,7 @@ static void RB_SurfaceSprite( void ) { VectorSubtract( vec3_origin, left, left ); } -#ifdef REACTION - if (ent->e.renderfx & RF_SUNFLARE) - { - if (backEnd.viewHasSunFlare) - { - ri.Printf(PRINT_WARNING, "Multiple sun flares not supported\n"); - return; - } - if (R_CullPointAndRadiusEx(ent->e.origin, ent->e.radius, backEnd.viewParms.frustum, ARRAY_LEN(backEnd.viewParms.frustum)) == CULL_OUT) - return; - colors[0] = colors[1] = colors[2] = colors[3] = ent->e.shaderRGBA[glRefConfig.framebufferObject] / 255.0f; - if (colors[0] == 0) - return; - backEnd.viewHasSunFlare = qtrue; - backEnd.frameHasSunFlare = qtrue; - } - else -#endif - { - VectorScale4(ent->e.shaderRGBA, 1.0f / 255.0f, colors); - } + VectorScale4(ent->e.shaderRGBA, 1.0f / 255.0f, colors); RB_AddQuadStamp( ent->e.origin, left, up, colors ); } @@ -362,9 +311,9 @@ static void RB_SurfacePolychain( srfPoly_t *p ) { tess.numVertexes = numv; } -static void RB_SurfaceHelper( int numVerts, srfVert_t *verts, int numTriangles, srfTriangle_t *triangles, int dlightBits, int pshadowBits) +static void RB_SurfaceVertsAndTris( int numVerts, srfVert_t *verts, int numTriangles, srfTriangle_t *triangles, int dlightBits, int pshadowBits) { - int i; + int i; srfTriangle_t *tri; srfVert_t *dv; float *xyz, *normal, *texCoords, *lightCoords, *lightdir; @@ -372,7 +321,7 @@ static void RB_SurfaceHelper( int numVerts, srfVert_t *verts, int numTriangles, float *tangent, *bitangent; #endif glIndex_t *index; - float *color; + float *color; RB_CheckVBOandIBO(tess.vbo, tess.ibo); @@ -465,7 +414,7 @@ static void RB_SurfaceHelper( int numVerts, srfVert_t *verts, int numTriangles, tess.numVertexes += numVerts; } -static qboolean RB_SurfaceHelperVBO(VBO_t *vbo, IBO_t *ibo, int numVerts, int numIndexes, int firstIndex, int minIndex, int maxIndex, int dlightBits, int pshadowBits, qboolean shaderCheck) +static qboolean RB_SurfaceVbo(VBO_t *vbo, IBO_t *ibo, int numVerts, int numIndexes, int firstIndex, int minIndex, int maxIndex, int dlightBits, int pshadowBits, qboolean shaderCheck) { int i, mergeForward, mergeBack; GLvoid *firstIndexOffset, *lastIndexOffset; @@ -574,12 +523,14 @@ RB_SurfaceTriangles ============= */ static void RB_SurfaceTriangles( srfTriangles_t *srf ) { - if( RB_SurfaceHelperVBO (srf->vbo, srf->ibo, srf->numVerts, srf->numTriangles * 3, srf->firstIndex, srf->minIndex, srf->maxIndex, srf->dlightBits[backEnd.smpFrame], srf->pshadowBits[backEnd.smpFrame], qtrue ) ) + if( RB_SurfaceVbo (srf->vbo, srf->ibo, srf->numVerts, srf->numTriangles * 3, + srf->firstIndex, srf->minIndex, srf->maxIndex, srf->dlightBits, srf->pshadowBits, qtrue ) ) { return; } - RB_SurfaceHelper(srf->numVerts, srf->verts, srf->numTriangles, srf->triangles, srf->dlightBits[backEnd.smpFrame], srf->pshadowBits[backEnd.smpFrame]); + RB_SurfaceVertsAndTris(srf->numVerts, srf->verts, srf->numTriangles, + srf->triangles, srf->dlightBits, srf->pshadowBits); } @@ -593,6 +544,7 @@ static void RB_SurfaceBeam( void ) { #define NUM_BEAM_SEGS 6 refEntity_t *e; + shaderProgram_t *sp = &tr.textureColorShader; int i; vec3_t perpvec; vec3_t direction, normalized_direction; @@ -659,21 +611,12 @@ static void RB_SurfaceBeam( void ) // FIXME: A lot of this can probably be removed for speed, and refactored into a more convenient function RB_UpdateVBOs(ATTR_POSITION); - { - shaderProgram_t *sp = &tr.textureColorShader; - vec4_t color; - - GLSL_VertexAttribsState(ATTR_POSITION); - GLSL_BindProgram(sp); + GLSL_VertexAttribsState(ATTR_POSITION); + GLSL_BindProgram(sp); - GLSL_SetUniformMatrix16(sp, TEXTURECOLOR_UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); + GLSL_SetUniformMatrix16(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); - color[0] = 1.0f; - color[1] = 0.0f; - color[2] = 0.0f; - color[3] = 1.0f; - GLSL_SetUniformVec4(sp, TEXTURECOLOR_UNIFORM_COLOR, color); - } + GLSL_SetUniformVec4(sp, UNIFORM_COLOR, colorRed); R_DrawElementsVBO(tess.numIndexes, tess.firstIndex, tess.minIndex, tess.maxIndex); @@ -1305,12 +1248,14 @@ RB_SurfaceFace ============== */ static void RB_SurfaceFace( srfSurfaceFace_t *srf ) { - if( RB_SurfaceHelperVBO (srf->vbo, srf->ibo, srf->numVerts, srf->numTriangles * 3, srf->firstIndex, srf->minIndex, srf->maxIndex, srf->dlightBits[backEnd.smpFrame], srf->pshadowBits[backEnd.smpFrame], qtrue ) ) + if( RB_SurfaceVbo (srf->vbo, srf->ibo, srf->numVerts, srf->numTriangles * 3, + srf->firstIndex, srf->minIndex, srf->maxIndex, srf->dlightBits, srf->pshadowBits, qtrue ) ) { return; } - RB_SurfaceHelper(srf->numVerts, srf->verts, srf->numTriangles, srf->triangles, srf->dlightBits[backEnd.smpFrame], srf->pshadowBits[backEnd.smpFrame]); + RB_SurfaceVertsAndTris(srf->numVerts, srf->verts, srf->numTriangles, + srf->triangles, srf->dlightBits, srf->pshadowBits); } @@ -1372,15 +1317,16 @@ static void RB_SurfaceGrid( srfGridMesh_t *srf ) { int pshadowBits; //int *vDlightBits; - if( RB_SurfaceHelperVBO (srf->vbo, srf->ibo, srf->numVerts, srf->numTriangles * 3, srf->firstIndex, srf->minIndex, srf->maxIndex, srf->dlightBits[backEnd.smpFrame], srf->pshadowBits[backEnd.smpFrame], qtrue ) ) + if( RB_SurfaceVbo (srf->vbo, srf->ibo, srf->numVerts, srf->numTriangles * 3, + srf->firstIndex, srf->minIndex, srf->maxIndex, srf->dlightBits, srf->pshadowBits, qtrue ) ) { return; } - dlightBits = srf->dlightBits[backEnd.smpFrame]; + dlightBits = srf->dlightBits; tess.dlightBits |= dlightBits; - pshadowBits = srf->pshadowBits[backEnd.smpFrame]; + pshadowBits = srf->pshadowBits; tess.pshadowBits |= pshadowBits; // determine the allowable discrepance @@ -1569,6 +1515,7 @@ static void RB_SurfaceAxis( void ) { // FIXME: implement this #if 0 GL_Bind( tr.whiteImage ); + GL_State( GLS_DEFAULT ); qglLineWidth( 3 ); qglBegin( GL_LINES ); qglColor3f( 1,0,0 ); @@ -1615,7 +1562,6 @@ static void RB_SurfaceEntity( surfaceType_t *surfType ) { RB_SurfaceAxis(); break; } - return; } static void RB_SurfaceBad( surfaceType_t *surfType ) { @@ -1630,7 +1576,8 @@ static void RB_SurfaceFlare(srfFlare_t *surf) static void RB_SurfaceVBOMesh(srfVBOMesh_t * srf) { - RB_SurfaceHelperVBO (srf->vbo, srf->ibo, srf->numVerts, srf->numIndexes, srf->firstIndex, srf->minIndex, srf->maxIndex, srf->dlightBits[backEnd.smpFrame], srf->pshadowBits[backEnd.smpFrame], qfalse ); + RB_SurfaceVbo (srf->vbo, srf->ibo, srf->numVerts, srf->numIndexes, srf->firstIndex, + srf->minIndex, srf->maxIndex, srf->dlightBits, srf->pshadowBits, qfalse ); } void RB_SurfaceVBOMDVMesh(srfVBOMDVMesh_t * surface) @@ -1700,9 +1647,7 @@ void (*rb_surfaceTable[SF_NUM_SURFACE_TYPES])( void *) = { (void(*)(void*))RB_SurfacePolychain, // SF_POLY, (void(*)(void*))RB_SurfaceMesh, // SF_MDV, (void(*)(void*))RB_SurfaceAnim, // SF_MD4, -#ifdef RAVENMD4 (void(*)(void*))RB_MDRSurfaceAnim, // SF_MDR, -#endif (void(*)(void*))RB_IQMSurfaceAnim, // SF_IQM, (void(*)(void*))RB_SurfaceFlare, // SF_FLARE, (void(*)(void*))RB_SurfaceEntity, // SF_ENTITY diff --git a/code/rend2/tr_vbo.c b/code/renderergl2/tr_vbo.c similarity index 96% rename from code/rend2/tr_vbo.c rename to code/renderergl2/tr_vbo.c index 41af9375..e9f2598b 100644 --- a/code/rend2/tr_vbo.c +++ b/code/renderergl2/tr_vbo.c @@ -49,15 +49,14 @@ VBO_t *R_CreateVBO(const char *name, byte * vertexes, int vertexesSize, if(strlen(name) >= MAX_QPATH) { - ri.Error(ERR_DROP, "R_CreateVBO: \"%s\" is too long\n", name); + ri.Error(ERR_DROP, "R_CreateVBO: \"%s\" is too long", name); } if ( tr.numVBOs == MAX_VBOS ) { - ri.Error( ERR_DROP, "R_CreateVBO: MAX_VBOS hit\n"); + ri.Error( ERR_DROP, "R_CreateVBO: MAX_VBOS hit"); } - // make sure the render thread is stopped - R_SyncRenderThread(); + R_IssuePendingRenderCommands(); vbo = tr.vbos[tr.numVBOs] = ri.Hunk_Alloc(sizeof(*vbo), h_low); tr.numVBOs++; @@ -118,15 +117,14 @@ VBO_t *R_CreateVBO2(const char *name, int numVertexes, srfVert_t * vert if(strlen(name) >= MAX_QPATH) { - ri.Error(ERR_DROP, "R_CreateVBO2: \"%s\" is too long\n", name); + ri.Error(ERR_DROP, "R_CreateVBO2: \"%s\" is too long", name); } if ( tr.numVBOs == MAX_VBOS ) { - ri.Error( ERR_DROP, "R_CreateVBO2: MAX_VBOS hit\n"); + ri.Error( ERR_DROP, "R_CreateVBO2: MAX_VBOS hit"); } - // make sure the render thread is stopped - R_SyncRenderThread(); + R_IssuePendingRenderCommands(); vbo = tr.vbos[tr.numVBOs] = ri.Hunk_Alloc(sizeof(*vbo), h_low); tr.numVBOs++; @@ -468,15 +466,14 @@ IBO_t *R_CreateIBO(const char *name, byte * indexes, int indexesSize, v if(strlen(name) >= MAX_QPATH) { - ri.Error(ERR_DROP, "R_CreateIBO: \"%s\" is too long\n", name); + ri.Error(ERR_DROP, "R_CreateIBO: \"%s\" is too long", name); } if ( tr.numIBOs == MAX_IBOS ) { - ri.Error( ERR_DROP, "R_CreateIBO: MAX_IBOS hit\n"); + ri.Error( ERR_DROP, "R_CreateIBO: MAX_IBOS hit"); } - // make sure the render thread is stopped - R_SyncRenderThread(); + R_IssuePendingRenderCommands(); ibo = tr.ibos[tr.numIBOs] = ri.Hunk_Alloc(sizeof(*ibo), h_low); tr.numIBOs++; @@ -537,15 +534,14 @@ IBO_t *R_CreateIBO2(const char *name, int numTriangles, srfTriangle_t * if(strlen(name) >= MAX_QPATH) { - ri.Error(ERR_DROP, "R_CreateIBO2: \"%s\" is too long\n", name); + ri.Error(ERR_DROP, "R_CreateIBO2: \"%s\" is too long", name); } if ( tr.numIBOs == MAX_IBOS ) { - ri.Error( ERR_DROP, "R_CreateIBO2: MAX_IBOS hit\n"); + ri.Error( ERR_DROP, "R_CreateIBO2: MAX_IBOS hit"); } - // make sure the render thread is stopped - R_SyncRenderThread(); + R_IssuePendingRenderCommands(); ibo = tr.ibos[tr.numIBOs] = ri.Hunk_Alloc(sizeof(*ibo), h_low); tr.numIBOs++; @@ -846,7 +842,7 @@ RB_UpdateVBOs Adapted from Tess_UpdateVBOs from xreal -Tr3B: update the default VBO to replace the client side vertex arrays +Update the default VBO to replace the client side vertex arrays ============== */ void RB_UpdateVBOs(unsigned int attribBits) diff --git a/code/rend2/tr_world.c b/code/renderergl2/tr_world.c similarity index 94% rename from code/rend2/tr_world.c rename to code/renderergl2/tr_world.c index 54287be4..e67be16f 100644 --- a/code/rend2/tr_world.c +++ b/code/renderergl2/tr_world.c @@ -36,6 +36,10 @@ static qboolean R_CullSurface( msurface_t *surf ) { return qfalse; } + if ( *surf->data == SF_GRID && r_nocurves->integer ) { + return qtrue; + } + if (surf->cullinfo.type & CULLINFO_PLANE) { // Only true for SF_FACE, so treat like its own function @@ -119,11 +123,6 @@ static qboolean R_CullSurface( msurface_t *surf ) { { return qtrue; } - - if ( sphereCull == CULL_IN ) - { - return qfalse; - } } if (surf->cullinfo.type & CULLINFO_BOX) @@ -140,11 +139,6 @@ static qboolean R_CullSurface( msurface_t *surf ) { { return qtrue; } - - if ( boxCull == CULL_IN ) - { - return qfalse; - } } return qfalse; @@ -167,7 +161,6 @@ static int R_DlightSurface( msurface_t *surf, int dlightBits ) { if ( surf->cullinfo.type & CULLINFO_PLANE ) { - int i; for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) { if ( ! ( dlightBits & ( 1 << i ) ) ) { continue; @@ -216,19 +209,21 @@ static int R_DlightSurface( msurface_t *surf, int dlightBits ) { } if ( *surf->data == SF_FACE ) { - ((srfSurfaceFace_t *)surf->data)->dlightBits[ tr.smpFrame ] = dlightBits; + ((srfSurfaceFace_t *)surf->data)->dlightBits = dlightBits; } else if ( *surf->data == SF_GRID ) { - ((srfGridMesh_t *)surf->data)->dlightBits[ tr.smpFrame ] = dlightBits; + ((srfGridMesh_t *)surf->data)->dlightBits = dlightBits; } else if ( *surf->data == SF_TRIANGLES ) { - ((srfTriangles_t *)surf->data)->dlightBits[ tr.smpFrame ] = dlightBits; + ((srfTriangles_t *)surf->data)->dlightBits = dlightBits; } else if ( *surf->data == SF_VBO_MESH ) { - ((srfVBOMesh_t *)surf->data)->dlightBits[ tr.smpFrame ] = dlightBits; + ((srfVBOMesh_t *)surf->data)->dlightBits = dlightBits; } else { dlightBits = 0; } if ( dlightBits ) { tr.pc.c_dlightSurfaces++; + } else { + tr.pc.c_dlightSurfacesCulled++; } return dlightBits; @@ -248,7 +243,6 @@ static int R_PshadowSurface( msurface_t *surf, int pshadowBits ) { if ( surf->cullinfo.type & CULLINFO_PLANE ) { - int i; for ( i = 0 ; i < tr.refdef.num_pshadows ; i++ ) { if ( ! ( pshadowBits & ( 1 << i ) ) ) { continue; @@ -299,13 +293,13 @@ static int R_PshadowSurface( msurface_t *surf, int pshadowBits ) { } if ( *surf->data == SF_FACE ) { - ((srfSurfaceFace_t *)surf->data)->pshadowBits[ tr.smpFrame ] = pshadowBits; + ((srfSurfaceFace_t *)surf->data)->pshadowBits = pshadowBits; } else if ( *surf->data == SF_GRID ) { - ((srfGridMesh_t *)surf->data)->pshadowBits[ tr.smpFrame ] = pshadowBits; + ((srfGridMesh_t *)surf->data)->pshadowBits = pshadowBits; } else if ( *surf->data == SF_TRIANGLES ) { - ((srfTriangles_t *)surf->data)->pshadowBits[ tr.smpFrame ] = pshadowBits; + ((srfTriangles_t *)surf->data)->pshadowBits = pshadowBits; } else if ( *surf->data == SF_VBO_MESH ) { - ((srfVBOMesh_t *)surf->data)->pshadowBits[ tr.smpFrame ] = pshadowBits; + ((srfVBOMesh_t *)surf->data)->pshadowBits = pshadowBits; } else { pshadowBits = 0; } @@ -564,7 +558,7 @@ static void R_RecursiveWorldNode( mnode_t *node, int planeBits, int dlightBits, } // add merged and unmerged surfaces - if (tr.world->viewSurfaces) + if (tr.world->viewSurfaces && !r_nocurves->integer) view = tr.world->viewSurfaces + node->firstmarksurface; else view = tr.world->marksurfaces + node->firstmarksurface; @@ -645,7 +639,7 @@ R_ClusterPVS ============== */ static const byte *R_ClusterPVS (int cluster) { - if (!tr.world || !tr.world->vis || cluster < 0 || cluster >= tr.world->numClusters ) { + if (!tr.world->vis || cluster < 0 || cluster >= tr.world->numClusters ) { return tr.world->novis; } @@ -782,6 +776,8 @@ R_AddWorldSurfaces ============= */ void R_AddWorldSurfaces (void) { + int planeBits, dlightBits, pshadowBits; + if ( !r_drawworld->integer ) { return; } @@ -809,19 +805,26 @@ void R_AddWorldSurfaces (void) { tr.refdef.num_pshadows = 32 ; } + planeBits = (tr.viewParms.flags & VPF_FARPLANEFRUSTUM) ? 31 : 15; + if ( tr.viewParms.flags & VPF_DEPTHSHADOW ) { - R_RecursiveWorldNode( tr.world->nodes, 31, 0, 0); + dlightBits = 0; + pshadowBits = 0; } else if ( !(tr.viewParms.flags & VPF_SHADOWMAP) ) { - R_RecursiveWorldNode( tr.world->nodes, 15, ( 1 << tr.refdef.num_dlights ) - 1, ( 1 << tr.refdef.num_pshadows ) - 1 ); + dlightBits = ( 1 << tr.refdef.num_dlights ) - 1; + pshadowBits = ( 1 << tr.refdef.num_pshadows ) - 1; } else { - R_RecursiveWorldNode( tr.world->nodes, 31, ( 1 << tr.refdef.num_dlights ) - 1, 0 ); + dlightBits = ( 1 << tr.refdef.num_dlights ) - 1; + pshadowBits = 0; } + R_RecursiveWorldNode( tr.world->nodes, planeBits, dlightBits, pshadowBits); + // now add all the potentially visible surfaces // also mask invisible dlights for next frame { diff --git a/code/sdl/sdl_gamma.c b/code/sdl/sdl_gamma.c index 94aaf5ad..a74ca6a8 100644 --- a/code/sdl/sdl_gamma.c +++ b/code/sdl/sdl_gamma.c @@ -26,7 +26,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # include #endif -#include "../renderer/tr_local.h" +#include "../renderercommon/tr_common.h" #include "../qcommon/qcommon.h" /* diff --git a/code/sdl/sdl_glimp.c b/code/sdl/sdl_glimp.c index 7e5d8153..0936c43d 100644 --- a/code/sdl/sdl_glimp.c +++ b/code/sdl/sdl_glimp.c @@ -26,20 +26,13 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # include #endif -#ifdef SMP -# ifdef USE_LOCAL_HEADERS -# include "SDL_thread.h" -# else -# include -# endif -#endif - #include #include #include #include -#include "../renderer/tr_local.h" +//FIXME: factor out the bits that are actually needed here into a renderercommon header +#include "../renderercommon/tr_common.h" #include "../sys/sys_local.h" #include "sdl_icon.h" @@ -93,9 +86,6 @@ void GLimp_Shutdown( void ) SDL_QuitSubSystem( SDL_INIT_VIDEO ); screen = NULL; - - Com_Memset( &glConfig, 0, sizeof( glConfig ) ); - Com_Memset( &glState, 0, sizeof( glState ) ); } /* @@ -835,245 +825,3 @@ void GLimp_EndFrame( void ) r_fullscreen->modified = qfalse; } } - - - -#ifdef SMP -/* -=========================================================== - -SMP acceleration - -=========================================================== -*/ - -/* - * I have no idea if this will even work...most platforms don't offer - * thread-safe OpenGL libraries, and it looks like the original Linux - * code counted on each thread claiming the GL context with glXMakeCurrent(), - * which you can't currently do in SDL. We'll just have to hope for the best. - */ - -static SDL_mutex *smpMutex = NULL; -static SDL_cond *renderCommandsEvent = NULL; -static SDL_cond *renderCompletedEvent = NULL; -static void (*glimpRenderThread)( void ) = NULL; -static SDL_Thread *renderThread = NULL; - -/* -=============== -GLimp_ShutdownRenderThread -=============== -*/ -static void GLimp_ShutdownRenderThread(void) -{ - if (smpMutex != NULL) - { - SDL_DestroyMutex(smpMutex); - smpMutex = NULL; - } - - if (renderCommandsEvent != NULL) - { - SDL_DestroyCond(renderCommandsEvent); - renderCommandsEvent = NULL; - } - - if (renderCompletedEvent != NULL) - { - SDL_DestroyCond(renderCompletedEvent); - renderCompletedEvent = NULL; - } - - glimpRenderThread = NULL; -} - -/* -=============== -GLimp_RenderThreadWrapper -=============== -*/ -static int GLimp_RenderThreadWrapper( void *arg ) -{ - Com_Printf( "Render thread starting\n" ); - - glimpRenderThread(); - - GLimp_SetCurrentContext(NULL); - - Com_Printf( "Render thread terminating\n" ); - - return 0; -} - -/* -=============== -GLimp_SpawnRenderThread -=============== -*/ -qboolean GLimp_SpawnRenderThread( void (*function)( void ) ) -{ - static qboolean warned = qfalse; - if (!warned) - { - Com_Printf("WARNING: You enable r_smp at your own risk!\n"); - warned = qtrue; - } - -#ifndef MACOS_X - return qfalse; /* better safe than sorry for now. */ -#endif - - if (renderThread != NULL) /* hopefully just a zombie at this point... */ - { - Com_Printf("Already a render thread? Trying to clean it up...\n"); - SDL_WaitThread(renderThread, NULL); - renderThread = NULL; - GLimp_ShutdownRenderThread(); - } - - smpMutex = SDL_CreateMutex(); - if (smpMutex == NULL) - { - Com_Printf( "smpMutex creation failed: %s\n", SDL_GetError() ); - GLimp_ShutdownRenderThread(); - return qfalse; - } - - renderCommandsEvent = SDL_CreateCond(); - if (renderCommandsEvent == NULL) - { - Com_Printf( "renderCommandsEvent creation failed: %s\n", SDL_GetError() ); - GLimp_ShutdownRenderThread(); - return qfalse; - } - - renderCompletedEvent = SDL_CreateCond(); - if (renderCompletedEvent == NULL) - { - Com_Printf( "renderCompletedEvent creation failed: %s\n", SDL_GetError() ); - GLimp_ShutdownRenderThread(); - return qfalse; - } - - glimpRenderThread = function; - renderThread = SDL_CreateThread(GLimp_RenderThreadWrapper, NULL); - if ( renderThread == NULL ) - { - ri.Printf( PRINT_ALL, "SDL_CreateThread() returned %s", SDL_GetError() ); - GLimp_ShutdownRenderThread(); - return qfalse; - } - else - { - // tma 01/09/07: don't think this is necessary anyway? - // - // !!! FIXME: No detach API available in SDL! - //ret = pthread_detach( renderThread ); - //if ( ret ) { - //ri.Printf( PRINT_ALL, "pthread_detach returned %d: %s", ret, strerror( ret ) ); - //} - } - - return qtrue; -} - -static volatile void *smpData = NULL; -static volatile qboolean smpDataReady; - -/* -=============== -GLimp_RendererSleep -=============== -*/ -void *GLimp_RendererSleep( void ) -{ - void *data = NULL; - - GLimp_SetCurrentContext(NULL); - - SDL_LockMutex(smpMutex); - { - smpData = NULL; - smpDataReady = qfalse; - - // after this, the front end can exit GLimp_FrontEndSleep - SDL_CondSignal(renderCompletedEvent); - - while ( !smpDataReady ) - SDL_CondWait(renderCommandsEvent, smpMutex); - - data = (void *)smpData; - } - SDL_UnlockMutex(smpMutex); - - GLimp_SetCurrentContext(opengl_context); - - return data; -} - -/* -=============== -GLimp_FrontEndSleep -=============== -*/ -void GLimp_FrontEndSleep( void ) -{ - SDL_LockMutex(smpMutex); - { - while ( smpData ) - SDL_CondWait(renderCompletedEvent, smpMutex); - } - SDL_UnlockMutex(smpMutex); - - GLimp_SetCurrentContext(opengl_context); -} - -/* -=============== -GLimp_WakeRenderer -=============== -*/ -void GLimp_WakeRenderer( void *data ) -{ - GLimp_SetCurrentContext(NULL); - - SDL_LockMutex(smpMutex); - { - assert( smpData == NULL ); - smpData = data; - smpDataReady = qtrue; - - // after this, the renderer can continue through GLimp_RendererSleep - SDL_CondSignal(renderCommandsEvent); - } - SDL_UnlockMutex(smpMutex); -} - -#else - -// No SMP - stubs -void GLimp_RenderThreadWrapper( void *arg ) -{ -} - -qboolean GLimp_SpawnRenderThread( void (*function)( void ) ) -{ - ri.Printf( PRINT_WARNING, "ERROR: SMP support was disabled at compile time\n"); - return qfalse; -} - -void *GLimp_RendererSleep( void ) -{ - return NULL; -} - -void GLimp_FrontEndSleep( void ) -{ -} - -void GLimp_WakeRenderer( void *data ) -{ -} - -#endif diff --git a/code/sdl/sdl_input.c b/code/sdl/sdl_input.c index 90500bd0..72c66096 100644 --- a/code/sdl/sdl_input.c +++ b/code/sdl/sdl_input.c @@ -912,17 +912,17 @@ static void IN_ProcessEvents( void ) case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: { - unsigned char b; + int b; switch( e.button.button ) { - case 1: b = K_MOUSE1; break; - case 2: b = K_MOUSE3; break; - case 3: b = K_MOUSE2; break; - case 4: b = K_MWHEELUP; break; - case 5: b = K_MWHEELDOWN; break; - case 6: b = K_MOUSE4; break; - case 7: b = K_MOUSE5; break; - default: b = K_AUX1 + ( e.button.button - 8 ) % 16; break; + case SDL_BUTTON_LEFT: b = K_MOUSE1; break; + case SDL_BUTTON_MIDDLE: b = K_MOUSE3; break; + case SDL_BUTTON_RIGHT: b = K_MOUSE2; break; + case SDL_BUTTON_WHEELUP: b = K_MWHEELUP; break; + case SDL_BUTTON_WHEELDOWN: b = K_MWHEELDOWN; break; + case SDL_BUTTON_X1: b = K_MOUSE4; break; + case SDL_BUTTON_X2: b = K_MOUSE5; break; + default: b = K_AUX1 + ( e.button.button - SDL_BUTTON_X2 + 1 ) % 16; break; } Com_QueueEvent( 0, SE_KEY, b, ( e.type == SDL_MOUSEBUTTONDOWN ? qtrue : qfalse ), 0, NULL ); diff --git a/code/server/server.h b/code/server/server.h index 3fefb602..b577591f 100644 --- a/code/server/server.h +++ b/code/server/server.h @@ -78,7 +78,6 @@ typedef struct { int snapshotCounter; // incremented for each snapshot built int timeResidual; // <= 1000 / sv_frame->value int nextFrameTime; // when time > nextFrameTime, process world - struct cmodel_s *models[MAX_MODELS]; char *configstrings[MAX_CONFIGSTRINGS]; svEntity_t svEntities[MAX_GENTITIES]; @@ -236,7 +235,7 @@ typedef struct { int snapFlagServerBit; // ^= SNAPFLAG_SERVERCOUNT every SV_SpawnServer() client_t *clients; // [sv_maxclients->integer]; - int numSnapshotEntities; // sv_maxclients->integer*PACKET_BACKUP*MAX_PACKET_ENTITIES + int numSnapshotEntities; // sv_maxclients->integer*PACKET_BACKUP*MAX_SNAPSHOT_ENTITIES int nextSnapshotEntities; // next snapshotEntities to use entityState_t *snapshotEntities; // [numSnapshotEntities] int nextHeartbeatTime; @@ -308,6 +307,28 @@ extern cvar_t *sv_voip; // // sv_main.c // +typedef struct leakyBucket_s leakyBucket_t; +struct leakyBucket_s { + netadrtype_t type; + + union { + byte _4[4]; + byte _6[16]; + } ipv; + + int lastTime; + signed char burst; + + long hash; + + leakyBucket_t *prev, *next; +}; + +extern leakyBucket_t outboundLeakyBucket; + +qboolean SVC_RateLimit( leakyBucket_t *bucket, int burst, int period ); +qboolean SVC_RateLimitAddress( netadr_t from, int burst, int period ); + void SV_FinalMessage (char *message); void QDECL SV_SendServerCommand( client_t *cl, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); diff --git a/code/server/sv_bot.c b/code/server/sv_bot.c index 3400a091..eb7089e1 100644 --- a/code/server/sv_bot.c +++ b/code/server/sv_bot.c @@ -451,6 +451,8 @@ int SV_BotLibSetup( void ) { return -1; } + botlib_export->BotLibVarSet( "basegame", com_basegame->string ); + return botlib_export->BotLibSetup(); } diff --git a/code/server/sv_client.c b/code/server/sv_client.c index 4012ee6e..2dcff87e 100644 --- a/code/server/sv_client.c +++ b/code/server/sv_client.c @@ -67,6 +67,20 @@ void SV_GetChallenge(netadr_t from) return; } + // Prevent using getchallenge as an amplifier + if ( SVC_RateLimitAddress( from, 10, 1000 ) ) { + Com_DPrintf( "SV_GetChallenge: rate limit from %s exceeded, dropping request\n", + NET_AdrToString( from ) ); + return; + } + + // Allow getchallenge to be DoSed relatively easily, but prevent + // excess outbound bandwidth usage when being flooded inbound + if ( SVC_RateLimit( &outboundLeakyBucket, 10, 100 ) ) { + Com_DPrintf( "SV_GetChallenge: rate limit exceeded, dropping request\n" ); + return; + } + gameName = Cmd_Argv(2); #ifdef LEGACY_PROTOCOL diff --git a/code/server/sv_init.c b/code/server/sv_init.c index 449547e4..2fa94dd7 100644 --- a/code/server/sv_init.c +++ b/code/server/sv_init.c @@ -271,10 +271,10 @@ static void SV_Startup( void ) { svs.clients = Z_Malloc (sizeof(client_t) * sv_maxclients->integer ); if ( com_dedicated->integer ) { - svs.numSnapshotEntities = sv_maxclients->integer * PACKET_BACKUP * 64; + svs.numSnapshotEntities = sv_maxclients->integer * PACKET_BACKUP * MAX_SNAPSHOT_ENTITIES; } else { // we don't need nearly as many when playing locally - svs.numSnapshotEntities = sv_maxclients->integer * 4 * 64; + svs.numSnapshotEntities = sv_maxclients->integer * 4 * MAX_SNAPSHOT_ENTITIES; } svs.initialized = qtrue; @@ -349,10 +349,10 @@ void SV_ChangeMaxClients( void ) { // allocate new snapshot entities if ( com_dedicated->integer ) { - svs.numSnapshotEntities = sv_maxclients->integer * PACKET_BACKUP * 64; + svs.numSnapshotEntities = sv_maxclients->integer * PACKET_BACKUP * MAX_SNAPSHOT_ENTITIES; } else { // we don't need nearly as many when playing locally - svs.numSnapshotEntities = sv_maxclients->integer * 4 * 64; + svs.numSnapshotEntities = sv_maxclients->integer * 4 * MAX_SNAPSHOT_ENTITIES; } } diff --git a/code/server/sv_main.c b/code/server/sv_main.c index afdac183..ed50707e 100644 --- a/code/server/sv_main.c +++ b/code/server/sv_main.c @@ -252,6 +252,9 @@ void SV_MasterHeartbeat(const char *message) if ( svs.time < svs.nextHeartbeatTime ) return; + if ( !Q_stricmp( com_gamename->string, LEGACY_MASTER_GAMENAME ) ) + message = LEGACY_HEARTBEAT_FOR_MASTER; + svs.nextHeartbeatTime = svs.time + HEARTBEAT_MSEC; // send to group masters @@ -333,7 +336,7 @@ Informs all masters that this server is going down ================= */ void SV_MasterShutdown( void ) { - // send a hearbeat right now + // send a heartbeat right now svs.nextHeartbeatTime = -9999; SV_MasterHeartbeat(HEARTBEAT_FOR_MASTER); @@ -354,30 +357,13 @@ CONNECTIONLESS COMMANDS ============================================================================== */ -typedef struct leakyBucket_s leakyBucket_t; -struct leakyBucket_s { - netadrtype_t type; - - union { - byte _4[4]; - byte _6[16]; - } ipv; - - int lastTime; - signed char burst; - - long hash; - - leakyBucket_t *prev, *next; -}; - // This is deliberately quite large to make it more of an effort to DoS #define MAX_BUCKETS 16384 #define MAX_HASHES 1024 static leakyBucket_t buckets[ MAX_BUCKETS ]; static leakyBucket_t *bucketHashes[ MAX_HASHES ]; -static leakyBucket_t outboundLeakyBucket; +leakyBucket_t outboundLeakyBucket; /* ================ @@ -494,7 +480,7 @@ static leakyBucket_t *SVC_BucketForAddress( netadr_t address, int burst, int per SVC_RateLimit ================ */ -static qboolean SVC_RateLimit( leakyBucket_t *bucket, int burst, int period ) { +qboolean SVC_RateLimit( leakyBucket_t *bucket, int burst, int period ) { if ( bucket != NULL ) { int now = Sys_Milliseconds(); int interval = now - bucket->lastTime; @@ -526,7 +512,7 @@ SVC_RateLimitAddress Rate limit for a particular address ================ */ -static qboolean SVC_RateLimitAddress( netadr_t from, int burst, int period ) { +qboolean SVC_RateLimitAddress( netadr_t from, int burst, int period ) { leakyBucket_t *bucket = SVC_BucketForAddress( from, burst, period ); return SVC_RateLimit( bucket, burst, period ); diff --git a/code/server/sv_snapshot.c b/code/server/sv_snapshot.c index 2499f040..6e4f2907 100644 --- a/code/server/sv_snapshot.c +++ b/code/server/sv_snapshot.c @@ -235,7 +235,6 @@ Build a client snapshot structure ============================================================================= */ -#define MAX_SNAPSHOT_ENTITIES 1024 typedef struct { int numSnapshotEntities; int snapshotEntities[MAX_SNAPSHOT_ENTITIES]; diff --git a/code/server/sv_world.c b/code/server/sv_world.c index 665043a0..94868142 100644 --- a/code/server/sv_world.c +++ b/code/server/sv_world.c @@ -257,7 +257,6 @@ void SV_LinkEntity( sharedEntity_t *gEnt ) { if ( gEnt->r.bmodel && (angles[0] || angles[1] || angles[2]) ) { // expand for rotation float max; - int i; max = RadiusFromBounds( gEnt->r.mins, gEnt->r.maxs ); for (i=0 ; i<3 ; i++) { diff --git a/code/sys/con_win32.c b/code/sys/con_win32.c index 1e22dd4e..edfa4e6a 100644 --- a/code/sys/con_win32.c +++ b/code/sys/con_win32.c @@ -28,6 +28,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define QCONSOLE_HISTORY 32 static WORD qconsole_attrib; +static WORD qconsole_backgroundAttrib; // saved console status static DWORD qconsole_orig_mode; @@ -41,10 +42,43 @@ static int qconsole_history_oldest = 0; // current edit buffer static char qconsole_line[ MAX_EDIT_LINE ]; static int qconsole_linelen = 0; +static qboolean qconsole_drawinput = qtrue; static HANDLE qconsole_hout; static HANDLE qconsole_hin; +/* +================== +CON_ColorCharToAttrib + +Convert Quake color character to Windows text attrib +================== +*/ +static WORD CON_ColorCharToAttrib( char color ) { + WORD attrib; + + if ( color == COLOR_WHITE ) + { + // use console's foreground and background colors + attrib = qconsole_attrib; + } + else + { + float *rgba = g_color_table[ ColorIndex( color ) ]; + + // set foreground color + attrib = ( rgba[0] >= 0.5 ? FOREGROUND_RED : 0 ) | + ( rgba[1] >= 0.5 ? FOREGROUND_GREEN : 0 ) | + ( rgba[2] >= 0.5 ? FOREGROUND_BLUE : 0 ) | + ( rgba[3] >= 0.5 ? FOREGROUND_INTENSITY : 0 ); + + // use console's background color + attrib |= qconsole_backgroundAttrib; + } + + return attrib; +} + /* ================== CON_CtrlHandler @@ -141,13 +175,15 @@ static void CON_Show( void ) COORD writeSize = { MAX_EDIT_LINE, 1 }; COORD writePos = { 0, 0 }; SMALL_RECT writeArea = { 0, 0, 0, 0 }; + COORD cursorPos; int i; CHAR_INFO line[ MAX_EDIT_LINE ]; + WORD attrib; GetConsoleScreenBufferInfo( qconsole_hout, &binfo ); // if we're in the middle of printf, don't bother writing the buffer - if( binfo.dwCursorPosition.X != 0 ) + if( !qconsole_drawinput ) return; writeArea.Left = 0; @@ -155,15 +191,23 @@ static void CON_Show( void ) writeArea.Bottom = binfo.dwCursorPosition.Y; writeArea.Right = MAX_EDIT_LINE; + // set color to white + attrib = CON_ColorCharToAttrib( COLOR_WHITE ); + // build a space-padded CHAR_INFO array for( i = 0; i < MAX_EDIT_LINE; i++ ) { if( i < qconsole_linelen ) + { + if( Q_IsColorString( qconsole_line + i ) ) + attrib = CON_ColorCharToAttrib( *( qconsole_line + i + 1 ) ); + line[ i ].Char.AsciiChar = qconsole_line[ i ]; + } else line[ i ].Char.AsciiChar = ' '; - line[ i ].Attributes = qconsole_attrib; + line[ i ].Attributes = attrib; } if( qconsole_linelen > binfo.srWindow.Right ) @@ -177,8 +221,33 @@ static void CON_Show( void ) WriteConsoleOutput( qconsole_hout, line, writeSize, writePos, &writeArea ); } + + // set curor position + cursorPos.Y = binfo.dwCursorPosition.Y; + cursorPos.X = qconsole_linelen > binfo.srWindow.Right ? binfo.srWindow.Right : qconsole_linelen; + + SetConsoleCursorPosition( qconsole_hout, cursorPos ); } +/* +================== +CON_Hide +================== +*/ +static void CON_Hide( void ) +{ + int realLen; + + realLen = qconsole_linelen; + + // remove input line from console output buffer + qconsole_linelen = 0; + CON_Show( ); + + qconsole_linelen = realLen; +} + + /* ================== CON_Shutdown @@ -186,8 +255,10 @@ CON_Shutdown */ void CON_Shutdown( void ) { + CON_Hide( ); SetConsoleMode( qconsole_hin, qconsole_orig_mode ); SetConsoleCursorInfo( qconsole_hout, &qconsole_orig_cursorinfo ); + SetConsoleTextAttribute( qconsole_hout, qconsole_attrib ); CloseHandle( qconsole_hout ); CloseHandle( qconsole_hin ); } @@ -199,7 +270,6 @@ CON_Init */ void CON_Init( void ) { - CONSOLE_CURSOR_INFO curs; CONSOLE_SCREEN_BUFFER_INFO info; int i; @@ -224,18 +294,16 @@ void CON_Init( void ) GetConsoleScreenBufferInfo( qconsole_hout, &info ); qconsole_attrib = info.wAttributes; + qconsole_backgroundAttrib = qconsole_attrib & (BACKGROUND_BLUE|BACKGROUND_GREEN|BACKGROUND_RED|BACKGROUND_INTENSITY); SetConsoleTitle(CLIENT_WINDOW_TITLE " Dedicated Server Console"); - // make cursor invisible - GetConsoleCursorInfo( qconsole_hout, &qconsole_orig_cursorinfo ); - curs.dwSize = 1; - curs.bVisible = FALSE; - SetConsoleCursorInfo( qconsole_hout, &curs ); - // initialize history for( i = 0; i < QCONSOLE_HISTORY; i++ ) qconsole_history[ i ][ 0 ] = '\0'; + + // set text color to white + SetConsoleTextAttribute( qconsole_hout, CON_ColorCharToAttrib( COLOR_WHITE ) ); } /* @@ -338,15 +406,74 @@ char *CON_Input( void ) return NULL; } - CON_HistAdd(); - Com_Printf( "%s\n", qconsole_line ); - qconsole_linelen = 0; CON_Show(); + CON_HistAdd(); + Com_Printf( "%s\n", qconsole_line ); + return qconsole_line; } +/* +================= +CON_WindowsColorPrint + +Set text colors based on Q3 color codes +================= +*/ +void CON_WindowsColorPrint( const char *msg ) +{ + static char buffer[ MAXPRINTMSG ]; + int length = 0; + + while( *msg ) + { + qconsole_drawinput = ( *msg == '\n' ); + + if( Q_IsColorString( msg ) || *msg == '\n' ) + { + // First empty the buffer + if( length > 0 ) + { + buffer[ length ] = '\0'; + fputs( buffer, stderr ); + length = 0; + } + + if( *msg == '\n' ) + { + // Reset color and then add the newline + SetConsoleTextAttribute( qconsole_hout, CON_ColorCharToAttrib( COLOR_WHITE ) ); + fputs( "\n", stderr ); + msg++; + } + else + { + // Set the color + SetConsoleTextAttribute( qconsole_hout, CON_ColorCharToAttrib( *( msg + 1 ) ) ); + msg += 2; + } + } + else + { + if( length >= MAXPRINTMSG - 1 ) + break; + + buffer[ length ] = *msg; + length++; + msg++; + } + } + + // Empty anything still left in the buffer + if( length > 0 ) + { + buffer[ length ] = '\0'; + fputs( buffer, stderr ); + } +} + /* ================== CON_Print @@ -354,7 +481,9 @@ CON_Print */ void CON_Print( const char *msg ) { - fputs( msg, stderr ); + CON_Hide( ); + + CON_WindowsColorPrint( msg ); CON_Show( ); } diff --git a/code/sys/sys_unix.c b/code/sys/sys_unix.c index 508383dd..607d0f21 100644 --- a/code/sys/sys_unix.c +++ b/code/sys/sys_unix.c @@ -123,7 +123,7 @@ qboolean Sys_RandomBytes( byte *string, int len ) if( !fp ) return qfalse; - if( !fread( string, sizeof( byte ), len, fp ) ) + if( fread( string, sizeof( byte ), len, fp ) != len ) { fclose( fp ); return qfalse; @@ -192,6 +192,21 @@ const char *Sys_Dirname( char *path ) return dirname( path ); } +/* +============== +Sys_FOpen +============== +*/ +FILE *Sys_FOpen( const char *ospath, const char *mode ) { + struct stat buf; + + // check if path exists and is a directory + if ( !stat( ospath, &buf ) && S_ISDIR( buf.st_mode ) ) + return NULL; + + return fopen( ospath, mode ); +} + /* ================== Sys_Mkdir diff --git a/code/sys/sys_win32.c b/code/sys/sys_win32.c index 47b2dae1..76fea307 100644 --- a/code/sys/sys_win32.c +++ b/code/sys/sys_win32.c @@ -89,15 +89,15 @@ char *Sys_DefaultHomePath( void ) TCHAR szPath[MAX_PATH]; FARPROC qSHGetFolderPath; HMODULE shfolder = LoadLibrary("shfolder.dll"); - + + if(shfolder == NULL) + { + Com_Printf("Unable to load SHFolder.dll\n"); + return NULL; + } + if(!*homePath && com_homepath) { - if(shfolder == NULL) - { - Com_Printf("Unable to load SHFolder.dll\n"); - return NULL; - } - qSHGetFolderPath = GetProcAddress(shfolder, "SHGetFolderPathA"); if(qSHGetFolderPath == NULL) { @@ -120,10 +120,9 @@ char *Sys_DefaultHomePath( void ) Q_strcat(homePath, sizeof(homePath), com_homepath->string); else Q_strcat(homePath, sizeof(homePath), HOMEPATH_NAME_WIN); - - FreeLibrary(shfolder); } + FreeLibrary(shfolder); return homePath; } @@ -283,6 +282,15 @@ const char *Sys_Dirname( char *path ) return dir; } +/* +============== +Sys_FOpen +============== +*/ +FILE *Sys_FOpen( const char *ospath, const char *mode ) { + return fopen( ospath, mode ); +} + /* ============== Sys_Mkdir diff --git a/code/tools/asm/q3asm.c b/code/tools/asm/q3asm.c index 331ba098..191a9db6 100644 --- a/code/tools/asm/q3asm.c +++ b/code/tools/asm/q3asm.c @@ -250,7 +250,6 @@ static void hashtable_init (hashtable_t *H, int buckets) { H->buckets = buckets; H->table = calloc(H->buckets, sizeof(*(H->table))); - return; } static hashtable_t *hashtable_new (int buckets) @@ -285,7 +284,6 @@ static void hashtable_add (hashtable_t *H, int hashvalue, void *datum) } hc->data = datum; hc->next = 0; - return; } static hashchain_t *hashtable_get (hashtable_t *H, int hashvalue) diff --git a/code/tools/lcc/cpp/cpp.c b/code/tools/lcc/cpp/cpp.c index 1fcffbc5..b999d212 100644 --- a/code/tools/lcc/cpp/cpp.c +++ b/code/tools/lcc/cpp/cpp.c @@ -250,7 +250,6 @@ control(Tokenrow *trp) break; } setempty(trp); - return; } void * diff --git a/code/tools/lcc/cpp/include.c b/code/tools/lcc/cpp/include.c index 1bb88475..54c0b77a 100644 --- a/code/tools/lcc/cpp/include.c +++ b/code/tools/lcc/cpp/include.c @@ -108,7 +108,6 @@ doinclude(Tokenrow *trp) return; syntax: error(ERROR, "Syntax error in #include"); - return; } /* diff --git a/code/tools/lcc/cpp/macro.c b/code/tools/lcc/cpp/macro.c index 49d11297..71102570 100644 --- a/code/tools/lcc/cpp/macro.c +++ b/code/tools/lcc/cpp/macro.c @@ -218,7 +218,6 @@ expand(Tokenrow *trp, Nlist *np) insertrow(trp, ntokc, &ntr); trp->tp -= rowlen(&ntr); dofree(ntr.bp); - return; } /* diff --git a/code/tools/lcc/cpp/unix.c b/code/tools/lcc/cpp/unix.c index 17986d84..bd879448 100644 --- a/code/tools/lcc/cpp/unix.c +++ b/code/tools/lcc/cpp/unix.c @@ -109,7 +109,7 @@ memmove(void *dp, const void *sp, size_t n) unsigned char *cdp, *csp; if (n<=0) - return 0; + return dp; cdp = dp; csp = (unsigned char *)sp; if (cdp < csp) { @@ -123,6 +123,6 @@ memmove(void *dp, const void *sp, size_t n) *--cdp = *--csp; } while (--n); } - return 0; + return dp; } #endif diff --git a/code/tools/lcc/lburg/gram.c b/code/tools/lcc/lburg/gram.c index 607ed55d..8de09010 100644 --- a/code/tools/lcc/lburg/gram.c +++ b/code/tools/lcc/lburg/gram.c @@ -1,69 +1,36 @@ -#ifndef lint -static const char yysccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93"; +#if defined(__STDC__) || defined(__cplusplus) +#define YYCONST const +#define YYPARAMS(x) x +#define YYDEFUN(name, arglist, args) name(args) +#define YYAND , +#define YYPTR void * +#else +#define YYCONST +#define YYPARAMS(x) () +#define YYDEFUN(name, arglist, args) name arglist args; +#define YYAND ; +#define YYPTR char * +#endif +#ifndef lint +YYCONST static char yysccsid[] = "@(#)yaccpar 1.8 (Berkeley +Cygnus.28) 01/20/91"; #endif - #define YYBYACC 1 -#define YYMAJOR 1 -#define YYMINOR 9 -#define YYPATCH 20111219 - -#define YYEMPTY (-1) -#define yyclearin (yychar = YYEMPTY) -#define yyerrok (yyerrflag = 0) -#define YYRECOVERING() (yyerrflag != 0) - -#define YYPREFIX "yy" - -#define YYPURE 0 - -#line 2 "code/tools/lcc/lburg/gram.y" +#ifndef YYDONT_INCLUDE_STDIO +#include +#endif +#include /* for malloc/realloc/free */ +#line 2 "lburg/gram.y" #include #include "lburg.h" -static char rcsid[] = "$Id: gram.y 145 2001-10-17 21:53:10Z timo $"; /*lint -e616 -e527 -e652 -esym(552,yynerrs) -esym(563,yynewstate,yyerrlab) */ static int yylineno = 0; -#line 8 "code/tools/lcc/lburg/gram.y" -#ifdef YYSTYPE -#undef YYSTYPE_IS_DECLARED -#define YYSTYPE_IS_DECLARED 1 -#endif -#ifndef YYSTYPE_IS_DECLARED -#define YYSTYPE_IS_DECLARED 1 +#line 8 "lburg/gram.y" typedef union { int n; char *string; Tree tree; } YYSTYPE; -#endif /* !YYSTYPE_IS_DECLARED */ -#line 38 "y.tab.c" - -/* compatibility with bison */ -#ifdef YYPARSE_PARAM -/* compatibility with FreeBSD */ -# ifdef YYPARSE_PARAM_TYPE -# define YYPARSE_DECL() yyparse(YYPARSE_PARAM_TYPE YYPARSE_PARAM) -# else -# define YYPARSE_DECL() yyparse(void *YYPARSE_PARAM) -# endif -#else -# define YYPARSE_DECL() yyparse(void) -#endif - -/* Parameters sent to lex. */ -#ifdef YYLEX_PARAM -# define YYLEX_DECL() yylex(void *YYLEX_PARAM) -# define YYLEX yylex(YYLEX_PARAM) -#else -# define YYLEX_DECL() yylex(void) -# define YYLEX yylex() -#endif - -/* Parameters sent to yyerror. */ -#define YYERROR_DECL() yyerror(const char *s) -#define YYERROR_CALL(msg) yyerror(msg) - -extern int YYPARSE_DECL(); - +#line 37 "y.tab.c" #define TERMINAL 257 #define START 258 #define PPERCENT 259 @@ -72,40 +39,40 @@ extern int YYPARSE_DECL(); #define CODE 262 #define INT 263 #define YYERRCODE 256 -static const short yylhs[] = { -1, +static YYCONST short yylhs[] = { -1, 0, 0, 4, 4, 6, 6, 6, 6, 7, 7, 5, 5, 5, 5, 1, 3, 3, 3, 2, }; -static const short yylen[] = { 2, +static YYCONST short yylen[] = { 2, 3, 1, 0, 2, 3, 3, 1, 2, 0, 4, 0, 7, 2, 3, 1, 1, 4, 6, 1, }; -static const short yydefred[] = { 3, +static YYCONST short yydefred[] = { 3, 0, 0, 0, 9, 0, 11, 7, 4, 8, 0, 15, 0, 0, 0, 5, 6, 0, 13, 0, 0, 14, 0, 10, 0, 0, 0, 0, 0, 19, 0, 17, 0, 12, 0, 18, }; -static const short yydgoto[] = { 1, +static YYCONST short yydgoto[] = { 1, 12, 30, 25, 2, 13, 8, 10, }; -static const short yysindex[] = { 0, +static YYCONST short yysindex[] = { 0, 0, -4, -2, 0, -250, 0, 0, 0, 0, -9, 0, 1, -10, -49, 0, 0, 3, 0, -44, -248, 0, -244, 0, -22, -242, -244, -245, -37, 0, 10, 0, -244, 0, -20, 0, }; -static const short yyrindex[] = { 0, +static YYCONST short yyrindex[] = { 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -static const short yygindex[] = { 0, +static YYCONST short yygindex[] = { 0, 11, 0, -23, 0, 0, 0, 0, }; #define YYTABLESIZE 255 -static const short yytable[] = { 18, +static YYCONST short yytable[] = { 18, 15, 16, 28, 31, 16, 7, 32, 9, 34, 11, 16, 20, 21, 22, 23, 24, 29, 26, 27, 33, 35, 2, 1, 19, 0, 0, 0, 0, 0, 0, @@ -133,7 +100,7 @@ static const short yytable[] = { 18, 0, 0, 0, 0, 0, 17, 0, 0, 0, 11, 14, 3, 4, 5, 6, }; -static const short yycheck[] = { 10, +static YYCONST short yycheck[] = { 10, 10, 41, 26, 41, 44, 10, 44, 10, 32, 260, 10, 61, 10, 58, 263, 260, 262, 40, 261, 10, 41, 0, 0, 13, -1, -1, -1, -1, -1, -1, @@ -167,8 +134,7 @@ static const short yycheck[] = { 10, #endif #define YYMAXTOKEN 263 #if YYDEBUG -static const char *yyname[] = { - +static YYCONST char *YYCONST yyname[] = { "end-of-file",0,0,0,0,0,0,0,0,0,"'\\n'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,"'('","')'",0,0,"','",0,0,0,0,0,0,0,0,0,0,0,0,0,"':'",0,0, "'='",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, @@ -178,7 +144,7 @@ static const char *yyname[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, "TERMINAL","START","PPERCENT","ID","TEMPLATE","CODE","INT", }; -static const char *yyrule[] = { +static YYCONST char *YYCONST yyrule[] = { "$accept : spec", "spec : decls PPERCENT rules", "spec : decls", @@ -199,44 +165,96 @@ static const char *yyrule[] = { "tree : ID '(' tree ')'", "tree : ID '(' tree ',' tree ')'", "cost : CODE", - }; #endif - -int yydebug; -int yynerrs; - -int yyerrflag; -int yychar; -YYSTYPE yyval; -YYSTYPE yylval; - -/* define the initial stack-sizes */ +#define YYLEX yylex() +#define YYEMPTY -1 +#define yyclearin (yychar=(YYEMPTY)) +#define yyerrok (yyerrflag=0) +#ifndef YYINITDEPTH +#define YYINITDEPTH 200 +#endif #ifdef YYSTACKSIZE -#undef YYMAXDEPTH -#define YYMAXDEPTH YYSTACKSIZE +#ifndef YYMAXDEPTH +#define YYMAXDEPTH YYSTACKSIZE +#endif #else #ifdef YYMAXDEPTH #define YYSTACKSIZE YYMAXDEPTH #else -#define YYSTACKSIZE 10000 -#define YYMAXDEPTH 500 +#define YYSTACKSIZE 500 +#define YYMAXDEPTH 500 #endif #endif +#ifndef YYMAXSTACKSIZE +#define YYMAXSTACKSIZE 10000 +#endif +int yydebug; +int yynerrs; +int yyerrflag; +int yychar; +YYSTYPE yyval; +YYSTYPE yylval; +static short *yyss; +static YYSTYPE *yyvs; +static int yystacksize; +#define yyfree(x) free(x) +extern int yylex(); -#define YYINITSTACKSIZE 500 +static YYPTR +YYDEFUN (yymalloc, (bytes), unsigned bytes) +{ + YYPTR ptr = (YYPTR) malloc (bytes); + if (ptr != 0) return (ptr); + yyerror ("yyparse: memory exhausted"); + return (0); +} -typedef struct { - unsigned stacksize; - short *s_base; - short *s_mark; - short *s_last; - YYSTYPE *l_base; - YYSTYPE *l_mark; -} YYSTACKDATA; -/* variables for the parser stack */ -static YYSTACKDATA yystack; -#line 60 "code/tools/lcc/lburg/gram.y" +static YYPTR +YYDEFUN (yyrealloc, (old, bytes), YYPTR old YYAND unsigned bytes) +{ + YYPTR ptr = (YYPTR) realloc (old, bytes); + if (ptr != 0) return (ptr); + yyerror ("yyparse: memory exhausted"); + return (0); +} + +static int +#ifdef __GNUC__ +inline +#endif +yygrow () +{ +#if YYDEBUG + int old_stacksize = yystacksize; +#endif + short *new_yyss; + YYSTYPE *new_yyvs; + + if (yystacksize == YYMAXSTACKSIZE) + return (1); + yystacksize += (yystacksize + 1 ) / 2; + if (yystacksize > YYMAXSTACKSIZE) + yystacksize = YYMAXSTACKSIZE; +#if YYDEBUG + if (yydebug) + printf("yydebug: growing stack size from %d to %d\n", + old_stacksize, yystacksize); +#endif + new_yyss = (short *) yyrealloc ((char *)yyss, yystacksize * sizeof (short)); + if (new_yyss == 0) + return (1); + new_yyvs = (YYSTYPE *) yyrealloc ((char *)yyvs, yystacksize * sizeof (YYSTYPE)); + if (new_yyvs == 0) + { + yyfree (new_yyss); + return (1); + } + yyss = new_yyss; + yyvs = new_yyvs; + return (0); +} +#line 60 "lburg/gram.y" #include #include #include @@ -380,74 +398,30 @@ void yywarn(char *fmt, ...) { fprintf(stderr, "warning: "); vfprintf(stderr, fmt, ap); } -#line 383 "y.tab.c" +#line 403 "y.tab.c" +#define YYABORT goto yyabort +#define YYACCEPT goto yyaccept +#define YYERROR goto yyerrlab #if YYDEBUG -#include /* needed for printf */ -#endif - -#include /* needed for malloc, etc */ -#include /* needed for memset */ - -/* allocate initial stack or double stack size, up to YYMAXDEPTH */ -static int yygrowstack(YYSTACKDATA *data) -{ - int i; - unsigned newsize; - short *newss; - YYSTYPE *newvs; - - if ((newsize = data->stacksize) == 0) - newsize = YYINITSTACKSIZE; - else if (newsize >= YYMAXDEPTH) - return -1; - else if ((newsize *= 2) > YYMAXDEPTH) - newsize = YYMAXDEPTH; - - i = data->s_mark - data->s_base; - newss = (short *)realloc(data->s_base, newsize * sizeof(*newss)); - if (newss == 0) - return -1; - - data->s_base = newss; - data->s_mark = newss + i; - - newvs = (YYSTYPE *)realloc(data->l_base, newsize * sizeof(*newvs)); - if (newvs == 0) - return -1; - - data->l_base = newvs; - data->l_mark = newvs + i; - - data->stacksize = newsize; - data->s_last = data->s_base + newsize - 1; - return 0; -} - -#if YYPURE || defined(YY_NO_LEAKS) -static void yyfreestack(YYSTACKDATA *data) -{ - free(data->s_base); - free(data->l_base); - memset(data, 0, sizeof(*data)); -} +#ifdef __cplusplus +extern "C" char *getenv(); #else -#define yyfreestack(data) /* nothing */ +extern char *getenv(); +#endif #endif - -#define YYABORT goto yyabort -#define YYREJECT goto yyabort -#define YYACCEPT goto yyaccept -#define YYERROR goto yyerrlab int -YYPARSE_DECL() +yyparse() { - int yym, yyn, yystate; + register int yym, yyn, yystate; + register YYSTYPE *yyvsp; + register short *yyssp; + short *yysse; #if YYDEBUG - const char *yys; + register YYCONST char *yys; - if ((yys = getenv("YYDEBUG")) != 0) + if (yys = getenv("YYDEBUG")) { yyn = *yys; if (yyn >= '0' && yyn <= '9') @@ -457,102 +431,120 @@ YYPARSE_DECL() yynerrs = 0; yyerrflag = 0; - yychar = YYEMPTY; - yystate = 0; + yychar = (-1); -#if YYPURE - memset(&yystack, 0, sizeof(yystack)); -#endif + if (yyss == 0) + { + yyss = (short *) yymalloc (YYSTACKSIZE * sizeof (short)); + if (yyss == 0) + goto yyabort; + yyvs = (YYSTYPE *) yymalloc (YYSTACKSIZE * sizeof (YYSTYPE)); + if (yyvs == 0) + { + yyfree (yyss); + goto yyabort; + } + yystacksize = YYSTACKSIZE; + } + yysse = yyss + yystacksize - 1; + yyssp = yyss; + yyvsp = yyvs; + *yyssp = yystate = 0; + goto yyloop; - if (yystack.s_base == NULL && yygrowstack(&yystack)) goto yyoverflow; - yystack.s_mark = yystack.s_base; - yystack.l_mark = yystack.l_base; - yystate = 0; - *yystack.s_mark = 0; +yypush_lex: + yyval = yylval; + yystate = yytable[yyn]; +yypush: + if (yyssp >= yysse) + { + int depth = yyssp - yyss; + if (yygrow() != 0) + goto yyoverflow; + yysse = yyss + yystacksize -1; + yyssp = depth + yyss; + yyvsp = depth + yyvs; + } + *++yyssp = yystate; + *++yyvsp = yyval; yyloop: - if ((yyn = yydefred[yystate]) != 0) goto yyreduce; + if ((yyn = yydefred[yystate])) goto yyreduce; + yyn = yysindex[yystate]; if (yychar < 0) { - if ((yychar = YYLEX) < 0) yychar = 0; + if ((yychar = yylex()) < 0) yychar = 0; #if YYDEBUG if (yydebug) { yys = 0; if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; if (!yys) yys = "illegal-symbol"; - printf("%sdebug: state %d, reading %d (%s)\n", - YYPREFIX, yystate, yychar, yys); + printf("yydebug: state %d, reading %d (%s)\n", yystate, + yychar, yys); } #endif } - if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 && - yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + if (yyn != 0 + && ((yyn += yychar), ((unsigned)yyn <= (unsigned)YYTABLESIZE)) + && yycheck[yyn] == yychar) { #if YYDEBUG if (yydebug) - printf("%sdebug: state %d, shifting to state %d\n", - YYPREFIX, yystate, yytable[yyn]); + printf("yydebug: state %d, shifting to state %d\n", + yystate, yytable[yyn]); #endif - if (yystack.s_mark >= yystack.s_last && yygrowstack(&yystack)) - { - goto yyoverflow; - } - yystate = yytable[yyn]; - *++yystack.s_mark = yytable[yyn]; - *++yystack.l_mark = yylval; - yychar = YYEMPTY; if (yyerrflag > 0) --yyerrflag; - goto yyloop; + yychar = (-1); + goto yypush_lex; } - if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 && - yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + yyn = yyrindex[yystate]; + if (yyn != 0 + && ((yyn += yychar), ((unsigned)yyn <= (unsigned)YYTABLESIZE)) + && yycheck[yyn] == yychar) { yyn = yytable[yyn]; goto yyreduce; } if (yyerrflag) goto yyinrecovery; - +#ifdef lint + goto yynewerror; +yynewerror: +#endif yyerror("syntax error"); - +#ifdef lint goto yyerrlab; - yyerrlab: +#endif ++yynerrs; - yyinrecovery: if (yyerrflag < 3) { yyerrflag = 3; for (;;) { - if ((yyn = yysindex[*yystack.s_mark]) && (yyn += YYERRCODE) >= 0 && - yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE) + yyn = yysindex[*yyssp]; + if (yyn != 0 + && ((yyn += YYERRCODE), ((unsigned)yyn <= (unsigned)YYTABLESIZE)) + && yycheck[yyn] == YYERRCODE) { #if YYDEBUG if (yydebug) - printf("%sdebug: state %d, error recovery shifting\ - to state %d\n", YYPREFIX, *yystack.s_mark, yytable[yyn]); + printf("yydebug: state %d, error recovery shifting\ + to state %d\n", *yyssp, yytable[yyn]); #endif - if (yystack.s_mark >= yystack.s_last && yygrowstack(&yystack)) - { - goto yyoverflow; - } - yystate = yytable[yyn]; - *++yystack.s_mark = yytable[yyn]; - *++yystack.l_mark = yylval; - goto yyloop; + goto yypush_lex; } else { #if YYDEBUG if (yydebug) - printf("%sdebug: error recovery discarding state %d\n", - YYPREFIX, *yystack.s_mark); + printf("yydebug: error recovery discarding state %d\n", + *yyssp); #endif - if (yystack.s_mark <= yystack.s_base) goto yyabort; - --yystack.s_mark; - --yystack.l_mark; + if (yyssp <= yyss) goto yyabort; + --yyssp; + --yyvsp; } } } @@ -565,137 +557,124 @@ yyinrecovery: yys = 0; if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; if (!yys) yys = "illegal-symbol"; - printf("%sdebug: state %d, error recovery discards token %d (%s)\n", - YYPREFIX, yystate, yychar, yys); + printf("yydebug: state %d, error recovery discards token %d (%s)\n", + yystate, yychar, yys); } #endif - yychar = YYEMPTY; + yychar = (-1); goto yyloop; } - yyreduce: #if YYDEBUG if (yydebug) - printf("%sdebug: state %d, reducing by rule %d (%s)\n", - YYPREFIX, yystate, yyn, yyrule[yyn]); + printf("yydebug: state %d, reducing by rule %d (%s)\n", + yystate, yyn, yyrule[yyn]); #endif yym = yylen[yyn]; - if (yym) - yyval = yystack.l_mark[1-yym]; - else - memset(&yyval, 0, sizeof yyval); + yyval = yyvsp[1-yym]; switch (yyn) { case 1: -#line 22 "code/tools/lcc/lburg/gram.y" - { yylineno = 0; } +#line 22 "lburg/gram.y" +{ yylineno = 0; } break; case 2: -#line 23 "code/tools/lcc/lburg/gram.y" - { yylineno = 0; } +#line 23 "lburg/gram.y" +{ yylineno = 0; } break; case 6: -#line 31 "code/tools/lcc/lburg/gram.y" - { - if (nonterm(yystack.l_mark[-1].string)->number != 1) +#line 31 "lburg/gram.y" +{ + if (nonterm(yyvsp[-1].string)->number != 1) yyerror("redeclaration of the start symbol\n"); } break; case 8: -#line 36 "code/tools/lcc/lburg/gram.y" - { yyerrok; } +#line 36 "lburg/gram.y" +{ yyerrok; } break; case 10: -#line 40 "code/tools/lcc/lburg/gram.y" - { term(yystack.l_mark[-2].string, yystack.l_mark[0].n); } +#line 40 "lburg/gram.y" +{ term(yyvsp[-2].string, yyvsp[0].n); } break; case 12: -#line 44 "code/tools/lcc/lburg/gram.y" - { rule(yystack.l_mark[-5].string, yystack.l_mark[-3].tree, yystack.l_mark[-2].string, yystack.l_mark[-1].string); } +#line 44 "lburg/gram.y" +{ rule(yyvsp[-5].string, yyvsp[-3].tree, yyvsp[-2].string, yyvsp[-1].string); } break; case 14: -#line 46 "code/tools/lcc/lburg/gram.y" - { yyerrok; } +#line 46 "lburg/gram.y" +{ yyerrok; } break; case 15: -#line 49 "code/tools/lcc/lburg/gram.y" - { nonterm(yyval.string = yystack.l_mark[0].string); } +#line 49 "lburg/gram.y" +{ nonterm(yyval.string = yyvsp[0].string); } break; case 16: -#line 52 "code/tools/lcc/lburg/gram.y" - { yyval.tree = tree(yystack.l_mark[0].string, 0, 0); } +#line 52 "lburg/gram.y" +{ yyval.tree = tree(yyvsp[0].string, 0, 0); } break; case 17: -#line 53 "code/tools/lcc/lburg/gram.y" - { yyval.tree = tree(yystack.l_mark[-3].string, yystack.l_mark[-1].tree, 0); } +#line 53 "lburg/gram.y" +{ yyval.tree = tree(yyvsp[-3].string, yyvsp[-1].tree, 0); } break; case 18: -#line 54 "code/tools/lcc/lburg/gram.y" - { yyval.tree = tree(yystack.l_mark[-5].string, yystack.l_mark[-3].tree, yystack.l_mark[-1].tree); } +#line 54 "lburg/gram.y" +{ yyval.tree = tree(yyvsp[-5].string, yyvsp[-3].tree, yyvsp[-1].tree); } break; case 19: -#line 57 "code/tools/lcc/lburg/gram.y" - { if (*yystack.l_mark[0].string == 0) yyval.string = "0"; } +#line 57 "lburg/gram.y" +{ if (*yyvsp[0].string == 0) yyval.string = "0"; } break; -#line 640 "y.tab.c" +#line 630 "y.tab.c" } - yystack.s_mark -= yym; - yystate = *yystack.s_mark; - yystack.l_mark -= yym; + yyssp -= yym; + yyvsp -= yym; yym = yylhs[yyn]; + yystate = *yyssp; if (yystate == 0 && yym == 0) { #if YYDEBUG if (yydebug) - printf("%sdebug: after reduction, shifting from state 0 to\ - state %d\n", YYPREFIX, YYFINAL); + printf("yydebug: after reduction, shifting from state 0 to\ + state %d\n", YYFINAL); #endif yystate = YYFINAL; - *++yystack.s_mark = YYFINAL; - *++yystack.l_mark = yyval; + *++yyssp = YYFINAL; + *++yyvsp = yyval; if (yychar < 0) { - if ((yychar = YYLEX) < 0) yychar = 0; + if ((yychar = yylex()) < 0) yychar = 0; #if YYDEBUG if (yydebug) { yys = 0; if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; if (!yys) yys = "illegal-symbol"; - printf("%sdebug: state %d, reading %d (%s)\n", - YYPREFIX, YYFINAL, yychar, yys); + printf("yydebug: state %d, reading %d (%s)\n", + YYFINAL, yychar, yys); } #endif } if (yychar == 0) goto yyaccept; goto yyloop; } - if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 && - yyn <= YYTABLESIZE && yycheck[yyn] == yystate) + yyn = yygindex[yym]; + if (yyn != 0 + && ((yyn += yystate), ((unsigned)yyn <= (unsigned)YYTABLESIZE)) + && yycheck[yyn] == yystate) yystate = yytable[yyn]; else yystate = yydgoto[yym]; #if YYDEBUG if (yydebug) - printf("%sdebug: after reduction, shifting from state %d \ -to state %d\n", YYPREFIX, *yystack.s_mark, yystate); + printf("yydebug: after reduction, shifting from state %d \ +to state %d\n", *yyssp, yystate); #endif - if (yystack.s_mark >= yystack.s_last && yygrowstack(&yystack)) - { - goto yyoverflow; - } - *++yystack.s_mark = (short) yystate; - *++yystack.l_mark = yyval; - goto yyloop; - + goto yypush; yyoverflow: yyerror("yacc stack overflow"); - yyabort: - yyfreestack(&yystack); return (1); - yyaccept: - yyfreestack(&yystack); return (0); } diff --git a/code/ui/make-ui.bat b/code/ui/make-ui.bat deleted file mode 100644 index 6d28fb4c..00000000 --- a/code/ui/make-ui.bat +++ /dev/null @@ -1,52 +0,0 @@ -@echo off - -REM *** NOTE: THIS BATCH FILE IS MEANT TO BE CALLED BY make-qvm.bat! -REM *** NOTE: THIS CANNOT BE RUN BY ITSELF WITHOUT %make-qvm-location% BEING DEFINED! - -cd vm -set cc=q3lcc.exe -DQ3_VM -S -Wf-target=bytecode -Wf-g -I..\..\cgame -I..\..\game -I..\..\ui - - -echo. -echo *** Running Q3LCC for UI... - -%cc% ../ui_main.c -@if errorlevel 1 goto quit -%cc% ../../game/bg_misc.c -@if errorlevel 1 goto quit -%cc% ../../game/bg_lib.c -@if errorlevel 1 goto quit -%cc% ../../game/q_math.c -@if errorlevel 1 goto quit -%cc% ../../qcommon/q_shared.c -@if errorlevel 1 goto quit -%cc% ../ui_atoms.c -@if errorlevel 1 goto quit -%cc% ../ui_players.c -@if errorlevel 1 goto quit -REM ***%cc% ../ui_util.c -REM ***../ui_util.c:21: warning: empty input file -REM ***ALSO REMOVED FROM UI.Q3ASM -@if errorlevel 1 goto quit -%cc% ../ui_shared.c -@if errorlevel 1 goto quit -%cc% ../ui_gameinfo.c -@if errorlevel 1 goto quit - -echo. -echo *** Running Q3ASM for UI... - -REM *** This tells q3asm to generate a vanilla q3-compatible qvm, generate a .map file, output -REM *** the resulting .qvm into "%make-qvm-location%bin\qvm\vm\ui" (it will be called ui.qvm), -REM *** and to compile the files listed in the ui.q3asm script located in "%make-qvm-location%code/ui/ui". - -q3asm -vq3 -m -o "%make-qvm-location%bin\qvm\vm\ui" -f "%make-qvm-location%code/ui/ui" - -:quit -if errorlevel 1 ( -echo. -echo ERROR IN Q3LCC PARSING! UI COMPILATION HALTED! -echo. -) -echo. -cd .. diff --git a/code/ui/ui.q3asm b/code/ui/ui.q3asm deleted file mode 100644 index 77893b2c..00000000 --- a/code/ui/ui.q3asm +++ /dev/null @@ -1,10 +0,0 @@ -ui_main -..\ui_syscalls -ui_atoms -ui_players -ui_shared -ui_gameinfo -bg_misc -bg_lib -q_math -q_shared diff --git a/code/ui/ui_local.h b/code/ui/ui_local.h index 167a54ff..a16f32cf 100644 --- a/code/ui/ui_local.h +++ b/code/ui/ui_local.h @@ -93,7 +93,7 @@ #define __UI_LOCAL_H__ #include "../qcommon/q_shared.h" -#include "../cgame/tr_types.h" +#include "../renderercommon/tr_types.h" #include "ui_public.h" #include "keycodes.h" #include "../game/bg_public.h" diff --git a/code/ui/ui_main.c b/code/ui/ui_main.c index 9d2525a0..a4056e8d 100644 --- a/code/ui/ui_main.c +++ b/code/ui/ui_main.c @@ -3800,10 +3800,11 @@ static void UI_DrawKeyBindStatus(itemDef_t *item, rectDef_t * rect, float scale, #define GLINFO_STRING2 va("VERSION: %s", uiInfo.uiDC.glconfig.version_string) #define GLINFO_STRING3 va("PIXELFORMAT: color(%d) Z(%d) stencil(%d); REFRESH: %d Hz", uiInfo.uiDC.glconfig.colorBits,\ uiInfo.uiDC.glconfig.depthBits, uiInfo.uiDC.glconfig.stencilBits, uiInfo.uiDC.glconfig.displayFrequency) +/* #define GLINFO_STRING4 va("TEX: %d units, %d x %d max%s%s", uiInfo.uiDC.glconfig.maxActiveTextures,\ uiInfo.uiDC.glconfig.maxTextureSize, uiInfo.uiDC.glconfig.maxTextureSize,\ (uiInfo.uiDC.glconfig.textureCompression == TC_NONE) ? "" : ", compressed", uiInfo.uiDC.glconfig.smpActive ? "; SMP: on" : "") - +*/ static void UI_DrawGLInfo(rectDef_t * rect, float scale, vec4_t color, int textStyle) { float p[2]; @@ -3829,7 +3830,7 @@ static void UI_DrawGLInfo(rectDef_t * rect, float scale, vec4_t color, int textS GLINFO_OUTPUT_STRING_ANGLED(GLINFO_STRING1); GLINFO_OUTPUT_STRING_ANGLED(GLINFO_STRING2); GLINFO_OUTPUT_STRING_ANGLED(GLINFO_STRING3); - GLINFO_OUTPUT_STRING_ANGLED(GLINFO_STRING4); +// GLINFO_OUTPUT_STRING_ANGLED(GLINFO_STRING4); } else { @@ -3840,7 +3841,7 @@ static void UI_DrawGLInfo(rectDef_t * rect, float scale, vec4_t color, int textS GLINFO_OUTPUT_STRING(GLINFO_STRING1); GLINFO_OUTPUT_STRING(GLINFO_STRING2); GLINFO_OUTPUT_STRING(GLINFO_STRING3); - GLINFO_OUTPUT_STRING(GLINFO_STRING4); +// GLINFO_OUTPUT_STRING(GLINFO_STRING4); } } @@ -8643,7 +8644,8 @@ void _UI_Init(qboolean inGameLoad) uiInfo.uiDC.bias = 0.5f * (uiInfo.uiDC.glconfig.vidWidth - (uiInfo.uiDC.glconfig.vidHeight * SCREEN_WIDTH / (float)SCREEN_HEIGHT)); //Makro - set up 2D scene - memset(&uiInfo.uiDC.scene2D, 0, sizeof(&uiInfo.uiDC.scene2D)); +// memset(&uiInfo.uiDC.scene2D, 0, sizeof(&uiInfo.uiDC.scene2D)); + memset(&uiInfo.uiDC.scene2D, 0, sizeof(uiInfo.uiDC.scene2D)); uiInfo.uiDC.scene2D.x = 0; uiInfo.uiDC.scene2D.y = 0; uiInfo.uiDC.scene2D.width = uiInfo.uiDC.glconfig.vidWidth; diff --git a/code/ui/ui_shared.h b/code/ui/ui_shared.h index 7409ff09..cfc51b17 100644 --- a/code/ui/ui_shared.h +++ b/code/ui/ui_shared.h @@ -74,7 +74,7 @@ #define __UI_SHARED_H #include "../qcommon/q_shared.h" -#include "../cgame/tr_types.h" +#include "../renderercommon/tr_types.h" #include "keycodes.h" #include "menudef.h" diff --git a/code/zlib/inffast.c b/code/zlib/inffast.c index bbee92ed..11bcbb0b 100644 --- a/code/zlib/inffast.c +++ b/code/zlib/inffast.c @@ -298,7 +298,6 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */ 257 + (end - out) : 257 - (out - end)); state->hold = hold; state->bits = bits; - return; } /* diff --git a/cross-make-mingw.sh b/cross-make-mingw.sh deleted file mode 100755 index c30872e1..00000000 --- a/cross-make-mingw.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/sh - -# Note: This works in Linux and cygwin - -CMD_PREFIX="i686-pc-mingw32 i586-mingw32msvc i686-w64-mingw32"; - -if [ "X$CC" = "X" ]; then - for check in $CMD_PREFIX; do - full_check="${check}-gcc" - which "$full_check" > /dev/null 2>&1 - if [ "$?" = "0" ]; then - export CC="$full_check" - fi - done -fi - -if [ "X$WINDRES" = "X" ]; then - for check in $CMD_PREFIX; do - full_check="${check}-windres" - which "$full_check" > /dev/null 2>&1 - if [ "$?" = "0" ]; then - export WINDRES="$full_check" - fi - done -fi - -if [ "X$WINDRES" = "X" -o "X$CC" = "X" ]; then - echo "Error: Must define or find WINDRES and CC" - exit 1 -fi - -export PLATFORM=mingw32 -export ARCH=x86 - -exec make $* diff --git a/cross-make-mingw64.sh b/cross-make-mingw64.sh deleted file mode 100755 index 16c3d5da..00000000 --- a/cross-make-mingw64.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/sh - -# Note: This works in Linux and cygwin - -CMD_PREFIX="amd64-mingw32msvc x86_64-w64-mingw32"; - -if [ "X$CC" = "X" ]; then - for check in $CMD_PREFIX; do - full_check="${check}-gcc" - which "$full_check" > /dev/null 2>&1 - if [ "$?" = "0" ]; then - export CC="$full_check" - fi - done -fi - -if [ "X$WINDRES" = "X" ]; then - for check in $CMD_PREFIX; do - full_check="${check}-windres" - which "$full_check" > /dev/null 2>&1 - if [ "$?" = "0" ]; then - export WINDRES="$full_check" - fi - done -fi - -if [ "X$WINDRES" = "X" -o "X$CC" = "X" ]; then - echo "Error: Must define or find WINDRES and CC" - exit 1 -fi - -export PLATFORM=mingw32 -export ARCH=x64 - -exec make $* diff --git a/jenkins-ci-build.sh b/jenkins-ci-build.sh new file mode 100755 index 00000000..fb922f25 --- /dev/null +++ b/jenkins-ci-build.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +UNAME=`uname` +MASTER_DIR=`dirname $0` +BUILD_DEFAULT="release" + +cd ${MASTER_DIR} + +if [ "$OPTIONS" = "all_options" ]; +then + export USE_CODEC_VORBIS=1 + export USE_FREETYPE=1 +fi + +if [ "$UNAME" == "Darwin" ]; then + CORES=`sysctl -n hw.ncpu` +elif [ "$UNAME" == "Linux" ]; then + CORES=`awk '/^processor/ { N++} END { print N }' /proc/cpuinfo` +fi + +echo "platform : ${UNAME}" +echo "cores : ${CORES}" +if [ "${BUILD_TYPE}" == "" ]; then + BUILD_TYPE="${BUILD_DEFAULT}" + echo "build type : defaulting to ${BUILD_TYPE}" +else + echo "build type : ${BUILD_TYPE}" +fi + +make -j${CORES} distclean ${BUILD_TYPE} + +exit $? diff --git a/make-macosx-app.sh b/make-macosx-app.sh new file mode 100755 index 00000000..4ed57d61 --- /dev/null +++ b/make-macosx-app.sh @@ -0,0 +1,375 @@ +#!/bin/bash + +# Let's make the user give us a target to work with. +# architecture is assumed universal if not specified, and is optional. +# if arch is defined, it we will store the .app bundle in the target arch build directory +if [ $# == 0 ] || [ $# -gt 2 ]; then + echo "Usage: $0 target " + echo "Example: $0 release x86" + echo "Valid targets are:" + echo " release" + echo " debug" + echo + echo "Optional architectures are:" + echo " x86" + echo " x86_64" + echo " ppc" + echo + exit 1 +fi + +# validate target name +if [ "$1" == "release" ]; then + TARGET_NAME="release" +elif [ "$1" == "debug" ]; then + TARGET_NAME="debug" +else + echo "Invalid target: $1" + echo "Valid targets are:" + echo " release" + echo " debug" + exit 1 +fi + +CURRENT_ARCH="" + +# validate the architecture if it was specified +if [ "$2" != "" ]; then + if [ "$2" == "x86" ]; then + CURRENT_ARCH="x86" + elif [ "$2" == "x86_64" ]; then + CURRENT_ARCH="x86_64" + elif [ "$2" == "ppc" ]; then + CURRENT_ARCH="ppc" + else + echo "Invalid architecture: $1" + echo "Valid architectures are:" + echo " x86" + echo " x86_64" + echo " ppc" + echo + exit 1 + fi +fi + +# symlinkArch() creates a symlink with the architecture suffix. +# meant for universal binaries, but also handles the way this script generates +# application bundles for a single architecture as well. +function symlinkArch() +{ + EXT="dylib" + SEP="${3}" + SRCFILE="${1}" + DSTFILE="${2}${SEP}" + DSTPATH="${4}" + + if [ ! -e "${DSTPATH}/${SRCFILE}.${EXT}" ]; then + echo "**** ERROR: missing ${SRCFILE}.${EXT} from ${MACOS}" + exit 1 + fi + + if [ ! -d "${DSTPATH}" ]; then + echo "**** ERROR: path not found ${DSTPATH}" + exit 1 + fi + + pushd "${DSTPATH}" > /dev/null + + IS32=`file "${SRCFILE}.${EXT}" | grep "i386" | awk '{print $NF}'` + IS64=`file "${SRCFILE}.${EXT}" | grep "x86_64" | awk '{print $NF}'` + ISPPC=`file "${SRCFILE}.${EXT}" | grep "ppc" | awk '{print $NF}'` + + if [ "${IS32}" == "i386" ]; then + if [ ! -L "${DSTFILE}x86.${EXT}" ]; then + ln -s "${SRCFILE}.${EXT}" "${DSTFILE}x86.${EXT}" + fi + elif [ -L "${DSTFILE}x86.${EXT}" ]; then + rm "${DSTFILE}x86.${EXT}" + fi + + if [ "${IS64}" == "x86_64" ]; then + if [ ! -L "${DSTFILE}x86_64.${EXT}" ]; then + ln -s "${SRCFILE}.${EXT}" "${DSTFILE}x86_64.${EXT}" + fi + elif [ -L "${DSTFILE}x86_64.${EXT}" ]; then + rm "${DSTFILE}x86_64.${EXT}" + fi + + if [ "${ISPPC}" == "ppc" ]; then + if [ ! -L "${DSTFILE}ppc.${EXT}" ]; then + ln -s "${SRCFILE}.${EXT}" "${DSTFILE}ppc.${EXT}" + fi + elif [ -L "${DSTFILE}ppc.${EXT}" ]; then + rm "${DSTFILE}ppc.${EXT}" + fi + + popd > /dev/null +} + +SEARCH_ARCHS=" \ + x86 \ + x86_64 \ + ppc \ +" + +HAS_LIPO=`command -v lipo` +HAS_CP=`command -v cp` + +# if lipo is not available, we cannot make a universal binary, print a warning +if [ ! -x "${HAS_LIPO}" ] && [ "${CURRENT_ARCH}" == "" ]; then + CURRENT_ARCH=`uname -m` + if [ "${CURRENT_ARCH}" == "i386" ]; then CURRENT_ARCH="x86"; fi + echo "$0 cannot make a universal binary, falling back to architecture ${CURRENT_ARCH}" +fi + +# if the optional arch parameter is used, replace SEARCH_ARCHS to only work with one +if [ "${CURRENT_ARCH}" != "" ]; then + SEARCH_ARCHS="${CURRENT_ARCH}" +fi + +AVAILABLE_ARCHS="" + +IOQ3_VERSION=`grep '^VERSION=' Makefile | sed -e 's/.*=\(.*\)/\1/'` +IOQ3_CLIENT_ARCHS="" +IOQ3_SERVER_ARCHS="" +IOQ3_RENDERER_GL1_ARCHS="" +IOQ3_RENDERER_GL2_ARCHS="" +IOQ3_CGAME_ARCHS="" +IOQ3_GAME_ARCHS="" +IOQ3_UI_ARCHS="" +IOQ3_MP_CGAME_ARCHS="" +IOQ3_MP_GAME_ARCHS="" +IOQ3_MP_UI_ARCHS="" + +BASEDIR="baseq3" +MISSIONPACKDIR="missionpack" + +CGAME="cgame" +GAME="qagame" +UI="ui" + +RENDERER_OPENGL="renderer_opengl" + +DEDICATED_NAME="ioq3ded" + +CGAME_NAME="${CGAME}.dylib" +GAME_NAME="${GAME}.dylib" +UI_NAME="${UI}.dylib" + +RENDERER_OPENGL1_NAME="${RENDERER_OPENGL}1.dylib" +RENDERER_OPENGL2_NAME="${RENDERER_OPENGL}2.dylib" + +ICNSDIR="misc" +ICNS="quake3_flat.icns" +PKGINFO="APPLIOQ3" + +OBJROOT="build" +#BUILT_PRODUCTS_DIR="${OBJROOT}/${TARGET_NAME}-darwin-${CURRENT_ARCH}" +PRODUCT_NAME="ioquake3" +WRAPPER_EXTENSION="app" +WRAPPER_NAME="${PRODUCT_NAME}.${WRAPPER_EXTENSION}" +CONTENTS_FOLDER_PATH="${WRAPPER_NAME}/Contents" +UNLOCALIZED_RESOURCES_FOLDER_PATH="${CONTENTS_FOLDER_PATH}/Resources" +EXECUTABLE_FOLDER_PATH="${CONTENTS_FOLDER_PATH}/MacOS" +EXECUTABLE_NAME="${PRODUCT_NAME}" + +# loop through the architectures to build string lists for each universal binary +for ARCH in $SEARCH_ARCHS; do + CURRENT_ARCH=${ARCH} + BUILT_PRODUCTS_DIR="${OBJROOT}/${TARGET_NAME}-darwin-${CURRENT_ARCH}" + IOQ3_CLIENT="${EXECUTABLE_NAME}.${CURRENT_ARCH}" + IOQ3_SERVER="${DEDICATED_NAME}.${CURRENT_ARCH}" + IOQ3_RENDERER_GL1="${RENDERER_OPENGL}1_${CURRENT_ARCH}.dylib" + IOQ3_RENDERER_GL2="${RENDERER_OPENGL}2_${CURRENT_ARCH}.dylib" + IOQ3_CGAME="${CGAME}${CURRENT_ARCH}.dylib" + IOQ3_GAME="${GAME}${CURRENT_ARCH}.dylib" + IOQ3_UI="${UI}${CURRENT_ARCH}.dylib" + + if [ ! -d ${BUILT_PRODUCTS_DIR} ]; then + CURRENT_ARCH="" + BUILT_PRODUCTS_DIR="" + continue + fi + + # executables + if [ -e ${BUILT_PRODUCTS_DIR}/${IOQ3_CLIENT} ]; then + IOQ3_CLIENT_ARCHS="${BUILT_PRODUCTS_DIR}/${IOQ3_CLIENT} ${IOQ3_CLIENT_ARCHS}" + VALID_ARCHS="${ARCH} ${VALID_ARCHS}" + else + continue + fi + if [ -e ${BUILT_PRODUCTS_DIR}/${IOQ3_SERVER} ]; then + IOQ3_SERVER_ARCHS="${BUILT_PRODUCTS_DIR}/${IOQ3_SERVER} ${IOQ3_SERVER_ARCHS}" + fi + + # renderers + if [ -e ${BUILT_PRODUCTS_DIR}/${IOQ3_RENDERER_GL1} ]; then + IOQ3_RENDERER_GL1_ARCHS="${BUILT_PRODUCTS_DIR}/${IOQ3_RENDERER_GL1} ${IOQ3_RENDERER_GL1_ARCHS}" + fi + if [ -e ${BUILT_PRODUCTS_DIR}/${IOQ3_RENDERER_GL2} ]; then + IOQ3_RENDERER_GL2_ARCHS="${BUILT_PRODUCTS_DIR}/${IOQ3_RENDERER_GL2} ${IOQ3_RENDERER_GL2_ARCHS}" + fi + + # game + if [ -e ${BUILT_PRODUCTS_DIR}/${BASEDIR}/${IOQ3_CGAME} ]; then + IOQ3_CGAME_ARCHS="${BUILT_PRODUCTS_DIR}/${BASEDIR}/${IOQ3_CGAME} ${IOQ3_CGAME_ARCHS}" + fi + if [ -e ${BUILT_PRODUCTS_DIR}/${BASEDIR}/${IOQ3_GAME} ]; then + IOQ3_GAME_ARCHS="${BUILT_PRODUCTS_DIR}/${BASEDIR}/${IOQ3_GAME} ${IOQ3_GAME_ARCHS}" + fi + if [ -e ${BUILT_PRODUCTS_DIR}/${BASEDIR}/${IOQ3_UI} ]; then + IOQ3_UI_ARCHS="${BUILT_PRODUCTS_DIR}/${BASEDIR}/${IOQ3_UI} ${IOQ3_UI_ARCHS}" + fi + # missionpack + if [ -e ${BUILT_PRODUCTS_DIR}/${BASEDIR}/${IOQ3_MP_CGAME} ]; then + IOQ3_MP_CGAME_ARCHS="${BUILT_PRODUCTS_DIR}/${MISSIONPACKDIR}/${IOQ3_CGAME} ${IOQ3_MP_CGAME_ARCHS}" + fi + if [ -e ${BUILT_PRODUCTS_DIR}/${BASEDIR}/${IOQ3_MP_GAME} ]; then + IOQ3_MP_GAME_ARCHS="${BUILT_PRODUCTS_DIR}/${MISSIONPACKDIR}/${IOQ3_GAME} ${IOQ3_MP_GAME_ARCHS}" + fi + if [ -e ${BUILT_PRODUCTS_DIR}/${BASEDIR}/${IOQ3_MP_UI} ]; then + IOQ3_MP_UI_ARCHS="${BUILT_PRODUCTS_DIR}/${MISSIONPACKDIR}/${IOQ3_UI} ${IOQ3_MP_UI_ARCHS}" + fi + + #echo "valid arch: ${ARCH}" +done + +# final preparations and checks before attempting to make the application bundle +cd `dirname $0` + +if [ ! -f Makefile ]; then + echo "$0 must be run from the ioquake3 build directory" + exit 1 +fi + +if [ "${IOQ3_CLIENT_ARCHS}" == "" ]; then + echo "$0: no ioquake3 binary architectures were found for target '${TARGET_NAME}'" + exit 1 +fi + +# set the final application bundle output directory +if [ "${2}" == "" ]; then + BUILT_PRODUCTS_DIR="${OBJROOT}/${TARGET_NAME}-darwin-universal" + if [ ! -d ${BUILT_PRODUCTS_DIR} ]; then + mkdir -p ${BUILT_PRODUCTS_DIR} || exit 1; + fi +else + BUILT_PRODUCTS_DIR="${OBJROOT}/${TARGET_NAME}-darwin-${CURRENT_ARCH}" +fi + +BUNDLEBINDIR="${BUILT_PRODUCTS_DIR}/${EXECUTABLE_FOLDER_PATH}" + + +# here we go +echo "Creating bundle '${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}'" +echo "with architectures:" +for ARCH in ${VALID_ARCHS}; do + echo " ${ARCH}" +done +echo "" + +# make the application bundle directories +if [ ! -d ${BUILT_PRODUCTS_DIR}/${EXECUTABLE_FOLDER_PATH}/$BASEDIR ]; then + mkdir -p ${BUILT_PRODUCTS_DIR}/${EXECUTABLE_FOLDER_PATH}/$BASEDIR || exit 1; +fi +if [ ! -d ${BUILT_PRODUCTS_DIR}/${EXECUTABLE_FOLDER_PATH}/$MISSIONPACKDIR ]; then + mkdir -p ${BUILT_PRODUCTS_DIR}/${EXECUTABLE_FOLDER_PATH}/$MISSIONPACKDIR || exit 1; +fi +if [ ! -d ${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH} ]; then + mkdir -p ${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH} || exit 1; +fi + +# copy and generate some application bundle resources +cp code/libs/macosx/*.dylib ${BUILT_PRODUCTS_DIR}/${EXECUTABLE_FOLDER_PATH} +cp ${ICNSDIR}/${ICNS} ${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/$ICNS || exit 1; +echo -n ${PKGINFO} > ${BUILT_PRODUCTS_DIR}/${CONTENTS_FOLDER_PATH}/PkgInfo || exit 1; +echo " + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + quake3_flat + CFBundleIdentifier + org.ioquake.${PRODUCT_NAME} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + ${IOQ3_VERSION} + CFBundleSignature + ???? + CFBundleVersion + ${IOQ3_VERSION} + CGDisableCoalescedUpdates + + LSMinimumSystemVersion + ${MACOSX_DEPLOYMENT_TARGET} + NSHumanReadableCopyright + QUAKE III ARENA Copyright © 1999-2000 id Software, Inc. All rights reserved. + NSPrincipalClass + NSApplication + + +" > ${BUILT_PRODUCTS_DIR}/${CONTENTS_FOLDER_PATH}/Info.plist + +# action takes care of generating universal binaries if lipo is available +# otherwise, it falls back to using a simple copy, expecting the first item in +# the second parameter list to be the desired architecture +function action() +{ + COMMAND="" + + if [ -x "${HAS_LIPO}" ]; then + COMMAND="${HAS_LIPO} -create -o" + $HAS_LIPO -create -o "${1}" ${2} # make sure $2 is treated as a list of files + elif [ -x ${HAS_CP} ]; then + COMMAND="${HAS_CP}" + SRC="${2// */}" # in case there is a list here, use only the first item + $HAS_CP "${SRC}" "${1}" + else + "$0 cannot create an application bundle." + exit 1 + fi + + #echo "${COMMAND}" "${1}" "${2}" +} + +# +# the meat of universal binary creation +# destination file names do not have architecture suffix. +# action will handle merging universal binaries if supported. +# symlink appropriate architecture names for universal (fat) binary support. +# + +# executables +action ${BUNDLEBINDIR}/${EXECUTABLE_NAME} "${IOQ3_CLIENT_ARCHS}" +action ${BUNDLEBINDIR}/${DEDICATED_NAME} "${IOQ3_SERVER_ARCHS}" + +# renderers +action ${BUNDLEBINDIR}/${RENDERER_OPENGL1_NAME} "${IOQ3_RENDERER_GL1_ARCHS}" +action ${BUNDLEBINDIR}/${RENDERER_OPENGL2_NAME} "${IOQ3_RENDERER_GL2_ARCHS}" +symlinkArch "${RENDERER_OPENGL}1" "${RENDERER_OPENGL}1" "_" "${BUNDLEBINDIR}" +symlinkArch "${RENDERER_OPENGL}2" "${RENDERER_OPENGL}2" "_" "${BUNDLEBINDIR}" + +# game +action ${BUNDLEBINDIR}/${BASEDIR}/${CGAME_NAME} "${IOQ3_CGAME_ARCHS}" +action ${BUNDLEBINDIR}/${BASEDIR}/${GAME_NAME} "${IOQ3_GAME_ARCHS}" +action ${BUNDLEBINDIR}/${BASEDIR}/${UI_NAME} "${IOQ3_UI_ARCHS}" +symlinkArch "${CGAME}" "${CGAME}" "" "${BUNDLEBINDIR}/${BASEDIR}" +symlinkArch "${GAME}" "${GAME}" "" "${BUNDLEBINDIR}/${BASEDIR}" +symlinkArch "${UI}" "${UI}" "" "${BUNDLEBINDIR}/${BASEDIR}" + +# missionpack +action ${BUNDLEBINDIR}/${MISSIONPACKDIR}/${CGAME_NAME} "${IOQ3_MP_CGAME_ARCHS}" +action ${BUNDLEBINDIR}/${MISSIONPACKDIR}/${GAME_NAME} "${IOQ3_MP_GAME_ARCHS}" +action ${BUNDLEBINDIR}/${MISSIONPACKDIR}/${UI_NAME} "${IOQ3_MP_UI_ARCHS}" +symlinkArch "${CGAME}" "${CGAME}" "" "${BUNDLEBINDIR}/${MISSIONPACKDIR}" +symlinkArch "${GAME}" "${GAME}" "" "${BUNDLEBINDIR}/${MISSIONPACKDIR}" +symlinkArch "${UI}" "${UI}" "" "${BUNDLEBINDIR}/${MISSIONPACKDIR}" diff --git a/make-macosx-ub.sh b/make-macosx-ub.sh index 841df44b..5f73fe36 100755 --- a/make-macosx-ub.sh +++ b/make-macosx-ub.sh @@ -1,66 +1,35 @@ -#!/bin/sh +#!/bin/bash CC=gcc-4.0 -APPBUNDLE=Reaction.app -BINARY=Reaction.ub -DEDBIN=Reactionded.ub -PKGINFO=APPLIOQ3 -ICNS=misc/quake3.icns -DESTDIR=build/release-darwin-ub -BASEDIR=Boomstick -MPACKDIR=missionpack -LANG=C -LC_ALL=C - -BIN_OBJ=" - build/release-darwin-x86_64/Reaction.x86_64 - build/release-darwin-i386/Reaction.i386 -" -BIN_DEDOBJ=" - build/release-darwin-x86_64/Reactionded.x86_64 - build/release-darwin-i386/Reactionded.i386 -" -BASE_OBJ=" - build/release-darwin-x86_64/$BASEDIR/cgamex86_64.dylib - build/release-darwin-i386/$BASEDIR/cgamei386.dylib - build/release-darwin-x86_64/$BASEDIR/uix86_64.dylib - build/release-darwin-i386/$BASEDIR/uii386.dylib - build/release-darwin-x86_64/$BASEDIR/qagamex86_64.dylib - build/release-darwin-i386/$BASEDIR/qagamei386.dylib -" -MPACK_OBJ=" - build/release-darwin-x86_64/$MPACKDIR/cgamex86_64.dylib - build/release-darwin-i386/$MPACKDIR/cgamei386.dylib - build/release-darwin-x86_64/$MPACKDIR/uix86_64.dylib - build/release-darwin-i386/$MPACKDIR/uii386.dylib - build/release-darwin-x86_64/$MPACKDIR/qagamex86_64.dylib - build/release-darwin-i386/$MPACKDIR/qagamei386.dylib -" -RENDER_OBJ=" - build/release-darwin-x86_64/renderer_opengl1_smp_x86_64.dylib - build/release-darwin-i386/renderer_opengl1_smp_i386.dylib - build/release-darwin-x86_64/renderer_opengl1_x86_64.dylib - build/release-darwin-i386/renderer_opengl1_i386.dylib - build/release-darwin-x86_64/renderer_rend2_smp_x86_64.dylib - build/release-darwin-i386/renderer_rend2_smp_i386.dylib - build/release-darwin-x86_64/renderer_rend2_x86_64.dylib - build/release-darwin-i386/renderer_rend2_i386.dylib -" +BINARY=ioquake3.ub cd `dirname $0` if [ ! -f Makefile ]; then - echo "This script must be run from the Reaction build directory" + echo "This script must be run from the ioquake3 build directory" exit 1 fi Q3_VERSION=`grep '^VERSION=' Makefile | sed -e 's/.*=\(.*\)/\1/'` -# we want to use the oldest available SDK for max compatiblity +# We only care if we're >= 10.4, not if we're specifically Tiger. +# "8" is the Darwin major kernel version. +TIGERHOST=`uname -r |perl -w -p -e 's/\A(\d+)\..*\Z/$1/; $_ = (($_ >= 8) ? "1" : "0");'` + +# we want to use the oldest available SDK for max compatiblity. However 10.4 and older +# can not build 64bit binaries, making 10.5 the minimum version. This has been tested +# with xcode 3.1 (xcode31_2199_developerdvd.dmg). It contains the 10.5 SDK and a decent +# enough gcc to actually compile ioquake3 +# For PPC macs, G4's or better are required to run ioquake3. + unset X86_64_SDK unset X86_64_CFLAGS unset X86_64_LDFLAGS unset X86_SDK unset X86_CFLAGS unset X86_LDFLAGS +unset PPC_64_SDK +unset PPC_CFLAGS +unset PPC_LDFLAGS + if [ -d /Developer/SDKs/MacOSX10.5.sdk ]; then X86_64_SDK=/Developer/SDKs/MacOSX10.5.sdk X86_64_CFLAGS="-arch x86_64 -isysroot /Developer/SDKs/MacOSX10.5.sdk \ @@ -71,44 +40,29 @@ if [ -d /Developer/SDKs/MacOSX10.5.sdk ]; then X86_CFLAGS="-arch i386 -isysroot /Developer/SDKs/MacOSX10.5.sdk \ -DMAC_OS_X_VERSION_MIN_REQUIRED=1050" X86_LDFLAGS=" -mmacosx-version-min=10.5" + + PPC_SDK=/Developer/SDKs/MacOSX10.5.sdk + PPC_CFLAGS="-arch ppc -isysroot /Developer/SDKs/MacOSX10.5.sdk \ + -DMAC_OS_X_VERSION_MIN_REQUIRED=1050" + PPC_LDFLAGS=" -mmacosx-version-min=10.5" fi -# The 10.4 SDK is not 64 bit ready and can not be used to build 64bit versions. -# This makes 10.5 the minimum for UB's containing x86_64 -# -#if [ -d /Developer/SDKs/MacOSX10.4u.sdk ]; then -# X86_64_SDK=/Developer/SDKs/MacOSX10.4u.sdk -# X86_64_CFLAGS="-arch x86_64 -isysroot /Developer/SDKs/MacOSX10.4u.sdk \ -# -DMAC_OS_X_VERSION_MIN_REQUIRED=1040" -# X86_64_LDFLAGS=" -mmacosx-version-min=10.4" -# -# X86_SDK=/Developer/SDKs/MacOSX10.4u.sdk -# X86_CFLAGS="-arch i386 -isysroot /Developer/SDKs/MacOSX10.4u.sdk \ -# -DMAC_OS_X_VERSION_MIN_REQUIRED=1040" -# X86_LDFLAGS=" -mmacosx-version-min=10.4" -#fi -# -#if [ -d /Developer/SDKs/MacOSX10.3.9.sdk ] && [ $TIGERHOST ]; then -# X86_64_SDK=/Developer/SDKs/MacOSX10.3.9.sdk -# X86_64_CFLAGS="-arch x86_64 -isysroot /Developer/SDKs/MacOSX10.3.9.sdk \ -# -DMAC_OS_X_VERSION_MIN_REQUIRED=1030" -# X86_64_LDFLAGS=" -mmacosx-version-min=10.3" -#fi - -if [ -z $X86_64_SDK ] || [ -z $X86_SDK ]; then +if [ -z $X86_64_SDK ] || [ -z $X86_SDK ] || [ -z $PPC_SDK ]; then echo "\ ERROR: This script is for building a Universal Binary. You cannot build for a different architecture unless you have the proper Mac OS X SDKs installed. If you just want to to compile for your own system run - 'make' instead of this script." + 'make-macosx.sh' instead of this script." exit 1 fi echo "Building X86_64 Client/Dedicated Server against \"$X86_64_SDK\"" echo "Building X86 Client/Dedicated Server against \"$X86_SDK\"" +echo "Building PPC Client/Dedicated Server against \"$PPC_SDK\"" echo + if [ "$X86_64_SDK" != "/Developer/SDKs/MacOSX10.5.sdk" ] || \ - [ "$X86_SDK" != "/Developer/SDKs/MacOSX10.5.sdk" ]; then + [ "$X86_SDK" != "/Developer/SDKs/MacOSX10.5.sdk" ]; then echo "\ WARNING: in order to build a binary with maximum compatibility you must build on Mac OS X 10.5 using Xcode 3.1 and have the MacOSX10.5 @@ -116,98 +70,32 @@ WARNING: in order to build a binary with maximum compatibility you must sleep 3 fi -if [ ! -d $DESTDIR ]; then - mkdir -p $DESTDIR -fi - # For parallel make on multicore boxes... NCPU=`sysctl -n hw.ncpu` # x86_64 client and server -if [ -d build/release-release-x86_64 ]; then - rm -r build/release-darwin-x86_64 -fi +#if [ -d build/release-release-x86_64 ]; then +# rm -r build/release-darwin-x86_64 +#fi (ARCH=x86_64 CC=gcc-4.0 CFLAGS=$X86_64_CFLAGS LDFLAGS=$X86_64_LDFLAGS make -j$NCPU) || exit 1; -echo;echo;echo +echo;echo -# i386 client and server -if [ -d build/release-darwin-i386 ]; then - rm -r build/release-darwin-i386 -fi -(ARCH=i386 CC=gcc-4.0 CFLAGS=$X86_CFLAGS LDFLAGS=$X86_LDFLAGS make -j$NCPU) || exit 1; +# x86 client and server +#if [ -d build/release-darwin-x86 ]; then +# rm -r build/release-darwin-x86 +#fi +(ARCH=x86 CC=gcc-4.0 CFLAGS=$X86_CFLAGS LDFLAGS=$X86_LDFLAGS make -j$NCPU) || exit 1; -echo;echo;echo +echo;echo -echo "Creating .app bundle $DESTDIR/$APPBUNDLE" -if [ ! -d $DESTDIR/$APPBUNDLE/Contents/MacOS/$BASEDIR ]; then - mkdir -p $DESTDIR/$APPBUNDLE/Contents/MacOS/$BASEDIR || exit 1; -fi -if [ ! -d $DESTDIR/$APPBUNDLE/Contents/MacOS/$MPACKDIR ]; then - mkdir -p $DESTDIR/$APPBUNDLE/Contents/MacOS/$MPACKDIR || exit 1; -fi -if [ ! -d $DESTDIR/$APPBUNDLE/Contents/Resources ]; then - mkdir -p $DESTDIR/$APPBUNDLE/Contents/Resources -fi -cp $ICNS $DESTDIR/$APPBUNDLE/Contents/Resources/Reaction.icns || exit 1; -echo $PKGINFO > $DESTDIR/$APPBUNDLE/Contents/PkgInfo -echo " - - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - $BINARY - CFBundleGetInfoString - Reaction 1.0 - CFBundleIconFile - Reaction.icns - CFBundleIdentifier - org.ioquake.Reaction - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - Reaction - CFBundlePackageType - APPL - CFBundleShortVersionString - $Q3_VERSION - CFBundleSignature - $PKGINFO - CFBundleVersion - $Q3_VERSION - NSExtensions - - NSPrincipalClass - NSApplication - - - " > $DESTDIR/$APPBUNDLE/Contents/Info.plist +# PPC client and server +#if [ -d build/release-darwin-ppc ]; then +# rm -r build/release-darwin-ppc +#fi +(ARCH=ppc CC=gcc-4.0 CFLAGS=$PPC_CFLAGS LDFLAGS=$PPC_LDFLAGS make -j$NCPU) || exit 1; -# Change the path of the SDL Framework in both arches for the executables and renderer dylib's -for i in $BIN_OBJ $BIN_DEDOBJ $RENDER_OBJ -do - install_name_tool -change "@rpath/SDL.framework/Versions/A/SDL" "@executable_path/../Frameworks/SDL.framework/Versions/A/SDL" $i -done - -# Make UB's from previous builds of 1386 and x86_64 binaries -lipo -create -o $DESTDIR/$APPBUNDLE/Contents/MacOS/$BINARY $BIN_OBJ -lipo -create -o $DESTDIR/$APPBUNDLE/Contents/MacOS/$DEDBIN $BIN_DEDOBJ - -# Embed the SDL framework into the .app so players done need to install it on their systems. -mkdir $DESTDIR/$APPBUNDLE/Contents/Frameworks -unzip -d $DESTDIR/$APPBUNDLE/Contents/Frameworks code/libs/macosx/SDL-1.2.15.framework.zip - -# Change the path in the UB, just in case -install_name_tool -change "@rpath/SDL.framework/Versions/A/SDL" "@executable_path/../Frameworks/SDL.framework/Versions/A/SDL" $DESTDIR/$APPBUNDLE/Contents/MacOS/$BINARY -install_name_tool -change "@rpath/SDL.framework/Versions/A/SDL" "@executable_path/../Frameworks/SDL.framework/Versions/A/SDL" $DESTDIR/$APPBUNDLE/Contents/MacOS/$DEDBIN - -cp $RENDER_OBJ $DESTDIR/$APPBUNDLE/Contents/MacOS/ -cp $BASE_OBJ $DESTDIR/$APPBUNDLE/Contents/MacOS/$BASEDIR/ -#cp $MPACK_OBJ $DESTDIR/$APPBUNDLE/Contents/MacOS/$MPACKDIR/ -cp code/libs/macosx/*.dylib $DESTDIR/$APPBUNDLE/Contents/MacOS/ +echo +# use the following shell script to build a universal application bundle +"./make-macosx-app.sh" release diff --git a/make-macosx.sh b/make-macosx.sh index cbdbab55..6dd5df17 100644 --- a/make-macosx.sh +++ b/make-macosx.sh @@ -1,40 +1,40 @@ -#!/bin/sh -CC=gcc-4.0 -APPBUNDLE=Reaction.app -BINARY=Reaction.x86_64 -DEDBIN=Reactionded.x86_64 -PKGINFO=APPLIOQ3 -ICNS=misc/quake3.icns -DESTDIR=build/release-darwin-x86_64 -BASEDIR=Boomstick -MPACKDIR=missionpack +#!/bin/bash +# -BIN_OBJ=" - build/release-darwin-x86_64/Reaction.x86_64 -" -BIN_DEDOBJ=" - build/release-darwin-x86_64/Reactionded.x86_64 -" -BASE_OBJ=" - build/release-darwin-x86_64/$BASEDIR/cgamex86_64.dylib - build/release-darwin-x86_64/$BASEDIR/uix86_64.dylib - build/release-darwin-x86_64/$BASEDIR/qagamex86_64.dylib -" -MPACK_OBJ=" - build/release-darwin-x86_64/$MPACKDIR/cgamex86_64.dylib - build/release-darwin-x86_64/$MPACKDIR/uix86_64.dylib - build/release-darwin-x86_64/$MPACKDIR/qagamex86_64.dylib -" -RENDER_OBJ=" - build/release-darwin-x86_64/renderer_opengl1_smp_x86_64.dylib - build/release-darwin-x86_64/renderer_opengl1_x86_64.dylib - build/release-darwin-x86_64/renderer_rend2_smp_x86_64.dylib - build/release-darwin-x86_64/renderer_rend2_x86_64.dylib -" +# Let's make the user give us a target build system + +if [ $# -ne 1 ]; then + echo "Usage: $0 target_architecture" + echo "Example: $0 x86" + echo "other valid options are x86_64 or ppc" + echo + echo "If you don't know or care about architectures please consider using make-macosx-ub.sh instead of this script." + exit 1 +fi + +if [ "$1" == "x86" ]; then + BUILDARCH=x86 + DARWIN_GCC_ARCH=i386 +elif [ "$1" == "x86_64" ]; then + BUILDARCH=x86_64 +elif [ "$1" == "ppc" ]; then + BUILDARCH=ppc +else + echo "Invalid architecture: $1" + echo "Valid architectures are x86, x86_64 or ppc" + exit 1 +fi + +if [ -z "$DARWIN_GCC_ARCH" ]; then + DARWIN_GCC_ARCH=${BUILDARCH} +fi + +CC=gcc-4.0 +DESTDIR=build/release-darwin-${BUILDARCH} cd `dirname $0` if [ ! -f Makefile ]; then - echo "This script must be run from the Reaction build directory" + echo "This script must be run from the ioquake3 build directory" exit 1 fi @@ -45,22 +45,24 @@ Q3_VERSION=`grep '^VERSION=' Makefile | sed -e 's/.*=\(.*\)/\1/'` TIGERHOST=`uname -r |perl -w -p -e 's/\A(\d+)\..*\Z/$1/; $_ = (($_ >= 8) ? "1" : "0");'` # we want to use the oldest available SDK for max compatiblity. However 10.4 and older -# can not build 64bit binaries, making 10.5 the minimum version. This has been tested +# can not build 64bit binaries, making 10.5 the minimum version. This has been tested # with xcode 3.1 (xcode31_2199_developerdvd.dmg). It contains the 10.5 SDK and a decent # enough gcc to actually compile ioquake3 +# For PPC macs, G4's or better are required to run ioquake3. + +unset ARCH_SDK +unset ARCH_CFLAGS +unset ARCH_LDFLAGS -unset X86_SDK -unset X86_CFLAGS -unset X86_LDFLAGS if [ -d /Developer/SDKs/MacOSX10.5.sdk ]; then - X86_SDK=/Developer/SDKs/MacOSX10.5.sdk - X86_CFLAGS="-arch x86_64 -isysroot /Developer/SDKs/MacOSX10.5.sdk \ + ARCH_SDK=/Developer/SDKs/MacOSX10.5.sdk + ARCH_CFLAGS="-arch ${DARWIN_GCC_ARCH} -isysroot /Developer/SDKs/MacOSX10.5.sdk \ -DMAC_OS_X_VERSION_MIN_REQUIRED=1050" - X86_LDFLAGS=" -mmacosx-version-min=10.5" + ARCH_LDFLAGS=" -mmacosx-version-min=10.5" fi -echo "Building X86 Client/Dedicated Server against \"$X86_SDK\"" +echo "Building ${BUILDARCH} Client/Dedicated Server against \"$ARCH_SDK\"" sleep 3 if [ ! -d $DESTDIR ]; then @@ -72,69 +74,10 @@ NCPU=`sysctl -n hw.ncpu` # intel client and server -if [ -d build/release-darwin-x86_64 ]; then - rm -r build/release-darwin-x86_64 -fi -(ARCH=x86_64 CFLAGS=$X86_CFLAGS LDFLAGS=$X86_LDFLAGS make -j$NCPU) || exit 1; - -echo "Creating .app bundle $DESTDIR/$APPBUNDLE" -if [ ! -d $DESTDIR/$APPBUNDLE/Contents/MacOS/$BASEDIR ]; then - mkdir -p $DESTDIR/$APPBUNDLE/Contents/MacOS/$BASEDIR || exit 1; -fi -if [ ! -d $DESTDIR/$APPBUNDLE/Contents/MacOS/$MPACKDIR ]; then - mkdir -p $DESTDIR/$APPBUNDLE/Contents/MacOS/$MPACKDIR || exit 1; -fi -if [ ! -d $DESTDIR/$APPBUNDLE/Contents/Resources ]; then - mkdir -p $DESTDIR/$APPBUNDLE/Contents/Resources -fi -cp $ICNS $DESTDIR/$APPBUNDLE/Contents/Resources/Reaction.icns || exit 1; -echo $PKGINFO > $DESTDIR/$APPBUNDLE/Contents/PkgInfo -echo " - - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - $BINARY - CFBundleGetInfoString - Reaction $Q3_VERSION - CFBundleIconFile - Reaction.icns - CFBundleIdentifier - org.ioquake.Reaction - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - Reaction - CFBundlePackageType - APPL - CFBundleShortVersionString - $Q3_VERSION - CFBundleSignature - $PKGINFO - CFBundleVersion - $Q3_VERSION - NSExtensions - - NSPrincipalClass - NSApplication - - - " > $DESTDIR/$APPBUNDLE/Contents/Info.plist - -for i in $BIN_OBJ $BIN_DEDOBJ $RENDER_OBJ -do - install_name_tool -change "@rpath/SDL.framework/Versions/A/SDL" "@executable_path/../Frameworks/SDL.framework/Versions/A/SDL" $i -done - -cp $BIN_OBJ $DESTDIR/$APPBUNDLE/Contents/MacOS/$BINARY -cp $BIN_DEDOBJ $DESTDIR/$APPBUNDLE/Contents/MacOS/$DEDBIN -cp $RENDER_OBJ $DESTDIR/$APPBUNDLE/Contents/MacOS/ -cp $BASE_OBJ $DESTDIR/$APPBUNDLE/Contents/MacOS/$BASEDIR/ -#cp $MPACK_OBJ $DESTDIR/$APPBUNDLE/Contents/MacOS/$MPACKDIR/ -cp code/libs/macosx/*.dylib $DESTDIR/$APPBUNDLE/Contents/MacOS/ +#if [ -d build/release-darwin-${BUILDARCH} ]; then +# rm -r build/release-darwin-${BUILDARCH} +#fi +(ARCH=${BUILDARCH} CFLAGS=$ARCH_CFLAGS LDFLAGS=$ARCH_LDFLAGS make -j$NCPU) || exit 1; +# use the following shell script to build an application bundle +"./make-macosx-app.sh" release ${BUILDARCH} diff --git a/misc/sdl-win32-fixes.diff b/misc/sdl-win32-fixes.diff deleted file mode 100644 index 3c0b8681..00000000 --- a/misc/sdl-win32-fixes.diff +++ /dev/null @@ -1,596 +0,0 @@ -Index: src/video/wincommon/SDL_lowvideo.h -=================================================================== ---- src/video/wincommon/SDL_lowvideo.h (revision 4067) -+++ src/video/wincommon/SDL_lowvideo.h (working copy) -@@ -51,10 +51,13 @@ - /* Hidden "this" pointer for the video functions */ - #define _THIS SDL_VideoDevice *this - -+#define FULLSCREEN() \ -+ ((SDL_VideoSurface->flags & SDL_FULLSCREEN) == SDL_FULLSCREEN) -+ - #define WINDIB_FULLSCREEN() \ - ( \ - SDL_VideoSurface && \ -- ((SDL_VideoSurface->flags & SDL_FULLSCREEN) == SDL_FULLSCREEN) && \ -+ FULLSCREEN() && \ - (((SDL_VideoSurface->flags & SDL_OPENGL ) == SDL_OPENGL ) || \ - ((SDL_strcmp(this->name, "windib") == 0) || \ - (SDL_strcmp(this->name, "gapi") == 0))) \ -@@ -62,13 +65,19 @@ - #define DDRAW_FULLSCREEN() \ - ( \ - SDL_VideoSurface && \ -- ((SDL_VideoSurface->flags & SDL_FULLSCREEN) == SDL_FULLSCREEN) && \ -+ FULLSCREEN() && \ - ((SDL_VideoSurface->flags & SDL_OPENGL ) != SDL_OPENGL ) && \ - (SDL_strcmp(this->name, "directx") == 0) \ - ) - --#define DINPUT_FULLSCREEN() DDRAW_FULLSCREEN() -+#define DINPUT_FULLSCREEN() \ -+( \ -+ FULLSCREEN() && \ -+ (strcmp(this->name, "directx") == 0) \ -+) - -+#define DINPUT() (strcmp(this->name, "directx") == 0) -+ - /* The main window -- and a function to set it for the audio */ - #ifdef _WIN32_WCE - extern LPWSTR SDL_Appname; -Index: src/video/wincommon/SDL_sysevents.c -=================================================================== ---- src/video/wincommon/SDL_sysevents.c (revision 4067) -+++ src/video/wincommon/SDL_sysevents.c (working copy) -@@ -335,7 +335,6 @@ - { - SDL_VideoDevice *this = current_video; - static int mouse_pressed = 0; -- static int in_window = 0; - #ifdef WMMSG_DEBUG - fprintf(stderr, "Received windows message: "); - if ( msg > MAX_WMMSG ) { -@@ -411,62 +410,41 @@ - break; - - case WM_MOUSEMOVE: { -- -- /* Mouse is handled by DirectInput when fullscreen */ -- if ( SDL_VideoSurface && ! DINPUT_FULLSCREEN() ) { -- Sint16 x, y; - -- /* mouse has entered the window */ -- if ( ! in_window ) { - #ifdef WM_MOUSELEAVE -+ /* No need to handle SDL_APPMOUSEFOCUS when fullscreen */ -+ if ( SDL_VideoSurface && !FULLSCREEN() ) { -+ /* mouse has entered the window */ -+ -+ if ( !(SDL_GetAppState() & SDL_APPMOUSEFOCUS) ) { - TRACKMOUSEEVENT tme; - - tme.cbSize = sizeof(tme); - tme.dwFlags = TME_LEAVE; - tme.hwndTrack = SDL_Window; - _TrackMouseEvent(&tme); -+ } -+ } - #endif /* WM_MOUSELEAVE */ -- in_window = TRUE; - -- posted = SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS); -- } -+ /* Mouse motion is handled in DIB_PumpEvents or -+ * DX5_PumpEvents, depending on the video driver -+ * in use */ - -- /* mouse has moved within the window */ -- x = LOWORD(lParam); -- y = HIWORD(lParam); -- if ( mouse_relative ) { -- POINT center; -- center.x = (SDL_VideoSurface->w/2); -- center.y = (SDL_VideoSurface->h/2); -- x -= (Sint16)center.x; -- y -= (Sint16)center.y; -- if ( x || y ) { -- ClientToScreen(SDL_Window, ¢er); -- SetCursorPos(center.x, center.y); -- posted = SDL_PrivateMouseMotion(0, 1, x, y); -- } -- } else { --#ifdef _WIN32_WCE -- if (SDL_VideoSurface) -- GapiTransform(this->hidden->userOrientation, this->hidden->hiresFix, &x, &y); --#endif -- posted = SDL_PrivateMouseMotion(0, 0, x, y); -- } -- } -+ posted = SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS); - } - return(0); - - #ifdef WM_MOUSELEAVE - case WM_MOUSELEAVE: { - -- /* Mouse is handled by DirectInput when fullscreen */ -- if ( SDL_VideoSurface && ! DINPUT_FULLSCREEN() ) { -+ /* No need to handle SDL_APPMOUSEFOCUS when fullscreen */ -+ if ( SDL_VideoSurface && !FULLSCREEN() ) { - /* mouse has left the window */ - /* or */ - /* Elvis has left the building! */ - posted = SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS); - } -- in_window = FALSE; - } - return(0); - #endif /* WM_MOUSELEAVE */ -@@ -480,7 +458,7 @@ - case WM_XBUTTONDOWN: - case WM_XBUTTONUP: { - /* Mouse is handled by DirectInput when fullscreen */ -- if ( SDL_VideoSurface && ! DINPUT_FULLSCREEN() ) { -+ if ( SDL_VideoSurface && ! DINPUT() ) { - WORD xbuttonval = 0; - Sint16 x, y; - Uint8 button, state; -@@ -544,20 +522,8 @@ - mouse_pressed = 0; - } - } -- if ( mouse_relative ) { -- /* RJR: March 28, 2000 -- report internal mouse position if in relative mode */ -- x = 0; y = 0; -- } else { -- x = (Sint16)LOWORD(lParam); -- y = (Sint16)HIWORD(lParam); --#ifdef _WIN32_WCE -- if (SDL_VideoSurface) -- GapiTransform(this->hidden->userOrientation, this->hidden->hiresFix, &x, &y); --#endif -- } - posted = SDL_PrivateMouseButton( -- state, button, x, y); -+ state, button, 0, 0); - - /* - * MSDN says: -@@ -578,7 +544,7 @@ - - #if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400) - case WM_MOUSEWHEEL: -- if ( SDL_VideoSurface && ! DINPUT_FULLSCREEN() ) { -+ if ( SDL_VideoSurface && ! DINPUT() ) { - int move = (short)HIWORD(wParam); - if ( move ) { - Uint8 button; -Index: src/video/wincommon/SDL_sysmouse.c -=================================================================== ---- src/video/wincommon/SDL_sysmouse.c (revision 4067) -+++ src/video/wincommon/SDL_sysmouse.c (working copy) -@@ -188,8 +188,7 @@ - { - POINT mouse_pos; - -- /* The fullscreen cursor must be done in software with DirectInput */ -- if ( !this->screen || DDRAW_FULLSCREEN() ) { -+ if ( !this->screen ) { - return(0); - } - -@@ -208,15 +207,20 @@ - - void WIN_WarpWMCursor(_THIS, Uint16 x, Uint16 y) - { -- if ( DDRAW_FULLSCREEN() ) { -- SDL_PrivateMouseMotion(0, 0, x, y); -- } else if ( mouse_relative) { -+ if ( mouse_relative) { - /* RJR: March 28, 2000 - leave physical cursor at center of screen if - mouse hidden and grabbed */ - SDL_PrivateMouseMotion(0, 0, x, y); - } else { - POINT pt; -+ -+ /* With DirectInput the position doesn't follow -+ * the cursor, so it is set manually */ -+ if ( DINPUT() ) { -+ SDL_PrivateMouseMotion(0, 0, x, y); -+ } -+ - pt.x = x; - pt.y = y; - ClientToScreen(SDL_Window, &pt); -@@ -227,20 +231,15 @@ - /* Update the current mouse state and position */ - void WIN_UpdateMouse(_THIS) - { -- RECT rect; - POINT pt; - -- if ( ! DDRAW_FULLSCREEN() ) { -- GetClientRect(SDL_Window, &rect); -- GetCursorPos(&pt); -- MapWindowPoints(NULL, SDL_Window, &pt, 1); -- if (PtInRect(&rect, pt) && (WindowFromPoint(pt) == SDL_Window)){ -- SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS); -- SDL_PrivateMouseMotion(0,0, (Sint16)pt.x, (Sint16)pt.y); -- } else { -- SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS); -- } -- } -+ /* Always unset SDL_APPMOUSEFOCUS to give the WM_MOUSEMOVE event -+ * handler a chance to install a TRACKMOUSEEVENT */ -+ SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS); -+ -+ GetCursorPos(&pt); -+ ScreenToClient(SDL_Window, &pt); -+ SDL_PrivateMouseMotion(0,0, (Sint16)pt.x, (Sint16)pt.y); - } - - /* Check to see if we need to enter or leave mouse relative mode */ -Index: src/video/windib/SDL_dibevents.c -=================================================================== ---- src/video/windib/SDL_dibevents.c (revision 4067) -+++ src/video/windib/SDL_dibevents.c (working copy) -@@ -262,6 +262,36 @@ - return(DefWindowProc(hwnd, msg, wParam, lParam)); - } - -+static void DIB_GenerateMouseMotionEvent(void) -+{ -+ extern int mouse_relative; -+ extern int posted; -+ -+ POINT mouse; -+ GetCursorPos( &mouse ); -+ -+ if ( mouse_relative ) { -+ POINT center; -+ center.x = (SDL_VideoSurface->w/2); -+ center.y = (SDL_VideoSurface->h/2); -+ ClientToScreen(SDL_Window, ¢er); -+ -+ mouse.x -= (Sint16)center.x; -+ mouse.y -= (Sint16)center.y; -+ if ( mouse.x || mouse.y ) { -+ SetCursorPos(center.x, center.y); -+ posted = SDL_PrivateMouseMotion(0, 1, mouse.x, mouse.y); -+ } -+ } else if ( SDL_GetAppState() & SDL_APPMOUSEFOCUS ) { -+ ScreenToClient(SDL_Window, &mouse); -+#ifdef _WIN32_WCE -+ if (SDL_VideoSurface) -+ GapiTransform(this->hidden->userOrientation, this->hidden->hiresFix, &mouse.x, &mouse.y); -+#endif -+ posted = SDL_PrivateMouseMotion(0, 0, mouse.x, mouse.y); -+ } -+} -+ - void DIB_PumpEvents(_THIS) - { - MSG msg; -@@ -271,6 +301,10 @@ - DispatchMessage(&msg); - } - } -+ -+ if ( SDL_GetAppState() & SDL_APPINPUTFOCUS ) { -+ DIB_GenerateMouseMotionEvent( ); -+ } - } - - static HKL hLayoutUS = NULL; -@@ -494,7 +528,7 @@ - Uint16 wchars[2]; - - GetKeyboardState(keystate); -- if (SDL_ToUnicode((UINT)vkey, scancode, keystate, wchars, sizeof(wchars)/sizeof(wchars[0]), 0) == 1) -+ if (SDL_ToUnicode((UINT)vkey, scancode, keystate, wchars, sizeof(wchars)/sizeof(wchars[0]), 0) > 0) - { - keysym->unicode = wchars[0]; - } -Index: src/video/windx5/SDL_dx5events.c -=================================================================== ---- src/video/windx5/SDL_dx5events.c (revision 4067) -+++ src/video/windx5/SDL_dx5events.c (working copy) -@@ -143,9 +143,14 @@ - (DISCL_FOREGROUND|DISCL_NONEXCLUSIVE), - (DISCL_FOREGROUND|DISCL_NONEXCLUSIVE), handle_keyboard }, - { "mouse", -- &GUID_SysMouse, &c_dfDIMouse, -+ &GUID_SysMouse, -+#if DIRECTINPUT_VERSION >= 0x700 -+ &c_dfDIMouse2, -+#else -+ &c_dfDIMouse, -+#endif - (DISCL_FOREGROUND|DISCL_NONEXCLUSIVE), -- (DISCL_FOREGROUND|DISCL_EXCLUSIVE), handle_mouse }, -+ (DISCL_FOREGROUND|DISCL_NONEXCLUSIVE), handle_mouse }, - { NULL, NULL, NULL, 0, 0, NULL } - }; - -@@ -285,6 +290,76 @@ - } - } - } -+ -+static void post_mouse_motion(int relative, Sint16 x, Sint16 y) -+{ -+ extern int mouse_relative; -+ -+ if ( SDL_GetAppState() & (SDL_APPINPUTFOCUS|SDL_APPMOUSEFOCUS) == -+ (SDL_APPINPUTFOCUS|SDL_APPMOUSEFOCUS) ) { -+ posted = SDL_PrivateMouseMotion( -+ 0, relative, x, y); -+ -+ if ( !mouse_relative ) { -+ /* As DirectInput reads raw device coordinates, it has no notion of -+ * cursors or absolute position. We must assume responsibility for -+ * keeping track of this. */ -+ int current_x, current_y; -+ POINT cursor; -+ RECT trap; -+ RECT window; -+ int at_edge; -+ -+ /* Get the current cursor position */ -+ SDL_GetMouseState(¤t_x, ¤t_y); -+ cursor.x = current_x; -+ cursor.y = current_y; -+ ClientToScreen(SDL_Window, &cursor); -+ -+ /* Construct a 1 pixel square RECT that is used to confine the cursor -+ * pointer to a specific pixel using ClipCursor. This is used in -+ * preference to SetCursorPos as it avoids the cursor jumping around as -+ * both the OS and SDL attempt to move it simultaneously. */ -+ trap.left = cursor.x; -+ trap.top = cursor.y; -+ trap.right = cursor.x + 1; -+ trap.bottom = cursor.y + 1; -+ -+ GetClientRect(SDL_Window, &window); -+ window.right -= window.left; window.left = 0; -+ window.bottom -= window.top; window.top = 0; -+ -+ /* As we're assuming control over the cursor, we need to know when to -+ * relinquish control of it back to the operating system. This is when -+ * the cursor reaches the edge of the window. */ -+ at_edge = (current_x == window.left) || -+ (current_x == (window.right - 1)) || -+ (current_y == window.top) || -+ (current_y == (window.bottom - 1)); -+ -+ if ( at_edge ) { -+ ClipCursor(NULL); -+ } else { -+ ClipCursor(&trap); -+ } -+ } else { -+ /* When in relative mode, warp the OS's idea of where the cursor is to -+ * the center of the screen. This isn't really necessary as DirectInput -+ * reads from the hardware itself, but in case things go wrong, the -+ * cursor will be left in a sensible place. */ -+ POINT center; -+ center.x = (SDL_VideoSurface->w/2); -+ center.y = (SDL_VideoSurface->h/2); -+ ClientToScreen(SDL_Window, ¢er); -+ SetCursorPos(center.x, center.y); -+ } -+ } else { -+ /* No window or mouse focus, control is lost */ -+ mouse_lost = 1; -+ ClipCursor(NULL); -+ } -+} -+ - static void handle_mouse(const int numevents, DIDEVICEOBJECTDATA *ptrbuf) - { - int i; -@@ -298,14 +373,8 @@ - return; - } - -- /* If we are in windowed mode, Windows is taking care of the mouse */ -- if ( (SDL_PublicSurface->flags & SDL_OPENGL) || -- !(SDL_PublicSurface->flags & SDL_FULLSCREEN) ) { -- return; -- } -- - /* If the mouse was lost, regain some sense of mouse state */ -- if ( mouse_lost ) { -+ if ( mouse_lost && (SDL_GetAppState() & SDL_APPMOUSEFOCUS) ) { - POINT mouse_pos; - Uint8 old_state; - Uint8 new_state; -@@ -313,14 +382,17 @@ - /* Set ourselves up with the current cursor position */ - GetCursorPos(&mouse_pos); - ScreenToClient(SDL_Window, &mouse_pos); -- posted = SDL_PrivateMouseMotion(0, 0, -- (Sint16)mouse_pos.x, (Sint16)mouse_pos.y); -+ post_mouse_motion( 0, (Sint16)mouse_pos.x, (Sint16)mouse_pos.y); - - /* Check for mouse button changes */ - old_state = SDL_GetMouseState(NULL, NULL); - new_state = 0; - { /* Get the new DirectInput button state for the mouse */ -+#if DIRECTINPUT_VERSION >= 0x700 -+ DIMOUSESTATE2 distate; -+#else - DIMOUSESTATE distate; -+#endif - HRESULT result; - - result=IDirectInputDevice2_GetDeviceState(SDL_DIdev[1], -@@ -341,14 +413,13 @@ - for ( i=0; i<8; ++i ) { - if ( (old_state&0x01) != (new_state&0x01) ) { - button = (Uint8)(i+1); -- /* Button #2 on two button mice is button 3 -- (the middle button is button 2) -- */ -- if ( button == 2 ) { -- button = 3; -- } else -- if ( button == 3 ) { -- button = 2; -+ /* Map DI button numbers to SDL */ -+ switch ( button ) { -+ case 2: button = SDL_BUTTON_RIGHT; break; -+ case 3: button = SDL_BUTTON_MIDDLE; break; -+ case 4: button = SDL_BUTTON_X1; break; -+ case 5: button = SDL_BUTTON_X2; break; -+ default: break; - } - if ( new_state & 0x01 ) { - /* Grab mouse so we get mouse-up */ -@@ -387,8 +458,7 @@ - case DIMOFS_X: - if ( timestamp != ptrbuf[i].dwTimeStamp ) { - if ( xrel || yrel ) { -- posted = SDL_PrivateMouseMotion( -- 0, 1, xrel, yrel); -+ post_mouse_motion(1, xrel, yrel); - xrel = 0; - yrel = 0; - } -@@ -399,8 +469,7 @@ - case DIMOFS_Y: - if ( timestamp != ptrbuf[i].dwTimeStamp ) { - if ( xrel || yrel ) { -- posted = SDL_PrivateMouseMotion( -- 0, 1, xrel, yrel); -+ post_mouse_motion(1, xrel, yrel); - xrel = 0; - yrel = 0; - } -@@ -410,8 +479,7 @@ - break; - case DIMOFS_Z: - if ( xrel || yrel ) { -- posted = SDL_PrivateMouseMotion( -- 0, 1, xrel, yrel); -+ post_mouse_motion(1, xrel, yrel); - xrel = 0; - yrel = 0; - } -@@ -429,22 +497,26 @@ - case DIMOFS_BUTTON1: - case DIMOFS_BUTTON2: - case DIMOFS_BUTTON3: -+#if DIRECTINPUT_VERSION >= 0x700 -+ case DIMOFS_BUTTON4: -+ case DIMOFS_BUTTON5: -+ case DIMOFS_BUTTON6: -+ case DIMOFS_BUTTON7: -+#endif - if ( xrel || yrel ) { -- posted = SDL_PrivateMouseMotion( -- 0, 1, xrel, yrel); -+ post_mouse_motion(1, xrel, yrel); - xrel = 0; - yrel = 0; - } - timestamp = 0; - button = (Uint8)(ptrbuf[i].dwOfs-DIMOFS_BUTTON0)+1; -- /* Button #2 on two button mice is button 3 -- (the middle button is button 2) -- */ -- if ( button == 2 ) { -- button = 3; -- } else -- if ( button == 3 ) { -- button = 2; -+ /* Map DI button numbers to SDL */ -+ switch ( button ) { -+ case 2: button = SDL_BUTTON_RIGHT; break; -+ case 3: button = SDL_BUTTON_MIDDLE; break; -+ case 4: button = SDL_BUTTON_X1; break; -+ case 5: button = SDL_BUTTON_X2; break; -+ default: break; - } - if ( ptrbuf[i].dwData & 0x80 ) { - /* Grab mouse so we get mouse-up */ -@@ -471,7 +543,7 @@ - } - } - if ( xrel || yrel ) { -- posted = SDL_PrivateMouseMotion( 0, 1, xrel, yrel); -+ post_mouse_motion(1, xrel, yrel); - } - } - -@@ -516,10 +588,7 @@ - - /* The keyboard is handled via DirectInput */ - case WM_SYSKEYUP: -- case WM_SYSKEYDOWN: { -- /* Pass syskey to DefWindwoProc (ALT-F4, etc.) */ -- } -- break; -+ case WM_SYSKEYDOWN: - case WM_KEYUP: - case WM_KEYDOWN: { - /* Ignore windows keyboard messages */; -@@ -840,7 +909,7 @@ - keysym->unicode = vkey; - #else - GetKeyboardState(keystate); -- if (SDL_ToUnicode(vkey, scancode, keystate, wchars, sizeof(wchars)/sizeof(wchars[0]), 0) == 1) -+ if (SDL_ToUnicode(vkey, scancode, keystate, wchars, sizeof(wchars)/sizeof(wchars[0]), 0) > 0) - { - keysym->unicode = wchars[0]; - } -Index: src/video/windx5/directx.h -=================================================================== ---- src/video/windx5/directx.h (revision 4067) -+++ src/video/windx5/directx.h (working copy) -@@ -72,7 +72,7 @@ - /* We need these defines to mark what version of DirectX API we use */ - #define DIRECTDRAW_VERSION 0x0700 - #define DIRECTSOUND_VERSION 0x0500 --#define DIRECTINPUT_VERSION 0x0500 -+#define DIRECTINPUT_VERSION 0x0700 - - #ifdef __GNUC__ - #define NONAMELESSUNION -@@ -81,4 +81,20 @@ - #include - #include - -+#if DIRECTINPUT_VERSION >= 0x0700 && !defined(DIMOFS_BUTTON4) -+typedef struct _DIMOUSESTATE2 { -+ LONG lX; -+ LONG lY; -+ LONG lZ; -+ BYTE rgbButtons[8]; -+} DIMOUSESTATE2, *LPDIMOUSESTATE2; -+ -+#define DIMOFS_BUTTON4 (FIELD_OFFSET(DIMOUSESTATE2, rgbButtons) + 4) -+#define DIMOFS_BUTTON5 (FIELD_OFFSET(DIMOUSESTATE2, rgbButtons) + 5) -+#define DIMOFS_BUTTON6 (FIELD_OFFSET(DIMOUSESTATE2, rgbButtons) + 6) -+#define DIMOFS_BUTTON7 (FIELD_OFFSET(DIMOUSESTATE2, rgbButtons) + 7) -+ -+extern const DIDATAFORMAT c_dfDIMouse2; -+#endif -+ - #endif /* _directx_h */ -Index: configure.in -=================================================================== ---- configure.in (revision 4067) -+++ configure.in (working copy) -@@ -2442,7 +2442,7 @@ - # Set up the system libraries we need - EXTRA_LDFLAGS="$EXTRA_LDFLAGS -luser32 -lgdi32 -lwinmm" - if test x$have_directx = xyes; then -- EXTRA_LDFLAGS="$EXTRA_LDFLAGS -ldxguid" -+ EXTRA_LDFLAGS="$EXTRA_LDFLAGS -ldxguid -ldinput8" - fi - # The Win32 platform requires special setup - SOURCES="$SOURCES $srcdir/src/main/win32/*.rc" diff --git a/misc/setup/doit b/misc/setup/doit index 267a07e6..2e082ba7 100755 --- a/misc/setup/doit +++ b/misc/setup/doit @@ -73,7 +73,7 @@ for arch in "${archs[@]}"; do install -m 755 $topdir/build/release-linux-$arch/ioquake3.$arch $dst/ioquake3.$arch install -m 755 $topdir/build/release-linux-$arch/ioq3ded.$arch $dst/ioq3ded.$arch install -m 755 $topdir/build/release-linux-$arch/renderer_opengl1_$arch.so $dst/renderer_opengl1_$arch.so - install -m 755 $topdir/build/release-linux-$arch/renderer_rend2_$arch.so $dst/renderer_rend2_$arch.so + install -m 755 $topdir/build/release-linux-$arch/renderer_opengl2_$arch.so $dst/renderer_opengl2_$arch.so install -m 644 $topdir/build/release-linux-$arch/baseq3/*.so $dst/baseq3 install -m 644 $topdir/build/release-linux-$arch/missionpack/*.so $dst/missionpack for i in cgame qagame ui; do diff --git a/rend2-readme.txt b/opengl2-readme.txt similarity index 94% rename from rend2-readme.txt rename to opengl2-readme.txt index 88f39bed..999fd385 100644 --- a/rend2-readme.txt +++ b/opengl2-readme.txt @@ -1,7 +1,7 @@ -Rend2 +OpenGL2 -Rend2 is an alternate renderer for ioquake3. It aims to implement modern +OpenGL2 is an alternate renderer for ioquake3. It aims to implement modern features and technologies into the id tech 3 engine, but without sacrificing compatibility with existing Quake 3 mods. @@ -23,25 +23,6 @@ compatibility with existing Quake 3 mods. - Screen-space ambient occlusion. -------------------------------------------------------------------------------- - COMPILATION -------------------------------------------------------------------------------- - -For *nix/MinGW: - -1. Download an appropriate version of the ioq3 source code. For version 32 of - Rend2, r2328 should do, though the latest may work as well. For - details on how to do this, see http://ioquake3.org/get-it/source-codes/ . - -2. Copy the patch file (for v32, vbos-glsl-31a.diff) into the directory you put - the ioq3 source code. There should be a README in that directory. - -3. Run 'patch -p0 - - State how this imagemap will be used by Rend2: + - State how this imagemap will be used by OpenGL2: diffuseMap - Standard, same as no stage entry normalMap - Image will be used as a normal map normalParallaxMap - Image will be used as a normal map with @@ -487,8 +478,8 @@ and is the equivalent for 'exactVertex'. This adds a new keyword to sky materials, q3gl2_sun. The syntax is: - q3gl2_sun - + q3gl2_sun + Note the first six parameters are the same as in q3map_sun or q3map_sunExt, and the last two indicate scaling factors for the map brightness and an ambient @@ -496,8 +487,9 @@ light of the same color as the sun. There are currently two ways to use this in your own (and other people's) maps. - 1. Create your map as normal and add a 'q3gl2_sun' line after your - 'q3map_sun' line in your sky material, like so: + 1. Create your map as normal, set r_sunlightMode to 1, and add a + 'q3gl2_sun' line after your 'q3map_sun' line in your sky material, like + so: textures/skies/bluesky { @@ -508,7 +500,7 @@ There are currently two ways to use this in your own (and other people's) maps. surfaceparm nolightmap surfaceparm sky q3map_sunExt 240 238 200 100 195 35 3 16 - q3gl2_sun 240 238 200 50 195 35 3 0.5 0.2 + q3gl2_sun 240 238 200 50 195 35 3 1.0 0.2 q3map_skylight 50 16 q3map_lightimage $whiteimage @@ -520,7 +512,8 @@ There are currently two ways to use this in your own (and other people's) maps. can be used with existing maps without recompilation. The downside is artifacts like doubled shadows and uneven shadow edges. - 2. Use 'q3gl2_sun' instead of 'q3map_sun' or 'q3map_sunExt', like so: + 2. Set r_sunlightMode to 2 and use 'q3gl2_sun' instead of 'q3map_sun' or + 'q3map_sunExt', like so: textures/skies/bluesky { diff --git a/travis-ci-build.sh b/travis-ci-build.sh new file mode 100755 index 00000000..d5119431 --- /dev/null +++ b/travis-ci-build.sh @@ -0,0 +1,30 @@ +#!/bin/sh + +failed=0; + +# check if testing mingw +if [ "$CC" = "i686-w64-mingw32-gcc" ]; then + export PLATFORM=mingw32 + export ARCH=x86 + export CC= + haveExternalLibs=0 +else + haveExternalLibs=1 +fi + +# Default Build +(make clean release) || failed=1; + +# Test additional options +if [ $haveExternalLibs -eq 1 ]; then + (make clean release USE_CODEC_VORBIS=1 USE_FREETYPE=1) || failed=1; +fi + +if [ $failed -eq 1 ]; then + echo "Build failure."; +else + echo "All builds successful."; +fi + +exit $failed; +